Question

I'm using DirectSound's DirectSoundBuffer to play voice data that I am streaming over a network. The nature of voice/speech is that it doesn't necessarily constantly stream (it starts and stops) and it also can come in varying packet sizes (which makes it difficult to predict where the buffer should stop). I keep a StoppingPoint variable that keeps track of where in my buffer I have written up to (it also takes into account the circular nature of this buffer). If the StoppingPoint is reached, I would like to stop playing my buffer. Also, I StoppingPoint would also signify the point at which I'd also like to start writing from.

My buffer
|==============================|--------------------------|
      ^                        ^             ^
      |                        |             |
  Voice Data            Stopping point   Old/Garbage
                                            data

Also, I can't use notifications, because in order to use a notification the buffer must be stopped. But in my case, it is very likely for more data to come in as the buffer is playing, thus pushing back my 'StoppingPoint` value.

What I currently have now is a function that is called every frame. This function, amongst other things, is checking where the Play cursor is. If the Play cursor is passed the StoppingPoint location, it stops the buffer, and moves the Play cursor back to the StoppingPoint location. This seems to work ok so far, but as you'd expect, the Play cursor quite often overshoots the StoppingPoint. This means a little bit of old/garbage data is played every time the end of the streamed data is reached.

I'm just curious as to if there is a way to stop playing a DirectSoundBuffer at a specific offset? What I would like is to write data to the buffer, then play, then have it stop precisely at the location described by my StoppingPoint variable without overshooting it.

Note: I haven't included any code because this is more of a high-level solution that I need. My implementation is incredibly straight forward, typical and for the most part it DOES work. I just need a nudge in the right direction to remove the overshooting of my StoppingPoint. Perhaps there is a function I can use? Or some other algorithm that is commonly used to achieve this?

Was it helpful?

Solution

I've come up with a solution, but I'm still interested in any feedback or alternative solutions. I'm not sure if the way I've done it is ok, but it seems to be producing the desired results. Although, my solution feels a little too convoluted...

1) Whenever I write data, I now write at either the Buffer's Write Cursor or the StoppingPoint - whichever is later. This is to avoid stopping, then later writing in that "untouchable" space between the Play Cursor and Write Cursor, whose data has already been dedicated to playback.

DWORD writeCursorOffset = 0;
buffer->GetCurrentPosition(NULL, &writeCursorOffset); 

//if write cursor has passed stopping point, then we need to write from there. 
//So update m_StoppingPoint to reflect the new writing position.
m_StoppingPoint = m_StoppingPoint > writeCursorOffset ? m_StoppingPoint : writeCursorOffset;

2) I added some silence after every single write, but I left StoppingPoint to point at the end of the actual voice data. Eg.

|==============================|*********|---------------------|
     ^                         ^      ^              ^
     |                         |      |              |
Voice data                  Stopping  Silence    Old/Garbage
                             Point                  Data

3) If the Buffer's Play Cursor passed the StoppingPoint, I would then stop playing the buffer. Even if the Play Cursor overshoots here, all it will play is silence.

//error checking removed for demonstration purposes
buffer->Stop();

4) Immediately after stopping I would update StoppingPoint to be equal to the end of the silence. This would ensure that when more speech data comes in, the buffer will not play any silence first.

//don't forget that modulo at the end - circular buffer!
m_StoppingPoint = (m_StoppingPoint + SILENCE_BUFFER_SIZE) % BufferSize;

|==============================|*********|-------------------|
                                         ^ 
                                         | 
                                    Move Stopping
                                      Point here

Again, if I've done anything glaringly evil here, please let me know!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top