Peristiwa Audio untuk Aplikasi Audio Warisan

API audio warisan seperti DirectSound, DirectShow, dan fungsi waveOutXxx memungkinkan aplikasi untuk mendapatkan dan mengatur tingkat volume aliran audio. Aplikasi dapat menggunakan kemampuan kontrol volume dalam API ini untuk menampilkan pengguncur volume di jendela aplikasi mereka.

Di Windows Vista, program kontrol volume sistem, Sndvol, memungkinkan pengguna mengontrol tingkat volume audio untuk aplikasi individual. Penggeser volume yang ditampilkan oleh aplikasi harus ditautkan ke penggeser volume yang sesuai di Sndvol. Jika pengguna menyesuaikan volume aplikasi melalui penggeser volume di jendela aplikasi, penggeser volume yang sesuai di Sndvol segera bergerak untuk menunjukkan tingkat volume baru. Sebaliknya, jika pengguna menyesuaikan volume aplikasi melalui Sndvol, slider volume di jendela aplikasi harus bergerak untuk menunjukkan tingkat volume baru.

Di Windows Vista, Sndvol segera mencerminkan perubahan volume yang dilakukan aplikasi melalui panggilan ke metode IDirectSoundBuffer::SetVolume atau fungsi waveOutSetVolume . Namun, API audio warisan seperti DirectSound atau fungsi waveOutXxx tidak menyediakan cara untuk memberi tahu aplikasi ketika pengguna mengubah volume aplikasi melalui Sndvol. Jika aplikasi menampilkan pengguncur volume tetapi tidak menerima pemberitahuan perubahan volume, pengguncuran akan gagal mencerminkan perubahan yang dibuat oleh pengguna di Sndvol. Untuk menerapkan perilaku yang sesuai, perancang aplikasi harus mengimbangi kurangnya pemberitahuan oleh API audio warisan.

Salah satu solusinya mungkin agar aplikasi mengatur timer untuk secara berkala mengingatkannya untuk memeriksa tingkat volume untuk melihat apakah aplikasi telah berubah.

Solusi yang lebih elegan adalah agar aplikasi dapat menggunakan kemampuan pemberitahuan peristiwa API audio inti. Secara khusus, aplikasi dapat mendaftarkan antarmuka IAudioSessionEvents untuk menerima panggilan balik ketika perubahan volume atau jenis peristiwa audio lainnya terjadi. Ketika volume berubah, rutinitas panggilan balik perubahan volume dapat segera memperbarui slider volume aplikasi untuk mencerminkan perubahan.

Contoh kode berikut menunjukkan bagaimana aplikasi dapat mendaftar untuk menerima pemberitahuan perubahan volume dan peristiwa audio lainnya:

//-----------------------------------------------------------
// Register the application to receive notifications when the
// volume level changes on the default process-specific audio
// session (with session GUID value GUID_NULL) on the audio
// endpoint device with the specified data-flow direction
// (eRender or eCapture) and device role.
//-----------------------------------------------------------
#define EXIT_ON_ERROR(hr)  \
              if (FAILED(hr)) { goto Exit; }
#define SAFE_RELEASE(punk)  \
              if ((punk) != NULL)  \
                { (punk)->Release(); (punk) = NULL; }

class AudioVolumeEvents
{
    HRESULT _hrStatus;
    IAudioSessionManager *_pManager;
    IAudioSessionControl *_pControl;
    IAudioSessionEvents *_pAudioEvents;
public:
    AudioVolumeEvents(EDataFlow, ERole, IAudioSessionEvents*);
    ~AudioVolumeEvents();
    HRESULT GetStatus() { return _hrStatus; };
};

// Constructor
AudioVolumeEvents::AudioVolumeEvents(EDataFlow flow, ERole role,
                                     IAudioSessionEvents *pAudioEvents)
{
    IMMDeviceEnumerator *pEnumerator = NULL;
    IMMDevice *pDevice = NULL;

    _hrStatus = S_OK;
    _pManager = NULL;
    _pControl = NULL;
    _pAudioEvents = pAudioEvents;

    if (_pAudioEvents == NULL)
    {
        _hrStatus = E_POINTER;
        return;
    }

    _pAudioEvents->AddRef();

    // Get the enumerator for the audio endpoint devices
    // on this system.
    _hrStatus = CoCreateInstance(__uuidof(MMDeviceEnumerator),
                                 NULL, CLSCTX_INPROC_SERVER,
                                 __uuidof(IMMDeviceEnumerator),
                                 (void**)&pEnumerator);
    EXIT_ON_ERROR(_hrStatus)

    // Get the audio endpoint device with the specified data-flow
    // direction (eRender or eCapture) and device role.
    _hrStatus = pEnumerator->GetDefaultAudioEndpoint(flow, role,
                                                     &pDevice);
    EXIT_ON_ERROR(_hrStatus)

    // Get the session manager for the endpoint device.
    _hrStatus = pDevice->Activate(__uuidof(IAudioSessionManager),
                                  CLSCTX_INPROC_SERVER, NULL,
                                  (void**)&_pManager);
    EXIT_ON_ERROR(_hrStatus)

    // Get the control interface for the process-specific audio
    // session with session GUID = GUID_NULL. This is the session
    // that an audio stream for a DirectSound, DirectShow, waveOut,
    // or PlaySound application stream belongs to by default.
    _hrStatus = _pManager->GetAudioSessionControl(NULL, 0, &_pControl);
    EXIT_ON_ERROR(_hrStatus)

    _hrStatus = _pControl->RegisterAudioSessionNotification(_pAudioEvents);
    EXIT_ON_ERROR(_hrStatus)

Exit:
    SAFE_RELEASE(pEnumerator)
    SAFE_RELEASE(pDevice)
}

// Destructor
AudioVolumeEvents::~AudioVolumeEvents()
{
    if (_pControl != NULL)
    {
        _pControl->UnregisterAudioSessionNotification(_pAudioEvents);
    }
    SAFE_RELEASE(_pManager)
    SAFE_RELEASE(_pControl)
    SAFE_RELEASE(_pAudioEvents)
};

Contoh kode sebelumnya mengimplementasikan kelas bernama AudioVolumeEvents. Selama inisialisasi program, aplikasi audio memungkinkan pemberitahuan peristiwa audio dengan membuat objek AudioVolumeEvents. Konstruktor untuk kelas ini mengambil tiga parameter input:

Konstruktor memasok nilai alur dan peran sebagai parameter input ke metode IMMDeviceEnumerator::GetDefaultAudioEndpoint. Metode ini membuat objek IMMDevice yang merangkum perangkat titik akhir audio dengan arah aliran data dan peran perangkat yang ditentukan.

Aplikasi mengimplementasikan objek yang ditunjukkan oleh pAudioEvents. (Implementasi tidak ditampilkan dalam contoh kode sebelumnya. Untuk contoh kode yang mengimplementasikan antarmuka IAudioSessionEvents , lihat Peristiwa Sesi Audio.) Setiap metode dalam antarmuka ini menerima pemberitahuan dari jenis peristiwa audio tertentu. Jika aplikasi tidak tertarik pada jenis peristiwa tertentu, maka metode untuk jenis peristiwa tersebut tidak boleh melakukan apa pun kecuali mengembalikan S_OK.

Metode IAudioSessionEvents::OnSimpleVolumeChanged menerima pemberitahuan perubahan volume. Biasanya, metode ini memperbarui penggerak volume aplikasi.

Dalam contoh kode sebelumnya, konstruktor untuk kelas AudioVolumeEvents mendaftar untuk pemberitahuan pada sesi audio khusus proses yang diidentifikasi oleh nilai GUID sesi GUID_NULL. Secara default, API audio warisan seperti DirectSound, DirectShow, dan fungsi waveOutXxx menetapkan alirannya ke sesi ini. Namun, aplikasi DirectSound atau DirectShow dapat, sebagai opsi, mengambil alih perilaku default dan menetapkan alirannya ke sesi lintas proses atau ke sesi yang diidentifikasi oleh nilai GUID selain GUID_NULL. (Tidak ada mekanisme yang saat ini disediakan untuk aplikasi waveOutXxx untuk mengambil alih perilaku default dengan cara yang sama.) Untuk contoh kode aplikasi DirectShow dengan perilaku ini, lihat Peran Perangkat untuk Aplikasi DirectShow. Untuk mengakomodasi aplikasi tersebut, Anda dapat memodifikasi konstruktor dalam contoh kode sebelumnya untuk menerima dua parameter input tambahan—GUID sesi dan bendera untuk menunjukkan apakah sesi yang akan dipantau adalah sesi lintas proses atau khusus proses. Teruskan parameter ini ke panggilan ke metode IAudioSessionManager::GetAudioSessionControl di konstruktor.

Setelah konstruktor memanggil metode IAudioSessionControl::RegisterAudioSessionNotification untuk mendaftar pemberitahuan, aplikasi terus menerima pemberitahuan hanya selama antarmuka IAudioSessionControl atau IAudioSessionManager ada. Objek AudioVolumeEvents dalam contoh kode sebelumnya menyimpan referensi ke antarmuka ini sampai destruktornya dipanggil. Perilaku ini memastikan bahwa aplikasi akan terus menerima pemberitahuan selama masa pakai objek AudioVolumeEvents.

Alih-alih secara implisit memilih perangkat audio berdasarkan peran perangkatnya, aplikasi multimedia Windows DirectSound atau warisan mungkin memungkinkan pengguna untuk secara eksplisit memilih perangkat dari daftar perangkat yang tersedia yang diidentifikasi dengan nama ramah mereka. Untuk mendukung perilaku ini, contoh kode sebelumnya harus dimodifikasi untuk menghasilkan pemberitahuan peristiwa audio untuk perangkat yang dipilih. Diperlukan dua modifikasi. Pertama, ubah definisi konstruktor untuk menerima string ID titik akhir sebagai parameter input (sebagai pengganti parameter alur dan peran dalam contoh kode). String ini mengidentifikasi perangkat titik akhir audio yang sesuai dengan perangkat Bentuk gelombang DirectSound atau warisan yang dipilih. Kedua, ganti panggilan ke metode IMMDeviceEnumerator::GetDefaultAudioEndpoint dengan panggilan ke metode IMMDeviceEnumerator::GetDevice. Panggilan GetDevice mengambil string ID titik akhir sebagai parameter input dan membuat instans perangkat titik akhir yang diidentifikasi oleh string.

Teknik untuk mendapatkan string ID titik akhir untuk perangkat DirectSound atau perangkat bentuk gelombang warisan adalah sebagai berikut.

Pertama, selama enumerasi perangkat, DirectSound menyediakan string ID titik akhir untuk setiap perangkat enumerasi. Untuk memulai enumerasi perangkat, aplikasi meneruskan penunjuk fungsi panggilan balik sebagai parameter input ke fungsi DirectSoundCreate atau DirectSoundCaptureCreate . Definisi fungsi panggilan balik adalah:

BOOL DSEnumCallback(
  LPGUID  lpGuid,
  LPCSTR  lpcstrDescription,
  LPCSTR  lpcstrModule,
  LPVOID  lpContext
);

Di Windows Vista, parameter lpcstrModule menunjuk ke string ID titik akhir. (Di versi Windows sebelumnya, termasuk Windows Server 2003, Windows XP, dan Windows 2000, parameter lpcstrModule menunjuk ke nama modul driver untuk perangkat.) Parameter lpcstrDescription menunjuk ke string yang berisi nama perangkat yang mudah diingat. Untuk informasi selengkapnya tentang enumerasi perangkat DirectSound, lihat dokumentasi Windows SDK.

Kedua, untuk mendapatkan string ID titik akhir untuk perangkat bentuk gelombang warisan, gunakan fungsi waveOutMessage atau waveInMessage untuk mengirim pesan DRV_QUERYFUNCTIONINSTANCEID ke driver perangkat bentuk gelombang. Untuk contoh kode yang menunjukkan penggunaan pesan ini, lihat Peran Perangkat untuk Aplikasi Multimedia Windows Warisan.

Interoperabilitas dengan API Audio Warisan