WASAPI Process Notifications (System Wide)

Share your advanced PureBasic knowledge/code with the community.
AndyMK
Enthusiast
Enthusiast
Posts: 582
Joined: Wed Jul 12, 2006 4:38 pm
Location: UK

Re: WASAPI Process Notifications (System Wide)

Post by AndyMK »

Like this?

Code: Select all

Procedure ProcessEnumeratedSessions(pSessionManager.IAudioSessionManager2)
  Protected pSessionList.IAudioSessionEnumerator
  Protected pSessionControl.IAudioSessionControl
  Protected pSessionControl2.IAudioSessionControl2
  Protected sessionEvents.IAudioSessionEvents
  Protected index, cbSessionCount, pSessionId, sessionId, PID, NewState, fname.s
  
  If pSessionManager\GetSessionEnumerator(@pSessionList) <> #S_OK
    Debug "Get Session List Error"
  EndIf
  
  If pSessionList\GetCount(@cbSessionCount) <> #S_OK
    Debug "Get Session Count Error"
  EndIf
  
  For index = 0 To cbSessionCount - 1
    pSessionList\GetSession(index, @pSessionControl)
    If pSessionControl\QueryInterface(?IID_IAudioSessionControl2, @pSessionControl2) = #S_OK
      pSessionControl2\GetProcessId(@PID)
      pSessionControl2\GetState(@NewState)
      pSessionControl2\GetSessionIdentifier(@pSessionId)
      
      If pSessionId
        fname = GetFilePart(StringField(StringField(PeekS(pSessionId, -1, #PB_Unicode), 2, "|"), 1, "%"))
      EndIf
      
      If PID > 0 And fname <> "PureBasic_Compilation0.exe"
        PostEvent(#EventBeginProcessing, #PB_Ignore, #PB_Ignore, #PB_Ignore, 500)
        
        Debug "New audio session created. PID: " + Str(PID)
        ;Debug GetFilePart(StringField(StringField(PeekS(pSessionId, -1, #PB_Unicode), 2, "|"), 1, "%"))
        Select NewState
          Case #AudioSessionStateInactive
            Debug Str(PID) + " Inactive"
          Case #AudioSessionStateActive
            Debug Str(PID) + " Active"
          Case #AudioSessionStateExpired
            Debug Str(PID) + " Expired"
        EndSelect
        
        sessionEvents = CreateMyAudioSessionEvents(PID, pSessionId, pSessionControl2)
        pSessionControl2\RegisterAudioSessionNotification(sessionEvents)
        pSessionControl2\Release()
      EndIf
      pSessionControl\Release()
    EndIf
  Next
  pSessionList\Release()
EndProcedure
User avatar
Zapman
Enthusiast
Enthusiast
Posts: 205
Joined: Tue Jan 07, 2020 7:27 pm

Re: WASAPI Process Notifications (System Wide)

Post by Zapman »

AndyMK wrote: Thu Feb 27, 2025 7:23 am

Code: Select all

Protected pSessionControl.IAudioSessionControl2
pSessionControl is already an IAudioSessionControl2 interface. Is this the wrong way to do it?
What is an interface? It is nothing other than a list of procedure addresses with the declaration of parameters that must be provided to these procedures.
When you declare

Code: Select all

Protected pSessionControl.IAudioSessionControl2
you reserve a memory area in which you will be able to store the list of addresses of the interface procedures. This address list is what we call the 'VTable'.

If you build everything yourself, you must start by defining the procedures (or methods) that will be called by the interface, then store the addresses of these procedures in a 'VTable', that is to say that you stack the addresses of the procedures on top of each other by storing them in the location that you first defined during your interface declaration.
This is exactly what you did to create the interface for 'MyAudioSessionEventsObj':
  • You first created all the procedures/methods of the interface (Procedures MySessionEvents_OnSessionDisconnected() and following),
  • then you reserved space for the interface with
    AllocateStructure(MyAudioSessionEventsObj)
  • then you stacked the method addresses in a vTable that you saved in MyAudioSessionEventsObj.
For IAudioSessionControl2, you don't need to do everything yourself, because you use functions that do it for you.
  • The procedures/methods of this interface are already defined by Windows.
  • You reserve memory space for the interface with

    Code: Select all

    Protected pSessionControl.IAudioSessionControl2
  • You store the vTable there by calling pSessionList\GetSession(index, @pSessionControl)
The problem is that with this, you have not completely filled the vTable of IAudioSessionControl2, because this interface is an extension of IAudioSessionControl.
You have only completed the first part of the vTable. To get the rest, you need to call pSessionControl\QueryInterface(?IID_IAudioSessionControl2, @pSessionControl).

What you did in the second post that you posted this morning seems good to me: you broke down what needed to be done by creating two objects:
  • pSessionControl initialized by pSessionList\GetSession(index, @pSessionControl)
  • pSessionControl2 initialized by pSessionControl\QueryInterface(?IID_IAudioSessionControl2, @pSessionControl2)
I couldn't test your new procedure because you added other things and I don't have the definition of #EventBeginProcessing, but I think it will work like this. :)

What I suggested you to do:

Code: Select all

    pSessionList\GetSession(index, @pSessionControl)
    pSessionControl\QueryInterface(?IID_IAudioSessionControl2, @pSessionControl)
is also good.
In that case, pSessionControl is an IAudioSessionControl2 object which is an addition of IAudioSessionControl plus the extension room. The first line fills the first part of the object, and the second line completes the job. It is perhaps less clear, but it is clean and efficient.
AndyMK
Enthusiast
Enthusiast
Posts: 582
Joined: Wed Jul 12, 2006 4:38 pm
Location: UK

Re: WASAPI Process Notifications (System Wide)

Post by AndyMK »

Thanks for the insight. I am still learning com. I get most of it but subtle things like you mentioned are very helpful. I was under the impression that asigning pSessionControl to IAudioSessionControl2 directly was ok because IAudioSessionControl2 inherits from IAudioSessionControl and the IAudioSessionControl methods are visible and appear to work. It is strange that it works here.

Ignore this, i am going to use it to send the results to the main thread.

Code: Select all

PostEvent(#EventBeginProcessing, #PB_Ignore, #PB_Ignore, #PB_Ignore, 500)
User avatar
Zapman
Enthusiast
Enthusiast
Posts: 205
Joined: Tue Jan 07, 2020 7:27 pm

Re: WASAPI Process Notifications (System Wide)

Post by Zapman »

AndyMK wrote: Thu Feb 27, 2025 11:02 am It is strange that it works here.
For sure! It's very strange that you were able to run your program without having correctly initialized the pSessionControl object.
Because you are using your set of functions within a bigger ensemble (your program), I suppose that (by luck) the memory area attributed to pSessionControl was allready set with the good values in your case, even if you did not do what is necessary for that.

But you should get problems one day or another, if the things are not done as they should be. So, I strongly recommend to initialize the object correctly.
AndyMK
Enthusiast
Enthusiast
Posts: 582
Joined: Wed Jul 12, 2006 4:38 pm
Location: UK

Re: WASAPI Process Notifications (System Wide)

Post by AndyMK »

Updated
Post Reply