File: VoiceStream.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Last Edited by: Ousterhout, March 8, 1983 11:34 am
Last Edited by: L. Stewart, December 30, 1983 11:30 am
Last Edited by: Swinehart, June 9, 1986 3:44:21 pm PDT
Ades, February 6, 1986 4:24:23 pm PST
DIRECTORY
IntervalTimer USING [Pulses],
IO USING [STREAM],
Jukebox USING [Handle, RunData, RunDataObject, Tune, WindowOrigin, RunArrayRange],
PrincOps USING [ByteBltBlock],
PupSocket USING [Socket],
Rope USING [ROPE],
VM USING [Interval],
VoiceTemp USING [ IntervalSpec, VoiceDirection ]
;
VoiceStream: DEFINITIONS =
BEGIN
This file contains routines that provide a stream-like facility for moving voice data between the jukebox and the Ethernet.
ErrorCode: TYPE = {Bug, BadPiece, StreamClosed, Timeout, Hungup};
The signals have the following meaning:
Bug: internal error in this module.
BadPiece: the piece referred to a non-existent tune or area within tune.
StreamClosed: operations were attempted on a stream after closing it.
Timeout: the Etherphone stopped responding.
Hungup: the Etherphone hungup.
Error:
ERROR[reason: ErrorCode, rope: Rope.
ROPE, clientData:
REF];
clientData will contain the clientData field from the last-queued piece, if there is one (same as $flushed event.)
ReportError:
PROC[handle: Handle];
Use handle.errorCode, else handle.errorRope. Supply clientData as specified above.
VoiceStreamEvent: TYPE = ATOM; -- For reporting what happened.
The following byte count is used to refer to an entire tune. It's just a
very large integer.
wholeTune: INT;
Open: PROC [jukebox: Jukebox.Handle, proc: NotifyProc ← NIL] RETURNS [handle: Handle];
This sets up a voice stream, which is a connection between the jukebox and the network. The stream is bidirectional. However, this call will not start information flowing. In order for information transfer to occur, two more things must happen: a) a socket to provide or receive the information must be identified with a call to SetSocket; b) one or more areas of the jukebox must be identified with calls to AddPiece. If the pieces run out, then the socket routine will just wait. If proc is specified, then it is invoked when pieces run out (this routine may also be invoked occasionally when pieces haven't really run out: call Empty to find out for sure).
Close: PROC [handle: Handle];
This flushes all the information in the stream, and kills a socket connection if there was one.
SetSocket: PROC [handle: Handle, socket: PupSocket.Socket];
This procedure sets up a background procedure that will pass data between the voice stream and the given socket. If there was already a socket associated with the stream, the old association is broken. If the new socket is NIL, then the stream is left with no socket association. Pieces in the stream are not flushed when the socket association is broken.
AddPiece:
PROC [handle: Handle,
intervalSpec: VoiceTemp.IntervalSpec,
direction: VoiceTemp.VoiceDirection ← play,
clientData: REF
];
This call indicates an area of the jukebox to be read or written, and adds that area to the list pending for the stream. If intervalSpec.firstByte is less than zero, then the piece starts at the end of the tune. direction specifies the direction of information flow. clientData will be supplied as the parameter to the procedure registered by Open.
FlushPieces: PROC [handle: Handle];
This procedure throws away all of the pieces pending for the stream.
IsEmpty: PROC [handle: Handle] RETURNS[BOOLEAN];
Indicates whether or not there are any pieces pending for the stream.
WaitEmpty: PROC [handle: Handle];
This procedure doesn't return until the stream is empty.
Get: PROC [handle: Handle, maxSilentBytes: NAT, block: PrincOps.ByteBltBlock, wait: BOOL ← FALSE] RETURNS[silence: NAT, bytesTransferred: NAT, keyIndex: NAT];
Reads information from a stream into a given area. Not normally invoked from outside this package. Returns value smaller than block size, or [0, 0], when pieces run out or if the current piece is for recording.
Put: PROC [handle: Handle, silentBytes: NAT, block: PrincOps.ByteBltBlock, energy: CARDINAL] RETURNS [bytesTransferred: NAT];
Writes information from a given area into a stream. Not normally invoked from outside the package. Returns value smaller than block size, or zero, when pieces run out or if the current piece is for playback.
Check: PROC [handle: Handle] RETURNS[BOOLEAN];
If there are any errors pending for the given voice stream, they are signalled immediately. If there are no errors and there is data pending for input, then TRUE is returned. Otherwise, FALSE is returned. Not normally used outside this package.
StartServer: PROC [stream: IO.STREAM];
Called to initialize the voice stream server and let us know where to output diagnostic messages. Nothing will happen in voice streams until this routine gets called.
Handle: TYPE = REF VSRecord;
NotifyProc:
TYPE =
PROC [self: Handle, event: VoiceStreamEvent, clientData:
REF
ANY];
Called when a voice stream begins ($started) or ends ($finished) the playback/recording of a piece, or when it is flushed ($aborted) (the clientData will refer to the last piece flushed. Registered by Open.
--------------------------------------------------------
Stuff below this point is only used by the implementation files and should never be used by clients.
--------------------------------------------------------
buffersPerStream: INTEGER = 3;
VSRecord:
TYPE =
RECORD [
This record describes a voice transfer. There are three lists of buffers: the server buffers are those that are waiting to be processed by the server, the client buffers are those waiting to be processed by the client, and the idle buffers are those that aren't in use at all (usually because there are no voice pieces specified for the stream). All of the VSRecords are linked together so that the server process can find them. If errorRope isn't NIL, then an error has occurred for the voice stream, as described by errorRope and errorCode. proc is a procedure to be invoked with clientData as parameter whenever the transfer of voice data for a piece is $started, $finished, or $aborted (due to a call on FlushPieces). connection identifies the characteristic of the remote terminal that is destination/source for data transmission. action is set by the get and put routines whenever data passes into or out of the stream, and it is cleared by the monitor routine.
jukebox: Jukebox.Handle,
firstServerBuffer: REF Buffer←NIL,
firstClientBuffer: REF Buffer←NIL,
firstIdleBuffer: REF Buffer←NIL,
piece: Piece←NIL,
next: REF VSRecord←NIL,
errorRope: Rope.ROPE←NIL,
errorCode: ErrorCode,
proc: NotifyProc,
connection: Connection←NIL,
newPiece: CONDITION,
action: BOOL←FALSE,
pieceInProgress: BOOL←FALSE
];
Connection: TYPE = REF ConnectionObject;
ConnectionObject:
TYPE =
RECORD [
socket: PupSocket.Socket,
packetSize: NAT, -- Packet size when we're sending.
bufferSpace: NAT, -- Milliseconds of buffering in Lark.
probeLaunchTime: IntervalTimer.Pulses, -- time probe was transmitted
probeSequenceNumber: CARDINAL, -- last probe fingerprint
a packet transmitted at localEpoch would arrive at the Lark at larkEpoch
larkEpoch: CARDINAL, -- Lark clock (milliseconds)
localEpoch: IntervalTimer.Pulses,
roundTripMS: CARDINAL, -- milliseconds
initialProbeDone: CONDITION,
initialProbeFinished: BOOL,
drift: INT, -- accumulated clock error
sendNext: IntervalTimer.Pulses,
pollStreamNext: IntervalTimer.Pulses,
sequenceNumber: CARDINAL,
timeToPlay: CARDINAL, -- lark time to play next packet
packetMS: NAT -- Milliseconds in most recent packet
];
Buffer: TYPE = RECORD [
This record keeps track of one chirp and the space used to represent it. block is only valid when the buffer is on the client list, and refers to the portion yet to be filled/emptied by the client. valid and block are set by the server process before adding the buffer to the client list. A FALSE value for valid means that the server shouldn't write out the chirp. toJukebox is TRUE if the buffer is to be filled with information for the jukebox, and FALSE if the buffer is already filled with information coming from the jukebox.
chirp: LONG INTEGER,
chirpSpace: VM.Interval,
window: Jukebox.WindowOrigin,
block: PrincOps.ByteBltBlock,
runData: RunData,
runIndex: Jukebox.RunArrayRange,
bytesAccountedFor: NAT,
next: REF Buffer,
toJukebox: BOOLEAN,
keyIndex: NAT,
valid: BOOLEAN,
playedBytes: CARDINAL
];
RunDataObject: TYPE = Jukebox.RunDataObject;
RunData:
TYPE = Jukebox.RunData;
Piece: TYPE = REF PieceObject;
PieceObject: TYPE = RECORD [
This record describes a continuous chunk of voice information within one tune for purposes of reading or writing via a VoiceStream. Piece information is interpreted entirely by the server process. The flush field means that the piece is supposed to be flushed, but hasn't been flushed yet.
next: Piece←NIL,
intervalSpec: VoiceTemp.IntervalSpec,
clientData: REF,
tune: Jukebox.Tune←NIL,
playback: BOOLEAN,
flush: BOOLEAN←FALSE,
packetsSinceLastNonSilence: INT -- used in both recording and playback: indicates how long since last sound worth playing occured; preset to Jukebox.hangoverPackets by AddPiece
];
Monitor lock for all internal routines:
Lock: MONITORLOCK;
Condition variables used by clients and servers of voicestreams to wait for buffers to fill or empty:
serverCondition: CONDITION;
client: CONDITION;
Condition variable used by the WaitEmpty procedure:
waitCondition: CONDITION;
Condition variable used during Close to ensure that the server is finished touching the voice stream.
closeCondition: CONDITION;
IO stream used to ouput diagnostic messages:
ioStream: IO.STREAM;
Head of list of all open voicestreams:
vSList: Handle;
SetError:
PROC [handle: Handle, rope: Rope.
ROPE,
code: ErrorCode];
Records error information in a voice stream.
FlushBuffer: PROC [handle: Handle];
Flushes leading client buffer to server.
END.
April 5, 1983 2:35 pm, Stewart, add RunData to Buffer record
June 4, 1983 5:39 pm, Stewart, add notified to VSRecord in order to notify only once
L. Stewart, June 20, 1983 4:52 pm, Try using Pulses instead of Microseconds
L. Stewart, December 26, 1983 7:41 pm, Cedar 5
Swinehart, May 9, 1986 6:19:52 pm PDT
Convert to new communications package
changes to: DIRECTORY, SetSocket, ConnectionObject
Swinehart, June 9, 1986 9:27:39 am PDT
Major redefinitions of data structures, esp. Piece. Error includes clientData, as in $flushed.
changes to: DIRECTORY, ErrorCode, Error, ReportError, VoiceStreamEvent, Open, AddPiece, NotifyProc, VSRecord, Piece, PieceObject, SetError