DirectSound + OGG + streaming = trouble

Started by
11 comments, last by ReType 20 years ago
Hi! I try to get working streaming sounds from ogg/vorbis with DirectSound. Can someone explain how to do it to works and what the way to develop this? Well... the idea is to have a small buffer and update it when is played, but how to know whent buffer is played and need to be updated? There are any callback or something like this or i must check every frame if buffer is done? Thanks in advance!
Advertisement
I'm more familiar with openAL, but the process should be similar between the two API's. The process should go something like this:

have 2 buffers (double buffered) for music

decompress the ogg into the first buffer
loop:
use the DMA to feed the buffer to the soundcard (done through directsound?)
while the sound is playing, decompress the ogg into the other buffer
use a callback for when the first buffer is empty to swap buffers
wash, rinse, repeat


I think that directsound may have this process encapsulated in a function already. Look through the SDK documentation at the directsound functions and see if it does.


Cheers,




----------------------------------
Halfway down the trail to hell...

[edited by - scourage on January 6, 2004 7:03:21 AM]

[size="3"]Halfway down the trail to Hell...
ok! thanks for reply!
-Create a 4 second buffer
-Load 4 seconds of sound
-When the first 2 seconds are done playing replace them with the next 2 seconds from the file
-When the last 2 seconds are done replace them with the next 2 seconds from the file. Buffer will loop back to beginning

Ogg has a convinient function to decompress a certain number of bytes
quote:Original post by Scourage

have 2 buffers (double buffered) for music

decompress the ogg into the first buffer
loop:
use the DMA to feed the buffer to the soundcard (done through directsound?)
while the sound is playing, decompress the ogg into the other buffer
use a callback for when the first buffer is empty to swap buffers
wash, rinse, repeat


i wrote a similar system of my own, 2 buffers, both filled, when one is near the end, start the other and stop the current one, then load it with the next ogg chunk

however, i do get some skipping at the time of the flip, any suggestions on how i can fix it?


Cartman''s definition of sexual harrasement:
"When you are trying to have intercourse with a lady friend, and some other guy comes up and tickles your balls from behind"

(watch South Park, it rocks)
Cartman's definition of sexual harrasement:"When you are trying to have intercourse with a lady friend, and some other guy comes up and tickles your balls from behind"(watch South Park, it rocks)
Can''t you use Notifications? Make a notification event halfway -1 and at the last byte in the buffer. The notifications then wakeup a WaitOnSingleEvent() function in a thread where you load the data and return and so on and so on.

Very convenient.

Is this approach perhaps illegal with ogg/vorbis? (I have no idea what those things are!

Brian
Brian Reinhold
that is how mine works. using dsound event notifiers, i notified at the end, got skipping and pushed the notifier about 1kb before the end, the skip was minimized, but still exists.
Cartman's definition of sexual harrasement:"When you are trying to have intercourse with a lady friend, and some other guy comes up and tickles your balls from behind"(watch South Park, it rocks)
ceasar4,
I don''t have that problem but I use more than one notification event and watch my timing. (In fact I use several notifications.) But in addition you also have to be VERY careful and make sure you initialize the position of the cursor in the buffer such that when you get your notification that your write position is far enough ahead that it does not conflict with the sending of any data. Even with events, the time it takes for your thread to get that event and load the next data buffer is not gauranteed! The good ''ol days of DOS interrupts are gone.

That was an important issue for my application since I had to try to minimize latency; I wanted my send and capture data to be as close to the actual sending and receiving of the audio signal as possible, which meant getting as close to the hardware read (playback) and write (capture) positions as I could get away with.

As I recall what I did was divide my buffer into N sections of ''x'' bytes. Before starting ''->Play()'' I zeroed the buffer and then I loaded my first hunk of data starting about 15 ms from the beginning of the buffer. My write pointer is then shifted about 15ms ahead of the hardware readpointer. I set the current read position to zero and call ->Play(). When the notification is received, I load the x bytes of data, but the load is started at my write pointer which is shifted by 15ms with respect to the notification points. I read somewhere that that time should be safe for all DirectSound systems. It seems to work on those few systems I have tried. Since this signal is a tone-encoded synchronous digital signal, I can''t have any glitches or the timing will be screwed up at the receiver!

I think the current latency limit is to be at least 15 ms ahead of the current read cursor (for playback). If your writing of the data (the Lock() junk) interferes with the reading by the hardware you will get an instance of crap. That also means there is no way to fill the entire buffer every notification (unless the hardware read is exactly the same speed as your hardware write and timed just right); you have to have at least 2 notifications.

Hope this long tedious story is of help in your case. If not, oh well, you got to read about my trials and tribulations.

Brian
Brian Reinhold
sounds to me that you are using a single buffer to do all that, and all that extra monitoring does have a toll on the CPU. but your idea to slightly rewind the ogg file by a couple milliseconds, is great and i will try to incorporate it into my ogg class


Cartman''s definition of sexual harrasement:
"When you are trying to have intercourse with a lady friend, and some other guy comes up and tickles your balls from behind"

(watch South Park, it rocks)
Cartman's definition of sexual harrasement:"When you are trying to have intercourse with a lady friend, and some other guy comes up and tickles your balls from behind"(watch South Park, it rocks)
here is my DirectSound's streaming class thread function:
bool Looped = false;int Decoded = 0;BYTE * BufferPtr = NULL;DWORD LockSize = 0;DWORD PlayCursor = 0;while(m_Playing){	Looped = false;	m_Buffer->GetCurrentPosition(&PlayCursor, NULL);	if(PlayCursor < m_DecodeCursor) // buffer reached the end, and the play cursor started over.	{		if(m_BufferSizeBytes - 1 > m_DecodeCursor) // chances of ending exactly on the last byte are slim...		{ // fill the end of the buffer with sound			m_Buffer->Lock(m_DecodeCursor, m_BufferSizeBytes - m_DecodeCursor, (void **)&BufferPtr, &LockSize, NULL, NULL, 0);			Decoded = m_Stream->Decode(BufferPtr, LockSize, &Looped);			m_Buffer->Unlock(BufferPtr, Decoded, NULL, NULL);		}		m_DecodeCursor = 0;	}	if(PlayCursor > m_DecodeCursor)	{ // there is room behind the play cursor to decode into		m_Buffer->Lock(m_DecodeCursor, PlayCursor - m_DecodeCursor, (void **)&BufferPtr, &LockSize, NULL, NULL, 0);		Decoded = m_Stream->Decode(BufferPtr, LockSize, &Looped);		m_Buffer->Unlock(BufferPtr, Decoded, NULL, NULL);		m_DecodeCursor += Decoded;	}	if(m_Loop == false && Looped)		return FinishedDecoding();}   


m_Stream is an abstraction of an audio stream, simplest form would be:

class IAudioStream{public:   virtual int Decode(BYTE * Buffer, int BufferSize) = 0;};class COggStream : public IAudioStream{public:   int Decode(BYTE * Buffer, int BufferSize)   {      // call ov_read until buffer is full   }};   

it has other stuff like seeking but that doesn't matter.

my decode function also has a pointer to a bool argument that is set to true if the stream reached the end and starting decoding at the beginning.

edit: messed up my code tags.

[edited by - billybob on April 4, 2004 7:55:40 AM]

[edited by - billybob on April 4, 2004 7:57:14 AM]

This topic is closed to new replies.

Advertisement