Ввод устройства с помощью Выходного Аудиоустройства 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
Необходимо сначала получить 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 для упрощения операций. Таким образом, в случае, когда Вы будете использовать аудиоустройство в качестве источника для вывода аудио к устройству, используйте следующее соединение:
Источник | Место назначения |
---|---|
Исходный Модуль (выходной объем, выходной элемент) | AUHAL (входной объем, элемент 0) |
Когда Вы хотите получить входные данные аудиоустройства, соединение должно быть:
Источник | Место назначения |
---|---|
AUHAL (выходной объем, элемент 1) | Целевой Модуль (входной объем, входной элемент) |
Конечно, для устройства как Встроенное Аудиоустройство, обеспечивающее оба ввода и вывода, программное обеспечение playthrough механизм может быть установлено просто путем создания следующего соединения:
Источник | Место назначения |
---|---|
AUHAL (выходной объем, элемент 1) | AUHAL (входной объем, элемент 0) |
Можно было также сделать любое число произвольных операций по обработке к аудио от ввода для вывода путем вставки одного или более аудиоустройств между вводом и выводом. Так, позволяет, берут пример, где Вы хотите обработать Встроенный Аудиовход с многополосным Аудиоустройством компрессора. Можно сделать это путем создания следующих соединений:
Источник | Место назначения |
---|---|
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 отношение, отображение канала необходимо. Отображение канала укажет, с какими каналами устройства Ваше аудиоустройство будет взаимодействовать. Если Вы намереваетесь использовать какую-либо установку кроме отображения по умолчанию, это только должно быть установлено.
Канал устройства | Ваш канал |
---|---|
0 | 0 |
1 | 1 |
2 | 2 |
... | ... |
Например, у нас есть устройство с 4 каналами, которое мы используем для ввода, но мы только желаем каналов 2 и 3 из устройства для стереовхода. Мы должны присвоиться (отображают) каналы, которые мы хотим от устройства до каналов AUHAL. Для создания карты канала для нашего AUHAL необходимо сделать массив SInt32 для каждого *место назначения* карты. Каждый элемент в массиве Sint32 будет или относиться к индексу каналов источника, которые будут направлены месту назначения или-1 значению «никакой источник». В этом примере мы создали бы массив 2 элементов и инициализировали бы значения к-1. Для каналов, которые мы хотели бы отобразить, мы устанавливаем значение элемента в массиве карты канала к 2 и 3. В результате наша карта канала [2,3].
Канал устройства | Ваш канал |
---|---|
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 для взаимодействия через интерфейс к аудиоустройству значительно упрощает взаимодействие между приложениями и аудиоустройствами. Это Аудиоустройство может помочь аудио разработчикам в получении информации аудиоустройства, а также переносе и получении аудиоданных.
Пример кода и ссылки
История версии документа
Дата | Примечания |
---|---|
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. |