Changing time within a stream


An interactive application is almost never played in linear order from beginning to end. Instead, the end-users of your application may be interested in a variety of interactions discussed in this section:

Starting and stopping a stream

To start, stop, or pause a stream, use the functions DSStartStream() and DSStopStream(). How you use DSStopStream() depends on whether you expect to resume playing. If you use SOPT_FLUSH as the last argument, all buffers will be flushed. If you use SOPT_NOFLUSH, buffers remain unchanged.

The following example is from NuPlayer.c, which is part of the NuPlayer application.

Example 1: Starting and stopping a stream.

else if ( jp->startBtn )
        {
        /* Pause / Unpause the stream
         */
        if ( ctx->streamCBPtr->streamFlags & STRM_RUNNING )
            {
            /* Note: we don't use the SOPT_FLUSH option when we stop
             * here so that the "A" button acts like a pause/resume
             * key. Using the SOPT_FLUSH option will cause buffered
             * data to be flushed, so that once resumed, any queued
             * audio will vanish. This is not what is usually desired 
             * for pause/resume.
             */
            status = DSStopStream( ctx->messageItem, NULL, ctx->streamCBPtr, 

                            SOPT_NOFLUSH );
            CHECK_DS_RESULT( "DSStopStream", status );
            }
        else
            {
            status = DSStartStream( ctx->messageItem, NULL, 

                    ctx->streamCBPtr, SOPT_NOFLUSH );
            CHECK_DS_RESULT( "DSStartStream", status );
            }

Using Weaver script commands to place markers

To specify the exact points at which a stream may start or stop, it is best to use the writestopchunk or writehaltchunk Weaver script commands.

Note: The Weaver always places markers at the beginning of a block, even if the time you specify actually falls in the middle of a block. This makes using markers advisable in all situations.

The following figure shows a Weaver script that include commands for placing markers.

Graphic cannot be displayed

Figure 3: Weaver script writing control chunks.

The writestopchunk command writes a STOP chunk to the output stream. You specify the time in audio clock ticks.

The writehaltchunk command writes a HALT chunk, which is sent to a specific subscriber. This can be used to halt the streamer thread from delivering chunks to all subscribers until a reply is received from the specified subscriber.

The writemarkertable command ensures the Weaver writes a table of marker positions with both time and position (file offset).

Note: When dealing with software compressed video, note that it's important to place markers at key frames. Examine the stream file to find out where key frames are located.

For more information

The writegotochunk command is discussed in the next section.

Jumping to a new location

To move to a different location in the application (branching), use the function DSGoMarker(). While starting or stopping a stream under certain conditions at certain points can happen under a variety of circumstances, branching is usually triggered by user input.

Placing markers

Before your application can branch, you have to place markers in the stream file to branch to. You have to include writegotochunk commands into the Weaver script; the the markers are then placed in the stream file when the Weaver tool generates it. You specify the stream time at which the branching should happen and the place to which the stream should branch. The command in the figure above, for example, places a marker at stream time 3000 that jumps back to stream time 0.

Using different options to DSGoMarker()

Different options to DSGoMarker() allow you to move in your stream in different ways:

Updating all threads participating in a streaming process

When a positioning operation-for example, with DSGoMarker()-has completed, the time associated with the marker position is transmitted to all other threads by a call to DSClockSync(). This function informs all subscriber threads that a change in the stream's temporal position has occurred and gives them the opportunity to take appropriate actions, such as flushing any "stale" data.

Flushing

Flushing should only occur when a positioning operation completes, not when a marker is simply played through. This distinction is made by storing the last "go marker" destination in the stream control block. The control subscriber calls DSIsMarker() to test whether a time-stamped flush control chunk matches the last branch destination. If so, DSIsMarker() returns TRUE and clears the branch destination logic to prevent further matches; otherwise, it returns FALSE. This permits conditional flushing based on whether or not a marker position is played through or is the destination of a branch. The receipt of the flush control chunk indicates that a positioning operation is complete.