Техническое примечание TN2091

Ввод устройства с помощью Выходного Аудиоустройства HAL

Это техническое примечание иллюстрирует, как получить ввод из аудиоустройства при помощи AudioOutputUnit Уровня аппаратной абстракции (AUHAL). AUHAL может использоваться для упрощения операций ввода и вывода, обычно делавшихся с аудиоустройствами.

Приложение может использовать AudioOutputUnit Уровня аппаратной абстракции (HAL) для взаимодействия через интерфейс к единственному аудиоустройству. AudioOutputUnit (AUHAL) модуль находится поверх AudioDevice возразите, как определено в <CoreAudio/AudioHardware.h>. AUHAL может привыкнуть для ввода и вывода к аудиоустройству.

AUHAL может использоваться для получения ввода от аудиоустройства путем выполнения этих шагов:

1. Откройте AUHAL

2. Включите AUHAL для ввода.

3. Установите устройство ввода данных по умолчанию как текущее устройство ввода данных AUHAL.

4. Получите формат устройства и укажите формат аудио, которого Вы желаете.

5. Создайте входной обратный вызов и зарегистрируйте его в AUHAL.

6. Выделите необходимые буферы.

7. Инициализируйте и запустите AUHAL.

Эти шаги проиллюстрированы подробно всюду по этому technote.

Создание AudioOutputUnit
Быстрое слово на соединениях Аудиоустройства
Включение IO
Установка текущего устройства AudioOutputUnit
Что относительно формата аудиоданных?
Отображение канала
Создание Ввода proc для AudioOutputUnit
Инициализация и запуск AudioOutputUnit
Получение данных от AudioOutputUnit
Заключение
Пример кода и ссылки
История версии документа

Создание AudioOutputUnit

Необходимо сначала получить AudioOutputUnit при помощи Описания Компонента, как Вы были бы при попытке получить любое другое Аудиоустройство.

Перечисление 1  , Как открыть AudioOutputUnit 10.6 и позже

 AudioComponent comp;
    AudioComponentDescription desc;
    AudioComponentInstance auHAL;
 
    //There are several different types of Audio Units.
    //Some audio units serve as Outputs, Mixers, or DSP
    //units. See AUComponent.h for listing
    desc.componentType = kAudioUnitType_Output;
 
    //Every Component has a subType, which will give a clearer picture
    //of what this components function will be.
    desc.componentSubType = kAudioUnitSubType_HALOutput;
 
     //all Audio Units in AUComponent.h must use
     //"kAudioUnitManufacturer_Apple" as the Manufacturer
    desc.componentManufacturer = kAudioUnitManufacturer_Apple;
    desc.componentFlags = 0;
    desc.componentFlagsMask = 0;
 
    //Finds a component that meets the desc spec's
    comp = AudioComponentFindNext(NULL, &desc);
    if (comp == NULL) exit (-1);
 
     //gains access to the services provided by the component
    AudioComponentInstanceNew(comp, &auHAL);

Перечисление 2  , Как открыть AudioOutputUnit 10.5.x и ранее

 Component comp;
    ComponentDescription desc;
    ComponentInstance audioOutputUnit;
 
    //There are several different types of Audio Units.
    //Some audio units serve as Outputs, Mixers, or DSP
    //units. See AUComponent.h for listing
    desc.componentType = kAudioUnitType_Output;
 
    //Every Component has a subType, which will give a clearer picture
    //of what this components function will be.
    desc.componentSubType = kAudioUnitSubType_HALOutput;
 
     //all Audio Units in AUComponent.h must use
     //"kAudioUnitManufacturer_Apple" as the Manufacturer
    desc.componentManufacturer = kAudioUnitManufacturer_Apple;
    desc.componentFlags = 0;
    desc.componentFlagsMask = 0;
 
    //Finds a component that meets the desc spec's
    comp = FindNextComponent(NULL, &desc);
    if (comp == NULL) exit (-1);
 
     //gains access to the services provided by the component
    OpenAComponent(comp, &audioOutputUnit);

Быстрое слово на соединениях Аудиоустройства

Когда аудиоустройство просят обеспечить аудиоданные, оно делает одну из двух вещей, в зависимости от того, как Вы соединяете его.

В этом втором случае два аудиоустройства непосредственно подключены друг к другу. Например, скажите, что аудиоустройство A1 подает аудиоустройство A2. Когда A2 просят предоставить данные, он «вытягивает» его от A1. Это выделяет требование, чтобы соединения между аудиоустройствами совместно использовали общий формат аудиопотока. Для чтения больше о соединениях аудиоустройства обратитесь к Графикам Обработки аудиоданных и разделу Pull Model Руководства по программированию Аудиоустройства.

Рисунок 1  поток сигналов AUHAL

Рисунок 1 иллюстрирует поток аудиоданных от аудиоустройств до и из Вашего приложения. Ваше приложение может подключить аудиоустройство к любому элементу (шина) AUHAL для упрощения операций. Таким образом, в случае, когда Вы будете использовать аудиоустройство в качестве источника для вывода аудио к устройству, используйте следующее соединение:

Табличное 1  Выходное аудио к устройству

Источник

Место назначения

Исходный Модуль (выходной объем, выходной элемент)

AUHAL (входной объем, элемент 0)

Когда Вы хотите получить входные данные аудиоустройства, соединение должно быть:

Табличное 2  аудио Получения в устройство

Источник

Место назначения

AUHAL (выходной объем, элемент 1)

Целевой Модуль (входной объем, входной элемент)

Конечно, для устройства как Встроенное Аудиоустройство, обеспечивающее оба ввода и вывода, программное обеспечение playthrough механизм может быть установлено просто путем создания следующего соединения:

Таблица 3  Простое программное обеспечение playthrough

Источник

Место назначения

AUHAL (выходной объем, элемент 1)

AUHAL (входной объем, элемент 0)

Можно было также сделать любое число произвольных операций по обработке к аудио от ввода для вывода путем вставки одного или более аудиоустройств между вводом и выводом. Так, позволяет, берут пример, где Вы хотите обработать Встроенный Аудиовход с многополосным Аудиоустройством компрессора. Можно сделать это путем создания следующих соединений:

Таблица 4  , Обрабатывающая ввод Встроенного Аудио с многополосным Аудиоустройством компрессора.

Источник

Место назначения

AUHAL (выходной объем, элемент 1)

Многополосный Компрессор (входной объем, элемент 0)

Многополосный Компрессор (выходной объем, элемент 0)

AUHAL (входной объем, элемент 0)

APIs AUGraph (в AudioToolbox.framework) может управлять этими соединениями для Вас. AUGraph представление высокого уровня ряда Аудиоустройств и соединений между ними. Посмотрите Ссылку Audio Unit Processing Graph Services для получения дополнительной информации.

Если у Вас будет два отдельных аудиоустройства, то два AUHALs будут требоваться. Однако, потому что каждый AUHAL собирается работать на своем собственном отдельном I/O proc, Вы не можете сделать прямое подключение между двумя AUHALs. Необходимо использовать механизм уведомления, чтобы уведомить устройство вывода, что данные поступили, тогда передают данные через.

Включение IO

После создания объекта AUHAL необходимо позволить IO на входном объеме Аудиоустройства получить ввод устройства. Ввод должен быть явно включен с kAudioOutputUnitProperty_EnableIO свойство на элементе 1 из AUHAL. Поскольку AUHAL может использоваться для обоих вводов и выводов для этого примера, мы должны также отключить IO на выходном объеме.

  Ввод Включения перечисления 3 и отключение вывода для AudioOutputUnit

 UInt32 enableIO;
     UInt32 size=0;
 
     //When using AudioUnitSetProperty the 4th parameter in the method
     //refer to an AudioUnitElement. When using an AudioOutputUnit
     //the input element will be '1' and the output element will be '0'.
 
 
      enableIO = 1;
      AudioUnitSetProperty(InputUnit,
                kAudioOutputUnitProperty_EnableIO,
                kAudioUnitScope_Input,
                1, // input element
                &enableIO,
                sizeof(enableIO));
 
      enableIO = 0;
      AudioUnitSetProperty(InputUnit,
                kAudioOutputUnitProperty_EnableIO,
                kAudioUnitScope_Output,
                0,   //output element
                &enableIO,
                sizeof(enableIO));

Установка текущего устройства AudioOutputUnit

AUHAL должен иметь устройство, с которым он будет взаимодействовать через интерфейс. В этом примере мы выберем устройство ввода данных системы по умолчанию для нашего текущего устройства. AudioHardwareGetProperty используемый с параметром kAudioHardwarePropertyDefaultInputDevice получит текущее устройство ввода данных, выбранное пользователем. После получения AudioDeviceID, можно установить аудиоустройство, чтобы быть текущим устройством Аудиоустройства с AudioUnitSetProperty и параметр kAudioOutputUnitProperty_CurrentDevice. Следует иметь в виду, что устройства могут только быть установлены в AUHAL после включения IO.

Перечисление 4  , Как установить текущее устройство AudioOutputUnit к устройству ввода данных по умолчанию

OSStatus SetDefaultInputDeviceAsCurrent(){
    UInt32 size;
    OSStatus err =noErr;
    size = sizeof(AudioDeviceID);
 
    AudioDeviceID inputDevice;
    err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice,
                                                  &size,
                                                  &inputDevice);
 
    if (err)
        return err;
 
    err =AudioUnitSetProperty(InputUnit,
                         kAudioOutputUnitProperty_CurrentDevice,
                         kAudioUnitScope_Global,
                         0,
                         &inputDevice,
                         sizeof(inputDevice));
 
   return err;
 
}

Что относительно формата аудиоданных?

AUHAL сглаживает потоки аудиоданных устройства в единственный устраненный чередование поток для обоих вводов и выводов. AUHALs имеют встроенное AudioConverter сделать эту трансформацию для Вас. AUHAL определяет какой AudioConverter требуется путем сравнения сглаженного формата устройства с нужным форматом клиента. Сброс или формат устройства или клиентский формат обычно будет подрывным событием, требуя, чтобы AUHAL установил новое AudioConverter. Если каналы формата устройства и нужного формата не имеют 1:1 отношение, модуль AUHAL может использовать карты канала для определения который каналы представить пользователю. Наконец, частота дискретизации устройства должна соответствовать желаемую частоту дискретизации.

Для вывода данных к аудиоустройству формат всегда выражается на выходном объеме Элемента AUHAL 0. Формат аудиоустройства может быть получен при помощи AudioUnitGetProperty с константой kAudioUnitProperty_StreamFormat. Несмотря на то, что эта информация может быть получена, это - writeable NEVER. Пользователь должен явно изменить эти настройки сами.

Для получения ввода от устройства формат устройства всегда выражается на входном объеме Элемента AUHAL 1. Поэтому необходимо установить нужный формат в выходной объем Элемента AUHAL 1. Внутреннее AudioConverter может обработать любого *простой* преобразование. Как правило, это означает, что клиент может указать вариант ANY форматов PCM. Следовательно, частота дискретизации устройства должна соответствовать желаемую частоту дискретизации. Если преобразование частоты дискретизации необходимо, оно может быть выполнено путем буферизации ввода и преобразования данных по разделять потоку с другим AudioConverter.

Перечисление 5  , Настраивающее желаемый 'входной' формат

 CAStreamBasicDescription DeviceFormat;
    CAStreamBasicDescription DesiredFormat;
   //Use CAStreamBasicDescriptions instead of 'naked'
   //AudioStreamBasicDescriptions to minimize errors.
   //CAStreamBasicDescription.h can be found in the CoreAudio SDK.
 
    UInt32 size = sizeof(CAStreamBasicDescription);
 
     //Get the input device format
    AudioUnitGetProperty (InputUnit,
                                   kAudioUnitProperty_StreamFormat,
                                   kAudioUnitScope_Input,
                                   1,
                                   &DeviceFormat,
                                   &size);
 
    //set the desired format to the device's sample rate
    DesiredFormat.mSampleRate =  DeviceFormat.mSampleRate;
 
     //set format to output scope
    AudioUnitSetProperty(
                            InputUnit,
                            kAudioUnitProperty_StreamFormat,
                            kAudioUnitScope_Output,
                            1,
                            &DesiredFormat,
                            sizeof(CAStreamBasicDescription));

Отображение канала

Если формат данных между каналами аудиоустройства и каналами нужного формата не соответствует 1:1 отношение, отображение канала необходимо. Отображение канала укажет, с какими каналами устройства Ваше аудиоустройство будет взаимодействовать. Если Вы намереваетесь использовать какую-либо установку кроме отображения по умолчанию, это только должно быть установлено.

Табличная 5  Карта Канала Значения по умолчанию (отображение канала, не необходимое)

Канал устройства

Ваш канал

0

0

1

1

2

2

...

...

Например, у нас есть устройство с 4 каналами, которое мы используем для ввода, но мы только желаем каналов 2 и 3 из устройства для стереовхода. Мы должны присвоиться (отображают) каналы, которые мы хотим от устройства до каналов AUHAL. Для создания карты канала для нашего AUHAL необходимо сделать массив SInt32 для каждого *место назначения* карты. Каждый элемент в массиве Sint32 будет или относиться к индексу каналов источника, которые будут направлены месту назначения или-1 значению «никакой источник». В этом примере мы создали бы массив 2 элементов и инициализировали бы значения к-1. Для каналов, которые мы хотели бы отобразить, мы устанавливаем значение элемента в массиве карты канала к 2 и 3. В результате наша карта канала [2,3].

Таблица 6 4  -> 2 Карты Канала

Канал устройства

Ваш канал

2

0

3

1

Перечисление 6  пример 4-> 2 канала, отображающиеся для ввода

 SInt32 *channelMap =NULL;
    UInt32 numOfChannels = DesiredFormat.mChannelsPerFrame; //2 channels
    UInt32 mapSize = numOfChannels *sizeof(SInt32);
    channelMap = (SInt32 *)malloc(mapSize);
 
    //for each channel of desired input, map the channel from
    //the device's output channel.
    for(UInt32 i=0;i<numOfChannels;i++)
    {
               channelMap[i]=-1;
    }
     //channelMap[desiredInputChannel] = deviceOutputChannel;
    channelMap[0] = 2;
    channelMap[1] = 3;
    AudioUnitSetProperty(InputUnit,
                                        kAudioOutputUnitProperty_ChannelMap,
                                        kAudioUnitScope_Output,
                                        1,
                                        channelMap,
                                        size);
    free(channelMap);

Создание Ввода proc для AudioOutputUnit

Затем, необходимо зарегистрировать входную процедуру для AUHAL. Когда AUHAL получит новые данные от Вашего устройства ввода данных, эту процедуру вызовут.

Перечисление 7  , Создающее Ввод proc для AudioOutputUnit

void MyInputCallbackSetup()
{
    AURenderCallbackStruct input;
    input.inputProc = InputProc;
    input.inputProcRefCon = 0;
 
    AudioUnitSetProperty(
            InputUnit,
            kAudioOutputUnitProperty_SetInputCallback,
            kAudioUnitScope_Global,
            0,
            &input,
            sizeof(input));
}

Инициализация и запуск AudioOutputUnit

AUHAL теперь устанавливается для получения ввода из устройства. Необходимо инициализировать и запустить Аудиоустройство, чтобы начать получать данные.

Перечисление 8  , начинающее AUHAL

OSStatus InitAndStartAUHAL()
{
   OSStatus err= noErr;
 
   err = AudioUnitInitialize(InputUnit);
   if(err)
       return err;
 
   err = AudioOutputUnitStart(InputUnit);
 
   return err;
}

Получение данных от AudioOutputUnit

AUHAL является Аудиоустройство, которое может получить и отправить аудиоданные в аудиоустройство. Для получения аудио из AUHAL необходимо получить его от выходного объема Аудиоустройства. На практике это сделано клиентом, вызывающим AudioUnitRender. Для предоставления аудио AUHAL необходимо дать ему данные по входному объему. Это сделано путем обеспечения входного обратного вызова для Аудиоустройства.

В нашем примере мы вызовем AudioUnitRender из ввода proc. Входные флаги действия рендеринга proc's, метка времени, номер шины и число кадров, которые требуют, должны быть распространены вниз к AudioUnitRender вызвать. AudioBufferList, йодатом будет NULL, поэтому необходимо обеспечить выделенное собственное AudioBufferList.

Перечисление 9  Используя AudioUnitRender для получения данных

AudioBufferList * theBufferList;
/* allocated to hold buffer data  */
 
OSStatus InputProc(
                    void *inRefCon,
                    AudioUnitRenderActionFlags *ioActionFlags,
                    const AudioTimeStamp *inTimeStamp,
                    UInt32 inBusNumber,
                    UInt32 inNumberFrames,
                    AudioBufferList * ioData)
{
    OSStatus err =noErr;
 
    err= AudioUnitRender(InputUnit,
                    ioActionFlags,
                    inTimeStamp,
                    inBusNumber,     //will be '1' for input data
                    inNumberFrames, //# of frames requested
                    theBufferList);
 
    return err;
}

Заключение

Используя AUHAL для взаимодействия через интерфейс к аудиоустройству значительно упрощает взаимодействие между приложениями и аудиоустройствами. Это Аудиоустройство может помочь аудио разработчикам в получении информации аудиоустройства, а также переносе и получении аудиоданных.

Пример кода и ссылки

CAPlayThrough

Обзор Core Audio



История версии документа


ДатаПримечания
21.01.2014

Обновленный пример кода и ссылочный URLs

23.09.2009

Передовая статья

25.07.2006

добавленная ссылка примера кода RecordAudioToFile

18.07.2006

фиксированный неправильный дисплей unicode символов, обновленных ссылок

23.08.2004

Добавленные ссылки к проектам Примера кода AUHAL. Несколько незначительных изменений, включая исправление к разрешению процесса IO.

06.07.2004

незначительные исправления в исходных списках

22.03.2004

Неуказанные версии содержания.

04.03.2004

Новый документ это, как быть введенным от аудиоустройства при помощи Выходного Аудиоустройства HAL's.