Click to See Complete Forum and Search --> : Full duplex agonies?


Gyannea
January 27th, 2004, 06:02 AM
This note is for those of you struggling (like myself) with full duplex DirectX operations on the sound system. By "full duplex" I mean using DirectSoundCapture and DirectSound to receive (record) an incoming data stream and send (playback) the same or modified or even created data stream at exactly the same rate.

Whats the trick?

One would think that if you set the format (samplerate, bit depth, number of channels, etc.) of the capture buffer identical to that of the secondary playback buffer, everything would be okay. But it ain't!

I have a capture buffer which I read at a certain rate. I fill it with notifications so I read exactly that number of bytes by which the notifications are separated. Now I look at the difference between my readindex and the "safe" read index using the '->GetCurrentPosition()' method and compare the difference. That difference SHOULD be constant unless you do too much processing and you don't finish your work before the next notification is sent. If you do your work fast enough, it will be constant. In my case, it is! Good.

Now, what about the playback? Lets take that SAME data I just read and send it out the playback buffer! What a wonderful idea. Glad I thought of it. Now, since the playback buffer is formatted IDENTICAL to the capture buffer, wouldn't you think that everything would be nice and okay? It's not.

I do exactly the same test for the "safe" write position with my write pointer on the playback buffer. However, unlike the capture buffer, the "safe" pointer creeps upon my write pointer, eventually catching up and causing trash. For other formats (different sample rates), the reverse may be true, though I haven't experimented enough yet. It also appeared that if I picked a standard samplerate like 44100 Hz, the capture and send buffers kept in phase.

What is going on? Not sure. Here is my guess. The format of the secondary playback buffer and that of primary buffer (recall there is no primary capture buffer) are not the same! The primary buffer is set at a few preferred formats and your secondary buffer is converted from your format to the primary buffer format. If you are JUST playing back stuff, there is no problem. BUT if you are full duplexing, big problem!

THis guess comes from looking at the full duplex SDK example. There they create a primary buffer JUST for the purpose of setting its format. They never write to it. They write to a secondary buffer.

That means setting the cooperative level to that for a primary buffer. I find NO place where they reset the cooperative level to DSSCL_EXCLUSIVE for the secondary buffer. Okay, I try the same thing! I set the format of the primary buffer to that of the capture buffer, but I can't create the secondary buffer. It just won't get created, and the error message is NONE of those given. The secondary buffer object pointer returned is NULL, however, which means the buffer was not created...I just have no reason as to why it wasn't created.

So I am getting there. I will add the line of code resetting the cooperation level and see what happens.

What pisses me off is NOWHERE is this explained in the full duplex code given by Microsoft SDK. They just do it. No explanation for why they create the primary buffer. No explanation for why one needs to do a special set of actions to have "full duplex".

The problem is that there must still be more "special" things I have to do in order to accomplish my goals. Since my "full duplex" needs are not identical to those of the MS example, I can't just "copy" it. However, I do need the playback and capture rates to be IDENTICAL! None of this creeping crap.

A long post, I know. For those Direct-X sound people that made it this far, what do you know? Any insights would be GREATLY appreciated.

A frustrated Brian.

Gyannea
January 27th, 2004, 09:13 AM
Update:

Fixed my bug so know I have been able to create the secondary buffer. (I didn't spell DSBUFFERDESC correctly.)

Here are some quick results:

I set the format of the primary buffer to that of the capture buffer and check that the primary buffer is actually set by "getting" the format from this buffer.

I set the format of the playback secondary buffer to that of the capture buffer which (SHOULD) be that of the primary buffer.

Now after every 'x' bytes are received in the capture buffer the 'WaitForSingleObject()' function is signalled and I do the following:

Look at the distance between the capture buffer safe read index and my read index (and read 'x' bytes) AND

Look at the distance between the playback buffer safe write index and my own write index (and write 'x' bytes).

The distance in the capture buffer stays roughly constant as it should...it is set by the notification events. It fluctuates as the time between the reaching the notification and the thread being signalled is up to Window's whims. And yes, if I did too much work the next event may signal before I am finished with this handling and THAT would mess things up...but I don't.

However, the distance for the playback buffer is not constant. Again, the safe write pointer creeps toward my own write index and when it reaches it, the data is trashed.

So setting the format of the primary buffer did not help.

There is a catch. If I choose certain sample rates, 44100 Hz is one case, then the playback buffer "seems" to stay in phase with the capture buffer. I say "seem" because the creep maybe slow enough that I didn't wait long enough to see it happen.

The funny thing is, I get the same result with this sample rate even if I don't bother with creating the primary buffer and setting it's format.

Why did I even choose this sample rate? Because it was in the list of possible sample rates in the MS fullduplex filter example included in their SDK. They also had 8000, 11025, and 22050 (with all combinations of mono, stereo, and 8 or 16 bit depths).

Conclusion:

(1) I still don't understand what is going on,
(2) These results maybe soundcard dependent,
(3) I don't know why MS does what they do in their "full duplex filter".
(4) I feel like a mushroom. Kept in the dark and fed, well, you know.

Brian