Theos PowerBasic Museum 2017

Archive => Discussion - Legacy Software (PBWIN 9.0+/PBCC 5.0+) => Topic started by: Bud Meyer on July 07, 2009, 04:59:30 AM

Title: Reading and changing the master volume on Vista/7
Post by: Bud Meyer on July 07, 2009, 04:59:30 AM
I'm trying to get/set/mute the master volume on Vista, but I don't know how to do direct interface stuff.

This is the file:
endpointvolume.inc

This is the interface:
IAudioEndpointVolume

With these methods:
SetMasterVolumeLevel
SetMasterVolumeLevelScalar
GetMasterVolumeLevel
GetMasterVolumeLevelScalar
SetMute
GetMute

http://blogs.msdn.com/larryosterman/archive/2007/03/06/how-do-i-change-the-master-volume-in-windows-vista.aspx

I think it's something like...
DIM aev AS IAudioEndpointVolume
aev = NEWCOM $IID_IAudioEndpointVolume
LOCAL vol AS SINGLE
aev.GetMasterVolumeLevelScalar(vol)
? STR$(vol)


But it crashes. :(

Any help please? :)
Title: Re: Reading and changing the master volume on Vista/7
Post by: Patrice Terrier on July 07, 2009, 09:16:37 AM
    LOCAL pIAudioEndpointVolume AS IAudioEndpointVolume

    LET pIAudioEndpointVolume = NEWCOM CLSID $IID_IAudioEndpointVolume
    IF NOT ISNOTHING(pIAudioEndpointVolume) THEN
       LOCAL currentVolume AS SINGLE
       pIAudioEndpointVolume.GetMasterVolumeLevel(currentVolume)
       pIAudioEndpointVolume.SetMasterVolumeLevel(currentVolume, "")
       pIAudioEndpointVolume = NOTHING
    END IF
Title: Re: Reading and changing the master volume on Vista/7
Post by: Bud Meyer on July 07, 2009, 04:10:19 PM
Thanks Patrice, but it doesn't work for me. I'm using Vista x64 if it matters.


#COMPILE EXE
#DIM ALL
#INCLUDE "endpointvolume.inc"

FUNCTION PBMAIN () AS LONG
   LOCAL pIAudioEndpointVolume AS IAudioEndpointVolume

   LET pIAudioEndpointVolume = NEWCOM CLSID $IID_IAudioEndpointVolume
   IF NOT ISNOTHING(pIAudioEndpointVolume) THEN
      LOCAL currentVolume AS SINGLE
      pIAudioEndpointVolume.GetMasterVolumeLevel(currentVolume)
      'pIAudioEndpointVolume.SetMasterVolumeLevel(currentVolume, "")
      pIAudioEndpointVolume = NOTHING
       ? FORMAT$(currentVolume)
   ELSE
       ? "failure."
   END IF
END FUNCTION
Title: Re: Reading and changing the master volume on Vista/7
Post by: Patrice Terrier on July 07, 2009, 05:38:12 PM
I am using it myself, in the MovieBox project on VISTA 64.

...

Title: Re: Reading and changing the master volume on Vista/7
Post by: Bud Meyer on July 07, 2009, 10:16:21 PM
hmm.. strange. Would you compile the exe in my previous post and test it out? If it works, please post the exe so I can figure out if the problem is on my end.
Title: Re: Reading and changing the master volume on Vista/7
Post by: Patrice Terrier on July 09, 2009, 08:24:56 AM
Bud,

Check this:
Endpoint Volume Controls (http://msdn.microsoft.com/en-us/library/dd370839(VS.85).aspx)

...
Title: Re: Reading and changing the master volume on Vista/7
Post by: Bud Meyer on July 09, 2009, 06:09:04 PM
I've read that link but it doesn't help much since I don't know C++ very well. If the simplest of code doesn't work for me, then I assume either my integrated sound is not supported, or my Windows installation has a problem.
Title: Re: Reading and changing the master volume on Vista/7
Post by: Patrice Terrier on July 09, 2009, 06:18:50 PM
Bud,

Anyway it is not a good idea to change the whole audio level on Vista and Windows 7, since now you can setup individualy for each running application.

I remember from the top of my head, that is the reason why i changed to the IBasicAudio interface in MovieBox when i switched to VISTA.

...
Title: Re: Reading and changing the master volume on Vista/7
Post by: Bud Meyer on July 09, 2009, 06:37:26 PM
I specifically want to control the master volume, just like I could on XP. I just wish there was a non-COM way of doing it, since it doesn't work for me.  :-[
Title: Re: Reading and changing the master volume on Vista/7
Post by: Patrice Terrier on July 09, 2009, 06:46:49 PM
The old mixer API of XP, doesn't exist anymore on VISTA, hence the reason why you must go the COM way.

...
Title: Re: Reading and changing the master volume on Vista/7
Post by: Bud Meyer on July 10, 2009, 02:44:01 AM
Yeah, that's mostly true.

I can mute the master volume with this, so that's no problem for me:
keybd_event(%VK_VOLUME_MUTE, 0, 0, 0)

And I use this to get/set the volume:
mixerSetControlDetails(hMixer, mcd, %MIXER_GETCONTROLDETAILSF_VALUE)
mixerSetControlDetails(hMixer, mcd, %MIXER_SETCONTROLDETAILSF_VALUE)
but of course in Vista that only works for my program instead of the main volume.

I tried your MusicBox which is nice, but the included code has IAudioEndpointVolume commented out. Do you have a working program that uses it successfully?
Title: Re: Reading and changing the master volume on Vista/7
Post by: Bud Meyer on July 11, 2009, 03:50:38 AM
OK, I've made progress! :D
This successfully reads the main volume level and returns a value between 0 and 1.
I still need to do more work on setting the volume, and getting/setting mute.
I'm brand new to this COM stuff, so if anyone sees something wrong, please let me know.

#COMPILE EXE
#DIM ALL
#INCLUDE "mmdeviceapi.inc"
#INCLUDE "endpointvolume.inc"

FUNCTION PBMAIN () AS LONG
    LOCAL pIMMDeviceEnumerator  AS IMMDeviceEnumerator
    LOCAL pIMMDevice            AS IMMDevice
    LOCAL pIAudioEndpointVolume AS IAudioEndpointVolume

    LET pIMMDeviceEnumerator  = NEWCOM CLSID $IID_IMMDeviceEnumerator
    LET pIMMDevice            = NEWCOM CLSID $IID_IMMDevice
    LET pIAudioEndpointVolume = NEWCOM CLSID $IID_IAudioEndpointVolume

    LOCAL hr AS LONG
    LOCAL x AS IUNKNOWN
    hr = CoCreateInstance(BYREF $CLSID_MMDeviceEnumerator, x, %CLSCTX_INPROC_SERVER, $IID_IMMDeviceEnumerator, pIMMDeviceEnumerator)
    pIMMDeviceEnumerator.GetDefaultAudioEndpoint(%eRender, %eConsole, pIMMDevice)
    pIMMDevice.Activate(BYREF $IID_IAudioEndpointVolume, %CLSCTX_ALL, BYVAL %NULL, pIAudioEndpointVolume)

    IF NOT ISNOTHING(pIAudioEndpointVolume) THEN
        LOCAL currentVolume AS SINGLE
        pIAudioEndpointVolume.GetMasterVolumeLevelScalar(currentVolume)
        ? FORMAT$(currentVolume)
        'currentVolume = 0.5
        'pIAudioEndpointVolume.SetMasterVolumeLevelScalar(currentVolume)
    ELSE
        ? "failure."
    END IF

    pIMMDeviceEnumerator  = NOTHING
    pIMMDevice            = NOTHING
    pIAudioEndpointVolume = NOTHING
END FUNCTION
                                                                         
Title: Re: Reading and changing the master volume on Vista/7
Post by: José Roca on July 11, 2009, 04:05:42 AM
Remove


    LET pIMMDeviceEnumerator  = NEWCOM CLSID $IID_IMMDeviceEnumerator
    LET pIMMDevice            = NEWCOM CLSID $IID_IMMDevice
    LET pIAudioEndpointVolume = NEWCOM CLSID $IID_IAudioEndpointVolume


and change


    LOCAL hr AS LONG
    LOCAL x AS IUNKNOWN
    hr = CoCreateInstance(BYREF $CLSID_MMDeviceEnumerator, x, %CLSCTX_INPROC_SERVER, $IID_IMMDeviceEnumerator, pIMMDeviceEnumerator)


to


    pIMMDeviceEnumerator  = NEWCOM CLSID $CLSID_MMDeviceEnumerator

Title: Re: Reading and changing the master volume on Vista/7
Post by: José Roca on July 11, 2009, 04:20:28 AM
 
Just to help you a little with your learning of COM:

NEWCOM CLSID does the same that CoCreateInstance and must be used with ClsIDs (class identifiers), not with IIDs (interface identifiers).

Therefore, the following statements are incorrect and will fail:


    LET pIMMDeviceEnumerator  = NEWCOM CLSID $IID_IMMDeviceEnumerator
    LET pIMMDevice            = NEWCOM CLSID $IID_IMMDevice
    LET pIAudioEndpointVolume = NEWCOM CLSID $IID_IAudioEndpointVolume


You can use CoCreateInstance if you prefer it, but NEWCOM CLSID is shorter and easier to use.

When using CoCreateInstance or other API functions that have a parameter declared as IUnknown, IDispatch or another interface name and you want to pass a null reference, you don't need to declare an uninitialized object variable and pass it, but you can pass NOTHING.

Therefore, instead of:


   LOCAL hr AS LONG
   LOCAL x AS IUNKNOWN
   hr = CoCreateInstance(BYREF $CLSID_MMDeviceEnumerator, x, %CLSCTX_INPROC_SERVER, $IID_IMMDeviceEnumerator, pIMMDeviceEnumerator)


you can use:


   LOCAL hr AS LONG
   hr = CoCreateInstance($CLSID_MMDeviceEnumerator, NOTHING, %CLSCTX_INPROC_SERVER, $IID_IMMDeviceEnumerator, pIMMDeviceEnumerator)


Notice also that the BYREFs in


   hr = CoCreateInstance(BYREF $CLSID_MMDeviceEnumerator, x, %CLSCTX_INPROC_SERVER, $IID_IMMDeviceEnumerator, pIMMDeviceEnumerator)
   pIMMDevice.Activate(BYREF $IID_IAudioEndpointVolume, %CLSCTX_ALL, BYVAL %NULL, pIAudioEndpointVolume)


are unneeded.

Title: Re: Reading and changing the master volume on Vista/7
Post by: Bud Meyer on July 11, 2009, 05:41:27 AM
Thanks for the wisdom José. :)

I think I've completed my goal. If anything looks wrong, such as error checking, cleanup, etc, please let me know.

#COMPILE EXE
#DIM ALL
#INCLUDE "mmdeviceapi.inc"
#INCLUDE "endpointvolume.inc"

FUNCTION PBMAIN () AS LONG
    LOCAL pIMMDeviceEnumerator  AS IMMDeviceEnumerator
    LOCAL pIMMDevice            AS IMMDevice
    LOCAL pIAudioEndpointVolume AS IAudioEndpointVolume
    LOCAL vol AS SINGLE
    LOCAL mute AS LONG
   
    pIMMDeviceEnumerator = NEWCOM CLSID $CLSID_MMDeviceEnumerator
    IF NOT ISNOTHING(pIMMDeviceEnumerator) THEN

        pIMMDeviceEnumerator.GetDefaultAudioEndpoint(%eRender, %eConsole, pIMMDevice)
        IF NOT ISNOTHING(pIMMDevice) THEN

            pIMMDevice.Activate($IID_IAudioEndpointVolume, %CLSCTX_ALL, BYVAL %NULL, pIAudioEndpointVolume)
            IF NOT ISNOTHING(pIAudioEndpointVolume) THEN
                vol = 0.75
                pIAudioEndpointVolume.SetMasterVolumeLevelScalar(vol, BYVAL %NULL)
                pIAudioEndpointVolume.GetMasterVolumeLevelScalar(vol)
                ? "Volume level set to: " & FORMAT$(vol * 100) & "%" & $CRLF & "Click OK to toggle mute"
                pIAudioEndpointVolume.GetMute(mute)
                pIAudioEndpointVolume.SetMute(IIF&(mute=0, 1, 0), BYVAL %NULL)
            END IF

        END IF

    END IF

    pIMMDeviceEnumerator  = NOTHING
    pIMMDevice            = NOTHING
    pIAudioEndpointVolume = NOTHING
END FUNCTION
Title: Re: Reading and changing the master volume on Vista/7
Post by: Theo Gottwald on June 24, 2012, 02:59:15 PM
I have expanded this sample code, trying to get the volume of avilable Audio Channel.

I have used:



LOCAL ch AS LONG, vol AS SINGLE

pIAudioEndpointVolume.SetChannelVolumeLevelScalar(ch,vol,BYVAL %NULL)


But it seems not to produce the expected Result.
Has anybody tried this before and knows whats wrong (why the volume doesn't change in the Mixer?)