A Typical Playback
Suppose that a client wants to playback an interval of an existing tune, and that the voice stream is currently idle.
The client calls
VoiceStream.AddPiece[handle: myVoiceStream, intervalSpec: [tuneID: 29, start: 800, length: 16000, keyIndex: 1], direction: play];
Note that the encryption key for this tune must have been previously registered and an associated keyIndex assigned (see ThParty.RegisterKey). Note also that since a chirp contains 8000 voice samples the specified interval in this example overlaps three chirps.
AddPiece allocates a VoiceStream.PieceObject and adds it to the end of the piece queue (in this case it's the only thing on the queue since the voice stream was initially idle). It thens notifies the server.
The server wakes up, finds the server and client queues empty, and starts to work on the new piece. It calls the notify procedure to indicate that the piece has been $started.
The server discovers that the specified interval starts in the middle of the tune's first chirp and that the whole tail of this chirp is needed. The server reads the chirp from the Jukebox into the first buffer on the idle queue. It then uses the chirp's run data to find where the 800th sample starts in the chirp's storage block. This information is recorded in the buffer and the buffer is moved to the client queue. The piece.intervalSpec is updated to be [tuneID: 29, start: 8000, length: 8800, keyIndex: 1].
The server then loops around and discovers that the interval left to be processed starts on a chirp boundary and contains the complete chirp. It reads the chirp from the Jukebox into the first buffer on the idle queue and then moves the buffer to the client queue. The piece.intervalSpec is updated to be [tuneID: 29, start: 16000, length: 800, keyIndex: 1].
The server then loops around once again. This time it discovers that only the first part of a chirp is desired. Nevertheless, it reads the whole chirp from the Jukebox into the first buffer on the idle queue and gives the buffer to the client queue. The piece.intervalSpec is updated to be [tuneID: 29, start: 16800, length: 0, keyIndex: 1].
The next time around, the server notices that the piece has been completely buffered and waits.
Meanwhile, the SendProc's call to VoiceStream.Get succeeds in finding a buffer on the client queue. The non-silent data in the buffer is copied into packets and sent on the network. When the buffer is used up, it is passed back to the server by placing it on the server queue. This procedure is identical for all three buffers.
When the server finds buffers on the server queue, it simply moves them to the idle queue.
When all of the buffers have been replaced on the idle queue, that is the server and client queues are empty, the server concludes that the piece has been completely processed. It thens calls the notify procedure to indicate that the piece has been $finished and removes the piece from the piece queue.
A Typical Recording
Suppose that a client wants to record a new tune, and that the voice stream is currently idle.
The client calls
VoiceStream.AddPiece[handle: myVoiceStream, intervalSpec: [tuneID: 54, start: 0, length: VoiceStream.wholeTune], direction: record];
Note that the tune must exist and must be closed before calling AddPiece (however the size of the existing tune is unimportant). A new tune can be created by calling Jukebox.CreateTune.
AddPiece allocates a VoiceStream.PieceObject and adds it to the end of the piece queue (in this case it's the only thing on the queue since the voice stream was initially idle). It thens notifies the server.
The server wakes up, finds the server and client queues empty, and starts to work on the new piece. It calls the notify procedure to indicate that the piece has been $started.
The server discovers that the specified interval starts on a chirp boundary and uses the whole chirp. It simply passes an empty buffer, which indicates that it should be filled with a chirp's worth of data destined for the Jukebox, from the idle queue to the client queue. The piece.intervalSpec is updated to be [tuneID: 54, start: 8000, length: VoiceStream.wholeTune].
The server continues this until it runs out of idle buffers or a buffer is returned to the server queue.
Meanwhile, the ReceiveProc's call to VoiceStream.Put succeeds in finding a buffer on the client queue that is destined for the Jukebox. Data from packets received over the network is copied into the buffer. When the buffer is full, it is passed back to the server by placing it on the server queue. The ReceiveProc then attempts to fill another buffer.
When the server discovers a buffer on the server queue that is destined for the Jukebox, it writes the buffer's data block into the appropriate chirp in the Jukebox. It then moves the buffer to the idle queue. Since the piece has not been completely processed, this buffer is immediately set up to receive the next chirp and passed back to the client queue.
This procedure of passing buffers back and forth between the server and the receiving process continues indefinitely until the client calls
VoiceStream.FlushPieces[handle: myVoiceStream];
FlushPieces simply marks the piece as being flushed. It also calls the notify procedure to indicate that the piece has been $flushed.
When the server notices that the piece is being flushed, it sets piece.intervalSpec.length to zero so that the piece looks like it has been completed. When the ReceiveProc notices the flush, it immediately gives its buffers back to the server. The server then continues to write out buffers that contain data for the Jukebox (these are buffers that were filled before the call to FlushPieces).
When all of the buffers have been replaced on the idle queue, that is the server and client queues are empty, the server concludes that the piece has been completely processed. It thens calls the notify procedure to indicate that the piece has been $finished and removes the piece from the piece queue.