Archived

This topic is now archived and is closed to further replies.

Gyannea

Why does this second call fail?

Recommended Posts

I have a section of code that initializes a direct sound capture object then buffer and then a notify object for that buffer: --------------------------- [All of this works] if(FAILED(pdsRXOb->CreateCaptureBuffer(&dsRXbd, &pdsRXBufOb, NULL))) // Create the capture buffer { return FALSE; } dsRXBufCaps.dwSize = sizeof(DSCBCAPS); // Get the capture buffer capabilities if(FAILED(pdsRXBufOb->GetCaps(&dsRXBufCaps))) { return FALSE; } // Create Notification interface for the capture buffer if(FAILED(pdsRXBufOb->QueryInterface(IID_IDirectSoundNotify, (void **)&pdsRXNotifyOb))) { return(FALSE); } ---------------------------------------------- It works fine. At least it compiles and executes. However, then I initialize a direct sound object, a secondary buffer and then try to place a notify object on that buffer. The notification object fails when executed. ---------------------------------------------- // Create the DirectSound buffer [This works] if(FAILED(pdsTXOb->CreateSoundBuffer(&dsTXbd, &pdsTXSecBufOb, NULL))) { return(FALSE); } // Create Notification interface for the send buffer [FAILS!!] if(FAILED(pdsTXSecBufOb->QueryInterface(IID_IDirectSoundNotify, (void **)&pdsTXNotifyOb))) { return(FALSE); } ----------------------------------------- Any ideas why I can''t create a notify object on the send buffer? Brian Reinhold

Share this post


Link to post
Share on other sites
The error return value is "E_NOINTERFACE" but that seems hard to believe given that the capture buffer works, the computer (1 year old Gateway) and soundcard (Soundblaster Live) are modern.

I tried using the outdated initialization method on the buffer but that gives "already initialized" so that obviously is not a solution.

It''s hard to know where to go from here!

I wanted to put the receive and send activities in a single high priority thread using a WaitForMulipleEvents() function to handle the two actions.

Does it make any sense that the interface would be available for the capture but not the play option? If anything, I would assume the reverse!

Not first creating the capture notify object doesn''t change things either!



Brian Reinhold

Share this post


Link to post
Share on other sites
Dave, it didn''t work. Same error...no interface. How could that be? I thought the primary purpose of having the notify event thing was for streaming playback. I don''t even know where to turn.


Brian Reinhold

Share this post


Link to post
Share on other sites
According to MSDN, the CreateSoundBuffer method returns an IDirectSoundBuffer interface. You have to QueryInterface to get an IDirectSoundBuffer8 interface. Once you have a pointer to IDirectSoundBuffer8, you should be able to get your notify pointer via IID_IDirectSoundNotify8. I''m just guessing since I''m at work and can''t reference my own code, so this may not help.

Share this post


Link to post
Share on other sites
That step of querying the DirectSoundBuffer interface to get the DirectSoundBuffer8 interface I have not done.

I have just created the Direct Sound object,
and from that created a DirectSoundBuffer object.

Wonder what the GUID idnetifier is called?

Brian

Share this post


Link to post
Share on other sites
I still get the same error, even though I can query the directsoundbuffer interface to get the ''8'' version. But I can''t query the ''8'' version to get the notify object.

I used DirectSoundCreate8 on the ''8'' version of the direct sound object. Maybe I should keep it at no ''8''?

This is crazy. I wish I could see an example, but the SDK doesn''t have one for directsound...just directsoundcapture. At least that which I can find!

Brian

Share this post


Link to post
Share on other sites
Dave,

If I add the flag "DSBCAPS_CTRLPOSITIONNOTIFY" in the DSBCAPS structure in my above code when creating the DirectSound object, then the notify interface is able to be created as written above, without all the ''8'' options. Why I need to do this for the DirectSound object and NOT the DirectSoundCapture object is something which I don''t understand.

Whether the notify event action will work, on the other hand, I have not tried. Now at least I will be able to proceed.

It is quite frustrating and it cost me a whole day! Thanks for your help. I DO wish there was more information somewhere on DirectSound and subsets. There is certainly PLENTY on DirectX in the graphics part!

Brian Reinhold

Share this post


Link to post
Share on other sites
Dave,

I saw a few lines from example code of a notification event on the MS website. It created the interface, and then setup the notification events, and then released the object. I guess once the ntofications are set, they stay with the buffer. The only advantage of not releasing the object is if you wanted to change the notification positions using the same buffer. What do you do or think is best?

Brian

Share this post


Link to post
Share on other sites
Glad you got it working. Something about the DSBCAPS was nagging at me, but it didn''t click.

As to the Release question, I set all my notification positions and release the interface. If I need to change the positions later, I create a new interface for the changes. I suspect DirectSound might get upset if the interface was kept around while the buffer was playing, but I don''t have any proof of that.

I agree that DirectSound information is hard to come by and they seldom go beyond the "This is how to play a WAV file" stage. Several of the DirectX game programming books have sections on DirectSound. I think Programming Role Playing Games with DirectX includes information on notifications, but that''s the only one I can think of.

Good luck with the rest of your project!

Share this post


Link to post
Share on other sites
Dave,

I followed that technique. Notify and then release. And I am VERY happy to say yesterday''s frustration paid off, because the wait for event approach solved the problem. I have 84 notify positions separated by less than 10 ms and I am not missing s glitch! No overreads of the data being written anymore. The Windows ''Sleep()'' function and time resolution just wasn''t cutting it and the round off was killing me (I had 1200 baud rates in this case).

The payoff was good!

Brian

Share this post


Link to post
Share on other sites
Dave,

Here''s a good one. I am using the MS Visual C++ development environment on this project. When I run the program within the environment, it works.

However, if I execute the program by itself (outside of the development environment) the Direct Sound object creation fails.

Have any idea on that!!???

Can''t debug it either! Go into the environment, it works!!

Brian

Share this post


Link to post
Share on other sites
Yes I did. The CoInitialize() function works, but the next call which creates the DirectSoundCapture object fails. Its otherwise the first DirectSound function to be called.

Is there some weird thing about accessing Direct X outside of the MSVC environment?

I''m baffled! But I can keep developing at least...some comfort but unsettling.

Brian

Share this post


Link to post
Share on other sites
The only difference is the current directory. When you run from the IDE, the current directory is the project directory. When you run from Explorer, the current directory is the directory where the exe is. If you don''t use fully explicit paths for your sound files, then you would have problems loading them. But it shouldn''t affect your ability to initialize DSound.

Very strange.

Share this post


Link to post
Share on other sites
Dave,

Found something really unique. I don''t understand it all, but the program will work as long as I take it out of the ''debug'' directory created by MSVC. It has something to do with the "debug" build which lets it know that it is in this special directory and therefore looks for something in the MS development environment. I tried making a release version instead and it does work, even in the "debug" directory. (Well, I have a fatal crash due an exception, but that''s another story.) So at least I have one answer. It''s the last thing I ever expected to happen, but MS doesn''t tell you what goes on inside! They leave you to stumble on them by accident.

Now to find out what I am accessing out of bounds in the release mode. It''s tough to do when you can''t debug (or you just get cryptic assmebly code where all function names and variables are replaced by Hex numbers!

Brian

Share this post


Link to post
Share on other sites
Hi,

I''ve written a class in C# to playback audio from streaming audio. The class was written according to the Microsoft Directx SDK guidelines set out for playing streaming audio in the following document:

http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_m/directx/sound/playingsounds/directsound_buffers.asp

Like yourself i''ve been having a problem with creating a notify object. However, my problem is that I get an "System.ArgumentException: Value does not fall within the expected range", which occurs when I pass my SecondaryBuffer to the Notify constructor. As i''m almost 100% sure that both my secondarybuffer and device are created correctly, and i''ve followed the guidelines set-out in the above link, i''m a little perplexed.

A copy of the code follows below, the error occurs in the Constructor (public PlaybackAudio(Control owner))

If anyone can cast light on my problem it would be greatly appreciated,

R. Casson


The following is an exact copy of the code, with the line on which the error occurs commented with "/* ERROR LINE */":

public class PlaybackAudio
{
private BufferPositionNotify[] posNotify = new BufferPositionNotify[nPlayNotifs + 1];
private static int nPlayNotifs = 2;
private AutoResetEvent caughtEvent = null;
private int notifySize = 1024;
private Notify playbackNotify = null;
public Guid playbackDeviceGuid = Guid.Empty;
private Receiver receive;
private int playbackBuffSize = 0;
private int nextWriteOffset;
private bool playing = false;
private Thread playBufferThread;
private byte[] playData = null;
private SecondaryBuffer playbackBuffer = null;

public PlaybackAudio(Control owner)
{
// Set the waveformat retrieved as the waveformat to play back at
WaveFormat outFormat = new WaveFormat();
outFormat.Channels = 1;
outFormat.SamplesPerSecond = 8000;
outFormat.AverageBytesPerSecond = 8000;
outFormat.BitsPerSample = 8;
outFormat.BlockAlign = 1;
outFormat.FormatTag = WaveFormatTag.Pcm;

// Create the device
Device device = new Device(DSoundHelper.DefaultPlaybackDevice);
device.SetCooperativeLevel(owner, CooperativeLevel.Normal);
//Caps deviceCaps = device.Caps;

// Create the buffer description
BufferDescription playbackBuffDesc = new BufferDescription(outFormat);
notifySize -= notifySize % outFormat.BlockAlign;
playbackBuffSize = notifySize * nPlayNotifs;
playbackBuffDesc.BufferBytes = playbackBuffSize;
// Set the format during creation
playbackBuffDesc.Format = outFormat;

// Create the Secondary Buffer
playbackBuffer = new SecondaryBuffer(playbackBuffDesc, device);
playbackBuffer.SetCurrentPosition(0);

// Create the AutoResetEvent. When each offset is reached in the SecondaryBuffer
// the ''BufferPositionNotify.EventNotifyHandle'' will cause an AutoResetEvent to
// notify the waiting thread that an event has occured.
caughtEvent = new AutoResetEvent(false);

// Create the Notify object.
/*ERROR LINE*/ playbackNotify = new Notify(playbackBuffer); /*ERROR LINE*/

// Set the notification positions at which playbackBuffer will be refreshed
for (int y = 0; y < nPlayNotifs; y++)
{
// Set the offset to one byte before the notifySize
posNotify[y].Offset = (notifySize * y) + notifySize - 1;
// Create an AutoResetEvent for each position
posNotify[y].EventNotifyHandle = caughtEvent.Handle;
}

// Tell DirectSound when to notify the app. The notification will come in the form
// of signaled events that are handled in the notify thread.
playbackNotify.SetNotificationPositions(posNotify, nPlayNotifs);

// Start the thread that waits for Notifications
playBufferThread = new Thread(new ThreadStart(WaitThread));
playing = true;
playBufferThread.Start();

nextWriteOffset = 0;
}


private void WaitThread()
{
playbackBuffer.Play(0, BufferPlayFlags.Looping);
while(playing)
{
// Calling WaitOne stops and waits for the next offset to be reached
caughtEvent.WaitOne(Timeout.Infinite, true);
AddPlayData();
}
}

private void AddPlayData()
{
try
{
// Begin asynchronous read of MemoryStream
receive.PlaybackStream.BeginRead(playData, 0, (int)receive.PlaybackStream.Length, null, null);
playbackBuffer.Write(nextWriteOffset, playData, LockFlag.None);

// Save the position of the last written byte
nextWriteOffset += (int)receive.PlaybackStream.Length;
// Circular buffer
nextWriteOffset %= playbackBuffSize;
}
catch(Exception){}
}

}

Share this post


Link to post
Share on other sites
I''m trying to follow what you have done but I am afraid I don''t know C# (have no idea how it relates to C/C++).

I had to use a ->QueryInterface() method on the directsound object to even begin. Is that where you are having the error?

I create the DirectSound Capture buffer and then use the query interface with the GUID identifier for the Notify interface. After I get that, then I set up the notification events. Unfortunately, at least in C/C++ you can''t just call the Create object function as you can for the Direct Sound object and Direct Sound Buffer object.

Here''s my code (directsoundcapture buffer has been created:

// Create Notification interface for the capture buffer
if(FAILED(pdsRXBufOb->QueryInterface(IID_IDirectSoundNotify, (void **)&pdsNotifyOb)))
{
return(DSC_QUERY_NOTIFY_FAIL);
}
// Now the notify object is given by ''pdsNotifyOb->...''

// Create the notification points and Event object
dsNotify = new DSBPOSITIONNOTIFY [temp]; // Allocate memory for the structure array
offset = bytestoread - 1;
hevent = CreateEvent(NULL, FALSE, FALSE, NULL); // Create event object unsignaled
for(index = 0; index < temp; index++) // Load the notify structure with positions
{
(dsNotify + index)->dwOffset = offset;
(dsNotify + index)->hEventNotify = hevent;
offset = offset + bytestoread;
}
if(FAILED(pdsNotifyOb->SetNotificationPositions(temp, dsNotify)))
{
delete dsNotify;
dsNotify = NULL;
CloseHandle(hevent);
hevent = NULL;
SAFE_RELEASE(pdsNotifyOb);// Release buffer notify object
return((DSC_NOTIFY_POS_FAIL));
}
delete dsNotify;
dsNotify = NULL;
SAFE_RELEASE(pdsNotifyOb);// Release buffer notify object

========================== End of junk

Maybe you can help me out with the C# stuff and tell me where you are.

Brian

Share this post


Link to post
Share on other sites
Cheers for the quick reply!

It seems most of our code is very similar, or at least most that you added in this post, that is. Although I don''t know c/c++ myself, it does appear that from the section where you "Create the notification points and Event object" onwards, there are great similarities between the code. Which bit is it that you would like me to explain? Would you like me to run through all of it? I''d be happy to as I''m desperate for help as this run-time exception has really got me flummoxed. In your code I do not understand what QueryInterface is used for, as I said i''m unfamiliar with c++. I copied the code over to the VS debugger but I got a lot of ambiguity in the topics which were shown when I used the dynamic help to try and resolve why it was used.

Thanks for replying, and for showing interest, it''s people like you who are great help in these forums.

r.casson

Share this post


Link to post
Share on other sites
Just thought i''d post to say that I figured out this particular problem. In both managed and unmanaged code there are certain properties that have to be set to ensure the buffer is created without an argument exception being thrown. In the sdk documentation for unmanaged C++, these guidelines are clearly set out. As an example, on the url that follows, there is a description of each property and how it would be applied when writing in unmanaged c++:

http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/htm/dsbufferdesc.asp


Unfortunately, the documentation for c# is very lacking. Therefore, i''d advise any one who has similar problems when writing managed code to refer to both the managed and unmanaged sdk documentation and try and apply the code examples and class descriptions to your own code, as it appears the managed documentation is quite incomplete.

Cheers,

richard casson

Share this post


Link to post
Share on other sites
There are two interesting items here. One has nothing to do with the problem, and the other does. First I got an email notification that someone had responded to my post yesterday, yet when I went to this site, the latest post was my post. Now I got another notification and I see two posts (both by you). Weird.

Now for the DirectSound Stuff. I found something similar trying to set notifications for DirectSoundBuffers (but not DirectSoundCaptureBuffers). In order to use notifications at all, you had to specify a special flag regarding that aspect in the buffer properties structure.

What I also learned is that using notifications on the DirectSoundBuffer may limit your ability to do hardware accelleration. Hopefully, newer soundcards/drivers don''t have that restriction. On the other hand, capture buffers don''t have that restriction.

So I have removed notifications on the playback and only have them on the capture, and I base everything on the capture timing. That works for my application since I am controlling a radio and ALWAYS receive (capture). When I send (playback) I use the same sample rate, write the same size hunk to the playback buffer as I read from the capture buffer, and do everything in one high priority thread.

You would think everything would be hunky dory, right? No. For some reason, at some (most) sample rates, the capture takes longer than the send. The only way that can be as far as I know is that there are two clocks. So when I am sending, every once and a while I have to load the playback buffer twice for one read of the capture buffer.

Brian

PS Glad you solved your problem. It''s hard to find much info on DirectSound and even harder to find it on DirectSoundCapture and virtually impossible to find anything about use of both.

Share this post


Link to post
Share on other sites