Использование интерфейса IKsControl для доступа к свойствам звука

В редких случаях специализированное звуковое приложение может потребоваться использовать интерфейс IKsControl для доступа к определенным аппаратным возможностям звукового адаптера, который не предоставляется API DeviceTopology или API MMDevice. Интерфейс IKsControl делает свойства, события и методы устройств потоковой передачи ядра (KS) доступными для приложений пользовательского режима. Основными интересами звуковых приложений являются свойства KS. Интерфейс IKsControl можно использовать вместе с API DeviceTopology и API MMDevice для доступа к свойствам KS звуковых адаптеров.

Интерфейс IKsControl предназначен в основном для использования поставщиками оборудования, которые записывают приложения панели управления для управления своим звуковым оборудованием. IKsControl менее полезна для звуковых приложений общего назначения, которые не привязаны к определенным аппаратным устройствам. Причина заключается в том, что поставщики оборудования часто реализуют собственные механизмы для доступа к звуковым свойствам своих устройств. В отличие от API DeviceTopology, который скрывает причуды драйвера для конкретного оборудования и предоставляет относительно универсальный интерфейс для доступа к звуковым свойствам, приложения используют IKsControl для обмена данными напрямую с драйверами. Дополнительные сведения об IKsControl см. в документации по Windows DDK.

Как описано в топологиях устройств, в топологии устройства адаптера может поддерживаться один или несколько интерфейсов управления для конкретной функции, показанных в левом столбце следующей таблицы. Каждая запись в правом столбце таблицы — это свойство KS, соответствующее интерфейсу управления слева. Интерфейс управления обеспечивает удобный доступ к свойству. Большинство звуковых драйверов используют свойства KS для представления возможностей обработки отдельных функций подсоединений (также называемых узлами KS) в топологиях своих звуковых адаптеров. Дополнительные сведения о свойствах KS и узлах KS см. в документации по Windows DDK.

Интерфейс управления Свойство 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

 

Топологии некоторых звуковых адаптеров могут содержать подсоединения с свойствами KS, которые не перечислены в предыдущей таблице. Например, предположим, что вызов метода IPart::GetSubType для определенного подунига извлекает значение GUID KSNODETYPE_TONE. Этот GUID подтипа указывает, что подъединка поддерживает одно или несколько следующих свойств KS:

  • KSPROPERTY_AUDIO_BASS
  • KSPROPERTY_AUDIO_MID
  • KSPROPERTY_AUDIO_TREBLE
  • KSPROPERTY_AUDIO_BASS_BOOST

К первым трем свойствам этого списка можно получить доступ через интерфейсы управления, которые отображаются в предыдущей таблице, но свойство KSPROPERTY_AUDIO_BASS_BOOST не имеет соответствующего интерфейса управления в API DeviceTopology. Однако приложение может использовать интерфейс IKsControl для доступа к этому свойству, если подуниг поддерживает это свойство.

Для доступа к свойству KSPROPERTY_AUDIO_BASS_BOOST подтипа KSNODETYPE_TONE необходимо выполнить следующие действия.

  1. Вызовите метод I Подключение or::GetDeviceId Подключение edTo или IDeviceTopology::GetDeviceId, чтобы получить строку идентификатора устройства, которая идентифицирует устройство адаптера. Эта строка похожа на строку идентификатора конечной точки, за исключением того, что она определяет устройство адаптера вместо устройства конечной точки. Дополнительные сведения о разнице между устройством адаптера и устройством конечной точки см. в разделе "Устройства аудио конечных точек".
  2. Получите интерфейс IMMDevice устройства адаптера, вызвав метод IMMDeviceEnumerator::GetDevice со строкой идентификатора устройства. Этот интерфейс IMMDevice совпадает с интерфейсом, описанным в интерфейсе IMMDevice, но представляет устройство адаптера вместо устройства конечной точки.
  3. Получите интерфейс IKsControl в подуните, вызвав метод IMMDevice::Activate с параметром iid, заданным для reFIID IID_IKsControl. Обратите внимание, что интерфейсы, поддерживаемые этим методом Активации , которые предназначены для устройства адаптера, отличаются от интерфейсов, поддерживаемых методом Активации для устройства конечной точки. В частности, метод Activate для устройства адаптера поддерживает IKsControl.
  4. Вызовите метод IPart::GetLocalId, чтобы получить локальный идентификатор подъединения.
  5. Создайте запрос свойства KS. Идентификатор узла KS, необходимый для запроса, содержится в 16 наименее значимых битах локального идентификатора, полученного на предыдущем шаге.
  6. Отправьте запрос свойства KS звуковому драйверу, вызвав метод IKsControl::KsProperty. Дополнительные сведения об этом методе см. в документации по Windows DDK.

В следующем примере кода извлекается значение свойства KSPROPERTY_AUDIO_BASS_BOOST из подтипа 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;
}

В предыдущем примере кода функция GetBassBoost принимает следующие три параметра:

  • pEnumerator указывает на интерфейс IMMDeviceEnumerator перечислителя звуковой конечной точки.
  • pPart указывает на интерфейс IPart подтипа подтипа KSNODETYPE_TONE.
  • pbValue указывает на переменную BOOL , в которую функция записывает значение свойства.

Программа вызывает GetBassBoost только после вызова IPart::GetSubType и определяет, что подтип подсоединения KSNODETYPE_TONE. Значение свойства имеет значение TRUE , если включен импульс баса. Значение FALSE, если повышение баса отключено.

В начале функции GetBassBoost вызов метода IPart::GetTopologyObject получает интерфейс IDeviceTopologyTopology устройства адаптера, содержащего KSNODETYPE_TONE подсоединения. Вызов метода IDeviceTopology::GetDeviceId извлекает строку идентификатора устройства, которая идентифицирует устройство адаптера. Вызов метода IMMDeviceEnumerator::GetDevice принимает строку идентификатора устройства в качестве входного параметра и извлекает интерфейс IMMDevice устройства адаптера. Затем вызов метода IMMDevice::Activate извлекает интерфейс IKsControl для подъединения. Дополнительные сведения об интерфейсе IKsControl см. в документации по Windows DDK.

Далее в приведенном выше примере кода создается структура KSNODEPROPERTY_AUDIO_CHANNEL , описывающая свойство bass-boost. Пример кода передает указатель на структуру методу IKsControl::KsProperty , который использует сведения в структуре для получения значения свойства. Дополнительные сведения о структуре KSNODEPROPERTY_AUDIO_CHANNEL и методе IKsControl::KsProperty см. в документации по Windows DDK.

Звуковое оборудование обычно назначает отдельное состояние бас-импульса каждому каналу в звуковом потоке. В принципе, бас-импульс может быть включен для некоторых каналов и отключен для других. Структура KSNODEPROPERTY_AUDIO_CHANNEL содержит член канала, указывающий номер канала. Если поток содержит N-каналы , каналы нумеруются от 0 до N– 1. Приведенный выше пример кода получает значение свойства bass-boost только для канала 0. Эта реализация неявно предполагает, что свойства бас-импульса для всех каналов задаются одинаково. Таким образом, чтение свойства бас-импульса для канала 0 достаточно, чтобы определить значение свойства бас-импульса для потока. Чтобы соответствовать этому предположению, соответствующая функция для задания свойства бас-буста будет устанавливать все каналы в одно и то же значение свойства бас-буста. Это разумные соглашения, но не все поставщики оборудования обязательно следуют им. Например, поставщик может предоставить приложение панели управления, которое обеспечивает повышение баса только для каналов, которые управляют динамиками с полным диапазоном. (Полный диапазон динамик способен играть звуки в полном диапазоне от басов до требл.) В этом случае значение свойства, полученное в приведенном выше примере кода, может не точно представлять состояние бас-импульса потока.

Клиенты, использующие интерфейсы управления, перечисленные в предыдущей таблице, могут вызывать метод IPart::RegisterControlChangeCallback для регистрации уведомлений при изменении значения параметра элемента управления. Обратите внимание, что интерфейс IKsControl не предоставляет аналогичные средства для клиентов, которые регистрируются для уведомлений при изменении значения свойства. Если IKsControl поддерживал уведомления об изменении свойств, оно может сообщить приложению, когда другое приложение изменило значение свойства. Однако в отличие от более часто используемых элементов управления, отслеживаемых с помощью уведомлений IPart , свойства, управляемые IKsControl , предназначены в основном для использования поставщиками оборудования, и эти свойства, скорее всего, будут изменены только приложениями панели управления, написанными поставщиками. Если приложение должно обнаруживать изменения свойств, внесенные другим приложением, оно может обнаруживать изменения, периодически опрашив значение свойства через IKsControl.

Руководство по программированию