Menggunakan Antarmuka IKsControl untuk Mengakses Properti Audio

Dalam kasus yang jarang terjadi, aplikasi audio khusus mungkin perlu menggunakan antarmuka IKsControl untuk mengakses kemampuan perangkat keras tertentu dari adaptor audio yang tidak diekspos oleh DeviceTopology API atau MMDevice API. Antarmuka IKsControl membuat properti, peristiwa, dan metode perangkat kernel-streaming (KS) tersedia untuk aplikasi mode pengguna. Minat utama untuk aplikasi audio adalah properti KS. Antarmuka IKsControl dapat digunakan bersama dengan DEVICETopology API dan MMDevice API untuk mengakses properti KS adaptor audio.

Antarmuka IKsControl dimaksudkan terutama untuk digunakan oleh vendor perangkat keras yang menulis aplikasi panel kontrol untuk mengelola perangkat keras audio mereka. IKsControl kurang berguna untuk aplikasi audio tujuan umum yang tidak terkait dengan perangkat keras tertentu. Alasannya adalah bahwa vendor perangkat keras sering menerapkan mekanisme kepemilikan untuk mengakses properti audio perangkat mereka. Berbeda dengan DEVICETopology API, yang menyembunyikan kekhasan driver khusus perangkat keras dan menyediakan antarmuka yang relatif seragam untuk mengakses properti audio, aplikasi menggunakan IKsControl untuk berkomunikasi langsung dengan driver. Untuk informasi selengkapnya tentang IKsControl, lihat dokumentasi Windows DDK.

Seperti yang dibahas dalam Topologi Perangkat, subunit dalam topologi perangkat adaptor mungkin mendukung satu atau beberapa antarmuka kontrol khusus fungsi yang ditunjukkan di kolom kiri tabel berikut. Setiap entri di kolom kanan tabel adalah properti KS yang sesuai dengan antarmuka kontrol di sebelah kiri. Antarmuka kontrol menyediakan akses mudah ke properti. Sebagian besar driver audio menggunakan properti KS untuk mewakili kemampuan pemrosesan khusus fungsi subunit (juga disebut sebagai node KS) dalam topologi adaptor audio mereka. Untuk informasi selengkapnya tentang properti KS dan node KS, lihat dokumentasi Windows DDK.

Antarmuka kontrol Properti KS
IAudioAutoGainControl KSPROPERTY_AUDIO_AGC
IAudioBass KSPROPERTY_AUDIO_BASS
IAudioChannelConfig KSPROPERTY_AUDIO_CHANNEL_CONFIG
IAudioInputSelector KSPROPERTY_AUDIO_MUX_SOURCE
IAudioLoudness KSPROPERTY_AUDIO_LOUDNESS
IAudioMidrange KSPROPERTY_AUDIO_MID
IAudioMute KSPROPERTY_AUDIO_MUTE
IAudioOutputSelector KSPROPERTY_AUDIO_DEMUX_DEST
IAudioPeakMeter KSPROPERTY_AUDIO_PEAKMETER
IAudioTreble KSPROPERTY_AUDIO_TREBLE
IAudioVolumeLevel KSPROPERTY_AUDIO_VOLUMELEVEL
IDeviceSpecificProperty KSPROPERTY_AUDIO_DEV_SPECIFIC

 

Topologi beberapa adaptor audio mungkin berisi subunit yang memiliki properti KS yang tidak tercantum dalam tabel sebelumnya. Misalnya, asumsikan bahwa panggilan ke metode IPart::GetSubType untuk subunit tertentu mengambil nilai GUID KSNODETYPE_TONE. GUID subjenis ini menunjukkan bahwa subunit mendukung satu atau beberapa properti KS berikut:

  • KSPROPERTY_AUDIO_BASS
  • KSPROPERTY_AUDIO_MID
  • KSPROPERTY_AUDIO_TREBLE
  • KSPROPERTY_AUDIO_BASS_BOOST

Tiga properti pertama dalam daftar ini dapat diakses melalui antarmuka kontrol yang muncul di tabel sebelumnya, tetapi properti KSPROPERTY_AUDIO_BASS_BOOST tidak memiliki antarmuka kontrol yang sesuai di DEVICETopology API. Namun, aplikasi dapat menggunakan antarmuka IKsControl untuk mengakses properti ini, jika subunit mendukung properti .

Langkah-langkah berikut diperlukan untuk mengakses properti KSPROPERTY_AUDIO_BASS_BOOST subjenis KSNODETYPE_TONE:

  1. Panggil metode I Koneksi or::GetDeviceId Koneksi edTo atau IDeviceTopology::GetDeviceId untuk mendapatkan string ID perangkat yang mengidentifikasi perangkat adaptor. String ini mirip dengan string ID titik akhir, kecuali bahwa string tersebut mengidentifikasi perangkat adaptor alih-alih perangkat titik akhir. Untuk informasi selengkapnya tentang perbedaan antara perangkat adaptor dan perangkat titik akhir, lihat Perangkat Titik Akhir Audio.
  2. Dapatkan antarmuka IMMDevice dari perangkat adaptor dengan memanggil metode IMMDeviceEnumerator::GetDevice dengan string ID perangkat. Antarmuka IMMDevice ini sama dengan antarmuka yang dijelaskan dalam Antarmuka IMMDevice, tetapi mewakili perangkat adaptor alih-alih perangkat titik akhir.
  3. Dapatkan antarmuka IKsControl pada subunit dengan memanggil metode IMMDevice::Activate dengan parameter iid diatur ke REFIID IID_IKsControl. Perhatikan bahwa antarmuka yang didukung oleh metode Aktifkan ini, yang untuk perangkat adaptor, berbeda dari antarmuka yang didukung oleh metode Aktifkan untuk perangkat titik akhir. Secara khusus, metode Aktifkan untuk perangkat adaptor mendukung IKsControl.
  4. Panggil metode IPart::GetLocalId untuk mendapatkan ID lokal subunit.
  5. Buat permintaan properti KS. ID simpul KS yang diperlukan untuk permintaan terkandung dalam 16 bit paling tidak signifikan dari ID lokal yang diperoleh pada langkah sebelumnya.
  6. Kirim permintaan properti KS ke driver audio dengan memanggil metode IKsControl::KsProperty. Untuk informasi selengkapnya tentang metode ini, lihat dokumentasi Windows DDK.

Contoh kode berikut mengambil nilai properti KSPROPERTY_AUDIO_BASS_BOOST dari subunit subjenis KSNODETYPE_TONE:

//-----------------------------------------------------------
// This function calls the IKsControl::Property method to get
// the value of the KSPROPERTY_AUDIO_BASS_BOOST property of
// a subunit. Parameter pPart should point to a part that is
// a subunit with a subtype GUID value of KSNODETYPE_TONE.
//-----------------------------------------------------------
#define PARTID_MASK 0x0000ffff
#define EXIT_ON_ERROR(hres)  \
              if (FAILED(hres)) { goto Exit; }
#define SAFE_RELEASE(punk)  \
              if ((punk) != NULL)  \
                { (punk)->Release(); (punk) = NULL; }

const IID IID_IKsControl = __uuidof(IKsControl);

HRESULT GetBassBoost(IMMDeviceEnumerator *pEnumerator,
                     IPart *pPart, BOOL *pbValue)
{
    HRESULT hr;
    IDeviceTopology *pTopology = NULL;
    IMMDevice *pPnpDevice = NULL;
    IKsControl *pKsControl = NULL;
    LPWSTR pwszDeviceId = NULL;

    if (pEnumerator == NULL || pPart == NULL || pbValue == NULL)
    {
        return E_INVALIDARG;
    }

    // Get the topology object for the adapter device that contains
    // the subunit represented by the IPart interface.
    hr = pPart->GetTopologyObject(&pTopology);
    EXIT_ON_ERROR(hr)

    // Get the device ID string that identifies the adapter device.
    hr = pTopology->GetDeviceId(&pwszDeviceId);
    EXIT_ON_ERROR(hr)

    // Get the IMMDevice interface of the adapter device object.
    hr = pEnumerator->GetDevice(pwszDeviceId, &pPnpDevice);
    EXIT_ON_ERROR(hr)

    // Activate an IKsControl interface on the adapter device object.
    hr = pPnpDevice->Activate(IID_IKsControl, CLSCTX_ALL, NULL, (void**)&pKsControl);
    EXIT_ON_ERROR(hr)

    // Get the local ID of the subunit (contains the KS node ID).
    UINT localId = 0;
    hr = pPart->GetLocalId(&localId);
    EXIT_ON_ERROR(hr)

    KSNODEPROPERTY_AUDIO_CHANNEL ksprop;
    ZeroMemory(&ksprop, sizeof(ksprop));
    ksprop.NodeProperty.Property.Set = KSPROPSETID_Audio;
    ksprop.NodeProperty.Property.Id = KSPROPERTY_AUDIO_BASS_BOOST;
    ksprop.NodeProperty.Property.Flags = KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_TOPOLOGY;
    ksprop.NodeProperty.NodeId = localId & PARTID_MASK;
    ksprop.Channel = 0;

    // Send the property request.to the device driver.
    BOOL bValue = FALSE;
    ULONG valueSize;
    hr = pKsControl->KsProperty(
                         &ksprop.NodeProperty.Property, sizeof(ksprop),
                         &bValue, sizeof(bValue), &valueSize);
    EXIT_ON_ERROR(hr)

    *pbValue = bValue;

Exit:
    SAFE_RELEASE(pTopology)
    SAFE_RELEASE(pPnpDevice)
    SAFE_RELEASE(pKsControl)
    CoTaskMemFree(pwszDeviceId);
    return hr;
}

Dalam contoh kode sebelumnya, fungsi GetBassBoost mengambil tiga parameter berikut:

  • pEnumerator menunjuk ke antarmuka IMMDeviceEnumerator dari enumerator titik akhir audio.
  • pPart menunjuk ke antarmuka IPart subunit yang memiliki subjenis KSNODETYPE_TONE.
  • pbValue menunjuk ke variabel BOOL tempat fungsi menulis nilai properti.

Program memanggil GetBassBoost hanya setelah memanggil IPart::GetSubType dan menentukan bahwa subjenis subunit KSNODETYPE_TONE. Nilai properti TRUE jika peningkatan bass diaktifkan. Ini ADALAH FALSE jika peningkatan bass dinonaktifkan.

Di awal fungsi GetBassBoost, panggilan ke metode IPart::GetTopologyObject mendapatkan antarmuka IDeviceTopology dari perangkat adaptor yang berisi subunit KSNODETYPE_TONE. Panggilan metode IDeviceTopology::GetDeviceId mengambil string ID perangkat yang mengidentifikasi perangkat adaptor. Panggilan metode IMMDeviceEnumerator::GetDevice mengambil string ID perangkat sebagai parameter input, dan mengambil antarmuka IMMDevice dari perangkat adaptor. Selanjutnya, panggilan metode IMMDevice::Activate mengambil antarmuka IKsControl subunit. Untuk informasi selengkapnya tentang antarmuka IKsControl , lihat dokumentasi Windows DDK.

Selanjutnya, contoh kode sebelumnya membuat struktur KSNODEPROPERTY_AUDIO_CHANNEL yang menjelaskan properti bass-boost. Contoh kode meneruskan penunjuk ke struktur ke metode IKsControl::KsProperty , yang menggunakan informasi dalam struktur untuk mengambil nilai properti. Untuk informasi selengkapnya tentang struktur KSNODEPROPERTY_AUDIO_CHANNEL dan metode IKsControl::KsProperty , lihat dokumentasi Windows DDK.

Perangkat keras audio biasanya menetapkan status peningkatan bass terpisah ke setiap saluran dalam aliran audio. Pada prinsipnya, peningkatan bass dapat diaktifkan untuk beberapa saluran dan dinonaktifkan untuk yang lain. Struktur KSNODEPROPERTY_AUDIO_CHANNEL berisi anggota Saluran yang menentukan nomor saluran. Jika aliran berisi saluran N , saluran dinomor dari 0 hingga N— 1. Contoh kode sebelumnya mendapatkan nilai properti bass-boost hanya untuk saluran 0. Implementasi ini secara implisit mengasumsikan bahwa properti bass-boost untuk semua saluran diatur secara seragam ke keadaan yang sama. Dengan demikian, membaca properti bass-boost untuk saluran 0 cukup untuk menentukan nilai properti bass-boost untuk aliran. Agar konsisten dengan asumsi ini, fungsi yang sesuai untuk mengatur properti bass-boost akan mengatur semua saluran ke nilai properti bass-boost yang sama. Ini adalah konvensi yang wajar, tetapi tidak semua vendor perangkat keras selalu mengikutinya. Misalnya, vendor mungkin menyediakan aplikasi panel kontrol yang memungkinkan peningkatan bass hanya untuk saluran yang mendorong speaker rentang penuh. (Speaker rentang penuh mampu memutar suara di atas rentang penuh dari bass hingga treble.) Dalam hal ini, nilai properti yang diambil oleh contoh kode sebelumnya mungkin tidak secara akurat mewakili status peningkatan bass aliran.

Klien yang menggunakan antarmuka kontrol yang tercantum dalam tabel sebelumnya dapat memanggil metode IPart::RegisterControlChangeCallback untuk mendaftar pemberitahuan ketika nilai parameter kontrol berubah. Perhatikan bahwa antarmuka IKsControl tidak menyediakan sarana serupa bagi klien untuk mendaftar pemberitahuan saat nilai properti berubah. Jika IKsControl memang mendukung pemberitahuan perubahan properti, IKsControl dapat menginformasikan aplikasi ketika aplikasi lain mengubah nilai properti. Namun, berbeda dengan kontrol yang lebih umum digunakan yang dipantau melalui pemberitahuan IPart, properti yang dikelola oleh IKsControl terutama ditujukan untuk digunakan oleh vendor perangkat keras, dan properti tersebut kemungkinan hanya akan diubah oleh aplikasi panel kontrol yang ditulis oleh vendor. Jika aplikasi harus mendeteksi perubahan properti yang dilakukan oleh aplikasi lain, aplikasi dapat mendeteksi perubahan dengan secara berkala melakukan polling nilai properti melalui IKsControl.

Panduan Pemrograman