Page 1 of 2

[RESOLVED] PDK Sound Service Instance -> Play() Function

Posted: Wed Dec 12, 2018 3:24 pm
by flyboy7798
I'm getting valid HRESULT saying that the SoundServiceInstance Play() function executed normally but no sound. I checked and set the volume and cockpit attenuation and nothing. I even called IsPlaying() and it said the sound was playing?

Any ideas as to what to try next?

Re: PDK Sound Service Instance -> Play() Function

Posted: Wed Dec 12, 2018 3:30 pm
by Brady Butler
Hello,

Is it related to what was reported here? https://www.prepar3d.com/forum/viewtopi ... 2&t=131937

Regards,
Brady

Re: PDK Sound Service Instance -> Play() Function

Posted: Wed Dec 12, 2018 5:03 pm
by flyboy7798
I don't think so, my setup is different, everything is set up for my headset. P3D is set to use the Default device.

Re: PDK Sound Service Instance -> Play() Function

Posted: Thu Dec 13, 2018 12:38 pm
by Rob McCarthy
Are you doing any position sets on the sound? Is it potentially too far away to hear?

Regards,
Rob McCarthy

Re: PDK Sound Service Instance -> Play() Function

Posted: Thu Dec 13, 2018 2:30 pm
by flyboy7798
No, I'm only declaring the pointers in the .h file as private:

Code: Select all

 
    P3D::IPdk* pIPdk = nullptr;
    CComPtr<P3D::ISoundServiceV440> pPdkSoundService;
    CComPtr<P3D::ISoundInstanceV440> pPdkGearWarningSoundInstance;
    LPCWSTR pszSoundFileName = L"..\\SimObjects\\Airplanes\\Aircraft\\Panel\\AircraftSound\\sound.wav";

The only functions I'm calling are the following (in order) all in the .cpp/constructor at this point:

Code: Select all

    query_pdk(P3D::IID_IPdkV01, (void **)&pIPdk);

    pPdkSoundService->CreateSoundInstance(pszSoundFileName, P3D::SOUND_GROUP::SOUND_GROUP_COCKPIT, P3D::VIEW_POINT::VIEW_POINT_INTERIOR, TRUE, FALSE, FALSE, (void **)&pPdkGearWarningSoundInstance);
Then to test functionality calls:

Code: Select all

    pPdkGearWarningSoundInstance->GetVolume();
    pPdkGearWarningSoundInstance->GetCockpitAttenuation();

    pPdkGearWarningSoundInstance->SetVolume(500.0);
    pPdkGearWarningSoundInstance->SetCockpitAttenuation(1.0);

    pPdkGearWarningSoundInstance->GetVolume();
    pPdkGearWarningSoundInstance->GetCockpitAttenuation();
After that, I call the Play() function:

Code: Select all

    pPdkGearWarningSoundInstance->Play();

Then I check if the sound is playing and looping:

Code: Select all

    pPdkGearWarningSoundInstance->IsLooping();
    pPdkGearWarningSoundInstance->IsPlaying();
I hooked up my logger and between it and the debugger, I verified all the HRESULTs are valid and OK. In fact, I get results for the above that show the sound is playing/looping.

Re: PDK Sound Service Instance -> Play() Function

Posted: Thu Dec 13, 2018 4:04 pm
by flyboy7798
Apologies, this line had a typo,

pPdkGearWarningSoundInstance->SetVolume(500.0);

...it should be:

pPdkGearWarningSoundInstance->SetVolume(9500.0);

and I verified that the sound plays.

Thank you guys for your help in getting this far.

Re: PDK Sound Service Instance -> Play() Function

Posted: Sat Dec 15, 2018 4:15 pm
by flyboy7798
I noticed in the PDK documentation that QueryInterface is supposed to be called on the newly created SoundInstance object. Or at least that is what I inferred. The line below is the call to create the sound instance (All error and exception handling removed for simplicity):

Code: Select all

pPdkSoundService->CreateSoundInstance(pszSoundFileName, P3D::SOUND_GROUP::SOUND_GROUP_COCKPIT, P3D::VIEW_POINT::VIEW_POINT_INTERIOR, TRUE, FALSE, FALSE, (void **)&pPdkGearWarningSoundInstance);
Then I call the QueryInterface that generates the exception,

Code: Select all

pPdkSoundService->QueryInterface(P3D::IID_ISoundInstanceV440, (void**)&pPdkGearWarningSoundInstance);
This is the text of the dialog,

Debug Assertion Failed!
Program: <Path on my machine>\my.dll
File: <Path on my machine>\atlcomcli.h
Line: 199
Expression: p==0

I'm obviously missing something, I can get the sound to play in the constructor without calling QueryInterface, but when I try to play from another function besides the constructor, the call to play returns garbage in the HRESULT. I understood that may be a reference count problem that could be alleviated by doing an AddRef, then I noticed that QueryInterface does an AddRef, and since the doc's said I should do it (but not for the stated reason in the PDK docs), I wanted to try it to see if I could get the calls to play and stop playing in class functions (not the constructor). Any ideas how to solve this?

Re: PDK Sound Service Instance -> Play() Function

Posted: Sun Dec 16, 2018 11:18 am
by BenBaron
Hi,

I haven't fiddeled around with the SoundService, yet, but the QueryInterface does something different from my understanding and doesn't have something to do with what you're trying to achieve. It is used to query for a different version of an existing interface. So you could directly query the pPdkGearWarningSoundInstance for another version of the IID_ISoundInstance, if available (but there is no different one as of now, as it was only introduced in 4.4). But you cannot query the pPdkSoundService for a SoundInstance, so an exception is expected.

As far as my understanding of what is written in the SDK goes, you should be able to do the pPdkSoundService->CreateSoundInstance call and then work directly on the returned pPdkGearWarningSoundInstance with Play(), Stop() etc.

Greets, Benny

Re: PDK Sound Service Instance -> Play() Function

Posted: Sun Dec 16, 2018 12:33 pm
by flyboy7798
Thanks Benny,

Then the only other question I have is why once the CComPtr which is a class variable (private) is initialized in the constructor becomes useless (the value it returns in the HRESULT looks like a hexidecimal value) when I call the Play() in a class function. I can call play in the constructor and it works. My guess (around 2000 was when I wrote my last COM project) is that I need to do an AddRef but it won't compile. I had earlier or in another thread asked about a canonical or idomatic order of calls to setup the CComPtr for use in a class as a member variable. I've gone over every use of a CComPtr in the PDK samples...I even broke out Don Box's book Essential COM (published a long time ago) and looked through it again. So any help to solve this would be greatly appreciated.

Very Respectfully,

Jim

Re: PDK Sound Service Instance -> Play() Function

Posted: Sun Dec 16, 2018 8:46 pm
by BenBaron
Hi Jim,

I "might" be fiddeling around with the SoundService and with its instances over the next week for a project of ours, so everything I discover or every problem I'm gonna stumble over, I'm gonna relay here.

But I'd say that you shouldn't need to AddRef manually on the CComPtr in order for it to work, as I'd expect the RefCount to become 2 on the SoundInstance, which should work just fine. One reference that is kept by P3Ds SoundService on creation of the SoundInstance and one reference that is kept by the CComPtr in your code.

Of course, I am just guessing here and I might experience something different, next week :).

But maybe someone else is able to shed a light on your issue, beforehand.

All the best,

Benny

Re: PDK Sound Service Instance -> Play() Function

Posted: Sun Dec 16, 2018 11:13 pm
by flyboy7798
Benny,

Sounds like a plan to me! And thank you for helping.

I had some time to dig a little deeper on this today, I ran down the error when I check if IsPlaying() is true or not, the HRESULT comes back as 0x887800aa. That error code is, I'm pretty sure for the LM sound.dll which I assume is using DirectMusic? I deduce this since the only code I could find for an HRESULT is the one for FACILITY_DIRECTMUSIC, Error 0x887800AA - DSERR_UNINITIALIZED. "This object has not been initialized" is how the documentation reads. Here's the sequence of PDK calls contained in a single class function, PlayGearWarningSound():

Code: Select all

query_pdk(P3D::IID_IPdkV01, (void **)&pIPdk);
pIPdk->QueryService(P3D::SID_SoundService, P3D::IID_ISoundServiceV440, (void**)&pPdkSoundService);
pPdkSoundService->CreateSoundInstance(pszSoundFileName, P3D::SOUND_GROUP::SOUND_GROUP_COCKPIT, P3D::VIEW_POINT::VIEW_POINT_INTERIOR, TRUE, FALSE, FALSE, (void **)&pPdkGearWarningSoundInstance);
pPdkGearWarningSoundInstance->SetVolume(9500.0);
pPdkGearWarningSoundInstance->IsPlaying();
I never make it to the call Play() on pPdkGearWarningSoundInstance. That last line doesn't return the S_OK HRESULT, it returns 0x887800aa. So the mystery is how did pPdkGearWarningSoundInstance become uninitialized when all that is between the function calls to that point are reading the HRESULT from each return and logging the result???

V/R
Jim

Re: PDK Sound Service Instance -> Play() Function

Posted: Mon Dec 17, 2018 7:09 pm
by BenBaron
Jim,

I started implementing the SoundService and I am also seeing the HRESULT 0x887800aa on the first call to IsPlaying(). Nevertheless, I can call Play() on the SoundInstance which also becomes audible and all subsequent calls to IsPlaying() return either S_OK or S_FALSE, as expected. So not much of an issue, I guess.

Now, I am trying to get the sound to play as Environment in 3D and there I am stuck, right now.

All the best,

Benny

Re: PDK Sound Service Instance -> Play() Function

Posted: Mon Dec 17, 2018 8:01 pm
by Clifton Crane
Hello,

The CreateSoundInstance function will give back a SoundInstance with a ref-count of one. One can then manually call Release() or it can be stored within a CComPtr for automatic release. You should not need to add a reference. Calling CreateSoundInstance essentially hands over ownership to your plugin.

The idea behind the subsequent QueryInterface on the SoundInstance is so that your plugin can verify that version you expected was actually returned. For right now, there is only the ISoundInstanceV440 interface, but that could potentially change with subsequent releases just as other PDK services/interfaces.

I can confirm that IsPlaying() will return S_OK or S_FALSE only after the sound has been played once using the Play() function. I would recommend explicitly checking for S_OK, S_FALSE, and using the FAILED() macro to determine if you should Play() your sound.

As far as playing your sound as Environment in 3D, be sure that you have correctly set the position of the sound as it will default to 0,0,0.

Hope this helps!

Re: PDK Sound Service Instance -> Play() Function

Posted: Mon Dec 17, 2018 8:12 pm
by flyboy7798
Benny, thanks for your reply. Thanks, Clifton for the information. Both your responses make sense as to why I'm getting the results in the debugger. I do have a followup question, I declare the both CComPtrs for the sound service and the sound instance as private. I initialize both smart pointers, in the constructor of the class, and set the sound volume on the SoundInstance. After the class is constructed I have a function that checks in a loop if a certain set of conditions is met and then calls a function which has the actual Play() call or another function that has the Stop() call. Are there any problems with the reference count doing this?

Re: PDK Sound Service Instance -> Play() Function

Posted: Mon Dec 17, 2018 8:27 pm
by BenBaron
Clifton Crane wrote: Mon Dec 17, 2018 8:01 pm As far as playing your sound as Environment in 3D, be sure that you have correctly set the position of the sound as it will default to 0,0,0.
Thanks Clifton...I noticed I did a stupid mistake there and used SetOrientation instead of SetPosition on the SoundInstance.
Now, it all works like a charm.

All the best, Benny