DIRECTORY BluejayTool, Containers USING [Container], Graphics USING [black, Color, white], IO USING [int, PutFR], Jukebox USING [bytesPerChirp], Process USING [Detach, MsecToTicks, Pause], PupDefs USING [PupSocket], Rules USING [Create, Set], VFonts USING [FontHeight, StringWidth], ViewerTools USING [MakeNewTextViewer, SetContents], VoiceStream; VoiceStreamMonitor: MONITOR LOCKS Lock IMPORTS IO, Process, Rules, VFonts, ViewerTools, VoiceStream EXPORTS BluejayTool, VoiceStream SHARES VoiceStream = BEGIN OPEN VoiceStream; masterSwitch: BOOL _ FALSE; EnableViewerUpdates: PUBLIC PROC [enable: BOOL _ TRUE] = { IF masterSwitch = enable THEN RETURN; masterSwitch _ enable; IF masterSwitch THEN Process.Detach[FORK monitor[]]; }; StartMonitor: PUBLIC PROCEDURE[container: Containers.Container, y: INT] RETURNS [newY: INT] = BEGIN lineHeight: INT _ VFonts.FontHeight[] + 3; playbackWidth: INT _ VFonts.StringWidth["Recording:"] + 20; pieceWidth: INT _ VFonts.StringWidth["XXXX[00000000:00000000]"]; [] _ Rules.Create[info: [parent: container, wx: 0, wy: y, ww: 1024, wh: 1, border: FALSE]]; y _ y+2; FOR i:INTEGER IN [0..nMonEntries) DO MonEntries[i].handle _ NIL; MonEntries[i].new _ TRUE; MonEntries[i].playbackViewer _ ViewerTools.MakeNewTextViewer[ info: [parent: container, wx: 0, wy: y, wh: lineHeight, ww: playbackWidth, data: " ", border: FALSE, scrollable: FALSE]]; MonEntries[i].pieceViewer _ ViewerTools.MakeNewTextViewer[ info: [parent: container, wx: playbackWidth+10, wy: y, wh: lineHeight, ww: pieceWidth, data: " ", border: FALSE, scrollable: FALSE]]; MonEntries[i].actionRule _ Rules.Create[ info: [parent: container, wx: playbackWidth+ pieceWidth+15, wy: y, wh: lineHeight, ww: lineHeight, border: FALSE], color: Graphics.white]; [] _ Rules.Create[info: [parent: container, wx: 0, wy: y+lineHeight+1, ww: 1024, wh: 1, border: FALSE]]; y _ y + lineHeight + 3; ENDLOOP; EnableViewerUpdates[TRUE]; RETURN [y]; END; monGet: ENTRY PROCEDURE[i: INTEGER] RETURNS[handle: Handle, socket: PupDefs.PupSocket, tuneId: INT, firstByte: INT, nBytes: INT, playback: BOOLEAN, action: BOOLEAN] = BEGIN piece: REF Piece; buffer: REF Buffer; adjust: INT; handle _ MonEntries[i].handle; IF handle = NIL THEN RETURN; IF handle.connection # NIL THEN socket _ handle.connection.socket; action _ handle.action; handle.action _ FALSE; piece _ handle.piece; IF piece = NIL THEN BEGIN tuneId _ -1; firstByte _ -1; nBytes _ -1; playback _ FALSE; END ELSE BEGIN tuneId _ piece.tuneId; firstByte _ piece.firstByte; nBytes _ piece.nBytes; buffer _ handle.firstClientBuffer; adjust _ 0; WHILE buffer # NIL DO adjust _ adjust + buffer.block.stopIndexPlusOne - buffer.block.startIndex; buffer _ buffer.next; ENDLOOP; firstByte _ firstByte - adjust; nBytes _ nBytes + adjust; playback _ piece.playback; END; RETURN; END; monitor: PROCEDURE = BEGIN handle: Handle; socket: PupDefs.PupSocket; tuneId, firstByte, nBytes: INT; playback, action, new: BOOLEAN; white: REF Graphics.Color _ NEW[Graphics.Color _ Graphics.white]; black: REF Graphics.Color _ NEW[Graphics.Color _ Graphics.black]; WHILE TRUE DO Process.Pause[Process.MsecToTicks[250]]; IF NOT masterSwitch THEN EXIT; FOR i:INTEGER IN [0..nMonEntries) DO [handle, socket, tuneId, firstByte, nBytes, playback, action] _ monGet[i]; new _ MonEntries[i].new; IF (handle = NIL) THEN BEGIN IF new THEN LOOP ELSE BEGIN MonEntries[i].new _ TRUE; ViewerTools.SetContents[MonEntries[i].playbackViewer, " "]; ViewerTools.SetContents[MonEntries[i].pieceViewer, " "]; Rules.Set[MonEntries[i].actionRule, white]; LOOP; END; END; IF (tuneId # MonEntries[i].tuneId) OR (firstByte # MonEntries[i].firstByte) OR (nBytes # MonEntries[i].nBytes) OR new THEN BEGIN IF tuneId >= 0 THEN BEGIN ViewerTools.SetContents[MonEntries[i].pieceViewer, IO.PutFR["%d[%d:%d]", IO.int[tuneId], IO.int[firstByte/Jukebox.bytesPerChirp], IO.int[(firstByte+nBytes-1)/Jukebox.bytesPerChirp]]]; END ELSE BEGIN ViewerTools.SetContents[MonEntries[i].pieceViewer, " "]; ViewerTools.SetContents[MonEntries[i].playbackViewer, " "]; END; MonEntries[i].tuneId _ tuneId; MonEntries[i].firstByte _ firstByte; MonEntries[i].nBytes _ nBytes; END; IF (playback # MonEntries[i].playback) OR new THEN BEGIN IF tuneId >= 0 THEN BEGIN IF playback THEN ViewerTools.SetContents[MonEntries[i].playbackViewer, "Playback:"] ELSE ViewerTools.SetContents[MonEntries[i].playbackViewer, "Recording:"]; END; MonEntries[i].playback _ playback; END; IF MonEntries[i].black THEN BEGIN Rules.Set[MonEntries[i].actionRule, white]; MonEntries[i].black _ FALSE; END ELSE IF action THEN BEGIN Rules.Set[MonEntries[i].actionRule, black]; MonEntries[i].black _ TRUE; END; MonEntries[i].new _ FALSE; ENDLOOP; ENDLOOP; END; END. ÒFile: VoiceStreamMonitor.mesa This file contains part of the implementation of voicestreams. The routines here provide a simple monitoring facility, displaying the state of existing streams in viewers. The monitor is a process that runs in background and periodically updates information on the display. Last Edited by: Ousterhout, March 8, 1983 11:39 amcompile Last Edited by: L. Stewart, December 27, 1983 1:50 pm Set up the monitor structure, then invoke the background monitor process. This is just a utility procedure to read things out of a stream record safely for the monitor procedure. To compute the actual number of bytes left in the piece, don't include the number of bytes waiting for the client. Ditto for the first byte. This procedure wakes up four times a second to update things in the display. Read out information from the handle. This also synchronizes with the other processes touching the handle. If this entry is idle, do nothing. If the entry has just become idle, then blank it out. Update entries that have changed. Update everything if the entry is a new one. Last Edited by: L. Stewart, March 25, 1983 3:55 pm, VoiceStream changes Last Edited by: L. Stewart, December 27, 1983 1:50 pm, Cedar 5 Êè˜Jšœ™JšœC™CJšœB™BJšœD™DJšœ>™>Jšœ™J˜Jšœ9™9Jšœ5™5J˜šÏk ˜ J˜ Jšœ œ ˜Jšœ œ˜%Jšœœ˜Jšœœ˜Jšœœ˜+Jšœœ ˜Jšœœ˜Jšœœ˜'Jšœ œ"˜3J˜ J˜—Jšœœœ˜&Jšœœ2˜™>J˜—…—ˆB