오디오 세션 이벤트

공유 모드 오디오 스트림을 관리하는 애플리케이션은 세션 이벤트가 발생할 때 알림을 수신하도록 등록할 수 있습니다. 앞에서 설명한 대로 각 스트림은 오디오 세션에 속합니다. 세션 이벤트는 오디오 세션의 상태 변경으로 시작됩니다.

클라이언트 애플리케이션은 다음 유형의 세션 이벤트에 대한 알림을 수신하도록 등록할 수 있습니다.

  • 세션 서브믹스의 master 볼륨 수준 또는 음소거 상태가 변경되었습니다.
  • 세션 서브믹스의 하나 이상의 채널 볼륨 수준이 변경되었습니다.
  • 세션의 연결이 끊어졌습니다.
  • 세션의 활동 상태가 활성, 비활성 또는 만료됨으로 변경되었습니다.
  • 세션에 새 그룹화 매개 변수가 할당되었습니다.
  • 세션의 사용자 인터페이스 속성(아이콘 또는 표시 이름)이 변경되었습니다.

클라이언트는 IAudioSessionEvents 인터페이스 구현의 메서드를 통해 이러한 이벤트에 대한 알림을 받습니다. WASAPI 시스템 모듈에 의해 구현되는 WASAPI의 다른 인터페이스와 달리 클라이언트는 IAudioSessionEvents를 구현합니다. 이 인터페이스의 메서드는 세션 이벤트가 발생할 때 WASAPI 시스템 모듈에서 콜백을 받습니다.

알림 수신을 시작하기 위해 클라이언트는 IAudioSessionControl::RegisterAudioSessionNotification 메서드를 호출하여 IAudioSessionEvents 인터페이스를 등록합니다. 클라이언트에 더 이상 알림이 필요하지 않은 경우 IAudioSessionControl::UnregisterAudioSessionNotification 메서드를 호출하여 등록을 삭제합니다.

다음 코드 예제에서는 IAudioSessionEvents 인터페이스의 가능한 구현을 보여 줍니다.

//-----------------------------------------------------------
// 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;
    }
};

이전 코드 예제의 CAudioSessionEvents 클래스는 IAudioSessionEvents 인터페이스의 구현입니다. 이 특정 구현은 세션 이벤트에 대한 정보를 명령 프롬프트 창에 출력하는 콘솔 애플리케이션의 일부일 수 있습니다. IAudioSessionEventsIUnknown에서 상속되므로 클래스 정의에는 IUnknown 메서드 AddRef, ReleaseQueryInterface의 구현이 포함됩니다. 클래스 정의의 나머지 공용 메서드는 IAudioSessionEvents 인터페이스와 관련이 있습니다 .

일부 클라이언트는 모든 유형의 세션 이벤트를 모니터링하는 데 관심이 없을 수 있습니다. 앞의 코드 예제에서 CAudioSessionEvents 클래스의 여러 알림 메서드는 아무 작업도 수행하지 않습니다. 예를 들어 OnChannelVolumeChanged 메서드는 상태 코드 S_OK 반환하는 것 외에는 아무 작업도 수행하지 않습니다. 이 애플리케이션은 채널 볼륨을 변경하지 않으므로( IChannelAudioVolume 인터페이스에서 메서드를 호출함) 채널 볼륨을 모니터링하지 않으며 채널 볼륨을 변경할 수 있는 다른 애플리케이션과 세션을 공유하지 않습니다.

세션 이벤트를 사용자에게 알리는 CAudioSessionEvents 클래스의 세 가지 메서드는 OnSimpleVolumeChanged, OnStateChangedOnSessionDisconnected입니다. 예를 들어 사용자가 시스템 볼륨 제어 프로그램인 Sndvol을 실행하고 Sndvol의 볼륨 컨트롤을 사용하여 애플리케이션의 볼륨 수준을 OnSimpleVolumeChanged 변경하는 경우 즉시 새 볼륨 수준을 출력합니다.

클라이언트의 IAudioSessionEvents 인터페이스를 등록 및 등록 취소하는 코드 예제는 레거시 오디오 애플리케이션에 대한 오디오 이벤트를 참조하세요.

오디오 세션