Audio Session Events

An application that manages shared-mode audio streams can register to receive notifications when session events occur. As explained previously, each stream belongs to an audio session. A session event is initiated by a change in the status of an audio session.

A client application can register to receive notifications of the following types of session events:

  • The master volume level or muting state of the session submix has changed.
  • The volume level of one or more channels of the session submix has changed.
  • The session has been disconnected.
  • The activity state of the session has changed to active, inactive, or expired.
  • The session has been assigned a new grouping parameter.
  • A user-interface property of the session (icon or display name) has changed.

The client receives notifications of these events through the methods in its implementation of the IAudioSessionEvents interface. Unlike the other interfaces in WASAPI, which are implemented by the WASAPI system module, the client implements IAudioSessionEvents. The methods in this interface receive callbacks from the WASAPI system module when session events occur.

To begin receiving notifications, the client calls the IAudioSessionControl::RegisterAudioSessionNotification method to register its IAudioSessionEvents interface. When the client no longer requires notifications, it calls the IAudioSessionControl::UnregisterAudioSessionNotification method to delete the registration.

The following code example shows a possible implementation of the IAudioSessionEvents interface:

//-----------------------------------------------------------
// Client implementation of IAudioSessionEvents interface.
// WASAPI calls these methods to notify the application when
// a parameter or property of the audio session changes.
//-----------------------------------------------------------
class CAudioSessionEvents : public IAudioSessionEvents
{
    LONG _cRef;

public:
    CAudioSessionEvents() :
        _cRef(1)
    {
    }

    ~CAudioSessionEvents()
    {
    }

    // IUnknown methods -- AddRef, Release, and QueryInterface

    ULONG STDMETHODCALLTYPE AddRef()
    {
        return InterlockedIncrement(&_cRef);
    }

    ULONG STDMETHODCALLTYPE Release()
    {
        ULONG ulRef = InterlockedDecrement(&_cRef);
        if (0 == ulRef)
        {
            delete this;
        }
        return ulRef;
    }

    HRESULT STDMETHODCALLTYPE QueryInterface(
                                REFIID  riid,
                                VOID  **ppvInterface)
    {
        if (IID_IUnknown == riid)
        {
            AddRef();
            *ppvInterface = (IUnknown*)this;
        }
        else if (__uuidof(IAudioSessionEvents) == riid)
        {
            AddRef();
            *ppvInterface = (IAudioSessionEvents*)this;
        }
        else
        {
            *ppvInterface = NULL;
            return E_NOINTERFACE;
        }
        return S_OK;
    }

    // Notification methods for audio session events

    HRESULT STDMETHODCALLTYPE OnDisplayNameChanged(
                                LPCWSTR NewDisplayName,
                                LPCGUID EventContext)
    {
        return S_OK;
    }

    HRESULT STDMETHODCALLTYPE OnIconPathChanged(
                                LPCWSTR NewIconPath,
                                LPCGUID EventContext)
    {
        return S_OK;
    }

    HRESULT STDMETHODCALLTYPE OnSimpleVolumeChanged(
                                float NewVolume,
                                BOOL NewMute,
                                LPCGUID EventContext)
    {
        if (NewMute)
        {
            printf("MUTE\n");
        }
        else
        {
            printf("Volume = %d percent\n",
                   (UINT32)(100*NewVolume + 0.5));
        }

        return S_OK;
    }

    HRESULT STDMETHODCALLTYPE OnChannelVolumeChanged(
                                DWORD ChannelCount,
                                float NewChannelVolumeArray[],
                                DWORD ChangedChannel,
                                LPCGUID EventContext)
    {
        return S_OK;
    }

    HRESULT STDMETHODCALLTYPE OnGroupingParamChanged(
                                LPCGUID NewGroupingParam,
                                LPCGUID EventContext)
    {
        return S_OK;
    }

    HRESULT STDMETHODCALLTYPE OnStateChanged(
                                AudioSessionState NewState)
    {
        char *pszState = "?????";

        switch (NewState)
        {
        case AudioSessionStateActive:
            pszState = "active";
            break;
        case AudioSessionStateInactive:
            pszState = "inactive";
            break;
        }
        printf("New session state = %s\n", pszState);

        return S_OK;
    }

    HRESULT STDMETHODCALLTYPE OnSessionDisconnected(
              AudioSessionDisconnectReason DisconnectReason)
    {
        char *pszReason = "?????";

        switch (DisconnectReason)
        {
        case DisconnectReasonDeviceRemoval:
            pszReason = "device removed";
            break;
        case DisconnectReasonServerShutdown:
            pszReason = "server shut down";
            break;
        case DisconnectReasonFormatChanged:
            pszReason = "format changed";
            break;
        case DisconnectReasonSessionLogoff:
            pszReason = "user logged off";
            break;
        case DisconnectReasonSessionDisconnected:
            pszReason = "session disconnected";
            break;
        case DisconnectReasonExclusiveModeOverride:
            pszReason = "exclusive-mode override";
            break;
        }
        printf("Audio session disconnected (reason: %s)\n",
               pszReason);

        return S_OK;
    }
};

The CAudioSessionEvents class in the preceding code example is an implementation of the IAudioSessionEvents interface. This particular implementation might be part of a console application that prints information about session events to a Command Prompt window. Because IAudioSessionEvents inherits from IUnknown, the class definition contains implementations of the IUnknown methods AddRef, Release, and QueryInterface. The remaining public methods in the class definition are specific to the IAudioSessionEvents interface.

Some clients might not be interested in monitoring all types of session events. In the preceding code example, several notification methods in the CAudioSessionEvents class do nothing. For example, the OnChannelVolumeChanged method does nothing except to return status code S_OK. This application does not monitor channel volumes because it does not change the channel volumes (by calling the methods in the IChannelAudioVolume interface), and it does not share the session with other applications that might change the channel volumes.

The only three methods in the CAudioSessionEvents class that notify the user of session events are OnSimpleVolumeChanged, OnStateChanged, and OnSessionDisconnected. For example, if the user runs the system volume-control program, Sndvol, and uses the volume control in Sndvol to change the application's volume level, OnSimpleVolumeChanged immediately prints the new volume level.

For a code example that registers and unregisters a client's IAudioSessionEvents interface, see Audio Events for Legacy Audio Applications.

Audio Sessions