Поделиться через


Настройка и запрос модулей звуковых устройств

В этой статье показано, как отправлять команды и получать уведомления об изменениях из модулей звуковых устройств из приложения UWP. Модуль звукового устройства может быть аппаратным модулем обработки эффектов или любым другим модулем конфигурации звука, определенным звуковым драйвером. Эта функция была разработана, чтобы позволить поставщикам модулей создавать приложения UWP, которые позволяют пользователям управлять и получать сведения о состоянии из модуля обработки звука, работающего в DSP. Чтобы использовать API модуля аудиоустройства, показанные в этой статье, необходимо указать ограниченную возможность audioDeviceConfiguration в манифесте пакета приложения.

Получение экземпляра класса AudioDeviceModulesManager

Все операции модуля аудиоустройства, показанные в этой статье, начинаются с получения экземпляра AudioDeviceModulesManager. Для этого сначала вызовите статический метод GetDefaultAudioRenderId класса MediaDevice . При этом возвращается идентификатор устройства отрисовки звука по умолчанию, который затем передается в конструктор для AudioDeviceModulesManager для создания экземпляра класса , связанного с звуковым устройством.

C#

var endpointId = MediaDevice.GetDefaultAudioRenderId(AudioDeviceRole.Default);
var audioModuleManager = new AudioDeviceModulesManager(endpointId);

Запрос установленных модулей аудиоустройств

Запросите все установленные модули аудиоустройства, вызвав FindAll класса AudioDeviceModulesManager . Запросите определенный набор модулей аудиоустройства, вызвав FindAllById и передав идентификатор запрошенных модулей. Следующий пример определяет идентификатор для набора модулей, вызывает FindAllById для получения списка объектов AudioDeviceModule , а затем выводит сведения о каждом модуле в выходные данные отладки.

C#

public const string Contoso_AudioDeviceModuleId = "F72E09C3-FEBA-4C50-93BE-2CA56123AF09";

C#

var endpointId = MediaDevice.GetDefaultAudioRenderId(AudioDeviceRole.Default);
var audioModuleManager = new AudioDeviceModulesManager(endpointId);
var modules = audioModuleManager.FindAllById(Contoso_AudioDeviceModuleId);

foreach (var module in modules)
{
    var classId = module.ClassId;
    var name = module.DisplayName;
    var minorVersion = module.MinorVersion;
    var majorVersion = module.MajorVersion;
    var instanceId = module.InstanceId;

        Debug.WriteLine($"{classId} : {name} : {minorVersion} : {majorVersion} : {instanceId}");
}

Отправка команды в модуль звукового устройства и получение результирующих данных

Отправка команд в модуль звукового устройства путем вызова SendCommandAsync для объекта AudioDeviceModule . Метод SendCommandAsync принимает массив байтов в качестве аргумента. Как правило, этот массив байтов содержит идентификатор команды, за которым следуют данные, связанные с командой, но формат и значения команды полностью определяются поставщиком и рассматриваются системой как прозрачные.

Метод SendCommandAsync возвращает асинхронную операцию, которая после завершения возвращает объект ModuleCommandResult , представляющий результат команды. Свойство Status содержит значение перечисления, указывающее, удалось ли системе выполнить команду. Это не обязательно означает, что модуль звукового устройства смог успешно выполнить команду. Свойство Result содержит массив байтов, возвращаемый модулем звукового устройства для указания состояния команды. Как правило, это значение, указывающее на успех или сбой, за которым следует результат данных команды. Как и в случае с командами модуля, форматы и значения ответа модуля определяются поставщиком.

В следующем примере метод FindAllAsync вызывается для получения набора модулей звуковых устройств. DataWriter используется для создания массива байтов, содержащего пример команды и данных. SendCommandAsync вызывается для отправки буфера команд и после завершения асинхронной операции возвращается ModuleCommandResult . Если команда выполнена успешно, dataReader сначала используется для чтения целочисленного значения состояния, возвращаемого из модуля. Если это значение является значением успешного выполнения, определяемым поставщиком, остальные данные результатов считываются и используются приложением, например для обновления пользовательского интерфейса.

C#

public const byte Contoso_ReverbLevel_Command = 30; 
public const byte Contoso_SendCommand_Success = 99;

C#

var endpointId = MediaDevice.GetDefaultAudioRenderId(AudioDeviceRole.Default);
var audioModuleManager = new AudioDeviceModulesManager(endpointId);
var modules = audioModuleManager.FindAllById(Contoso_AudioDeviceModuleId);

foreach (var module in modules)
{
    var writer = new Windows.Storage.Streams.DataWriter();
    writer.WriteByte(Contoso_ReverbLevel_Command);
    writer.WriteByte(100);

    var command = writer.DetachBuffer();

    var result = await module.SendCommandAsync(command);

    if (result.Status == SendCommandStatus.Success)
    {
        using (DataReader reader = DataReader.FromBuffer(result.Result))
        {
            int bufferStatus = reader.ReadInt32();
            if (bufferStatus == Contoso_SendCommand_Success)
            {
                byte[] data = { 0, 0 };
                reader.ReadBytes(data);
                // Do something with returned data, such as update UI
            }
        }
    }
}

Получение уведомлений при изменении модулей звуковых устройств

Приложения могут получать уведомления об обновлении модуля звукового устройства, зарегистрировав событие ModuleNotificationReceived .

C#

var endpointId = MediaDevice.GetDefaultAudioRenderId(AudioDeviceRole.Default);
var audioModuleManager = new AudioDeviceModulesManager(endpointId);

audioModuleManager.ModuleNotificationReceived += AudioModuleManager_ModuleNotificationReceived;

ModuleNotificationReceived будет возникать при изменении любого модуля звукового устройства, связанного с текущим звуковым устройством. Чтобы определить, связано ли событие с определенным модулем, получите экземпляр AudioDeviceModule , перейдя к свойству Moduleобъекта AudioDeviceModuleNoticiationEventArgs , переданного в обработчик событий, а затем проверив свойство ClassId , идентифицирующее модуль. Данные, связанные с событием, передаются в виде массива байтов, хранящегося в свойстве NotificationData аргументов события. Как и в случае с командами и результатами, формат возвращаемого массива байтов определяется поставщиком. В приведенном ниже примере, если первый байт данных уведомления содержит пример значения для параметра уровня реверберации модуля, данные считываются и используются для обновления пользовательского интерфейса.

C#

public const byte Contoso_ReverbLevel_Data = 25;

C#

private void AudioModuleManager_ModuleNotificationReceived(AudioDeviceModulesManager sender, AudioDeviceModuleNotificationEventArgs args)
{
    if (args.Module.ClassId == Contoso_AudioDeviceModuleId)
    {
        // Get the coefficient data from the reverb module.
        using (DataReader reader = DataReader.FromBuffer(args.NotificationData))
        {
            // read notification data.
            byte item = reader.ReadByte();

            // if reverb coefficient data are changed.
            if (item == Contoso_ReverbLevel_Data)
            {
                // read the new value
                byte[] data = { 0 };
                reader.ReadBytes(data);
                ReverbLevelSlider.Value = data[0];
            }
        }
    }
}