iOS AudioUnits 通过
Posted
技术标签:
【中文标题】iOS AudioUnits 通过【英文标题】:iOS AudioUnits pass through 【发布时间】:2012-12-01 21:52:11 【问题描述】:我正在尝试编写一个 ios 应用程序,它将从麦克风接收到的声音传递到扬声器而不做任何更改。我已经阅读了苹果文档和指南。我从这个guide 中选择了第一个模式。但什么也没发生——沉默。如您所见,我尝试使用 AUAudioGraph(已评论)- 结果相同(在这个简单的示例中我是否需要它?)。
我在互联网上看到几个使用回调的例子,但我不想使用任何回调。有可能吗?
有什么建议吗? 感谢关注。
实际代码
#import "AudioController.h"
#import <AudioToolbox/AudioToolbox.h>
#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioServices.h>
#define kInputBus 1
#define kOutputBus 0
@interface AudioController ()
AudioComponentDescription desc;
AudioComponent component;
AudioUnit unit;
AudioStreamBasicDescription audioFormat;
double rate;
//AUGraph graph;
@end
@implementation AudioController
- (void) setUp
AVAudioSession *sess = [AVAudioSession sharedInstance];
NSError *error = nil;
rate = 44100.0;
[sess setPreferredSampleRate:rate error:&error];
[sess setCategory:AVAudioSessionCategoryPlayAndRecord error:&error];
[sess setActive:YES error:&error];
rate = [sess sampleRate];
if (error)
NSLog(@"%@", error);
NSLog(@"Init...");
[self createUnitDesc];
[self getComponent];
[self getAudioUnit];
[self enableIORec];
[self enableIOPb];
[self createFormat];
[self applyFormat];
OSStatus err = AudioUnitInitialize(unit);
if (noErr != err)
[self showStatus:err];
/*NewAUGraph(&graph);
AUNode node;
AUGraphAddNode(graph, &desc, &node);
AUGraphInitialize(graph);
AUGraphOpen(graph);*/
- (void) createUnitDesc
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_RemoteIO;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
- (void) getComponent
component = AudioComponentFindNext(NULL, &desc);
- (void) getAudioUnit
OSStatus res = AudioComponentInstanceNew(component, &unit);
if (noErr != res)
[self showStatus:res];
- (void) enableIORec
UInt32 flag = 1;
OSStatus err = AudioUnitSetProperty(unit,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Input,
kInputBus,
&flag,
sizeof(flag));
if (noErr != err)
[self showStatus:err];
- (void) enableIOPb
UInt32 flag = 1;
OSStatus err = AudioUnitSetProperty(unit,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Output,
kOutputBus,
&flag,
sizeof(flag));
if (noErr != err)
[self showStatus:err];
- (void) createFormat
// Describe format
audioFormat.mSampleRate = rate;//44100.00;
audioFormat.mFormatID = kAudioFormatLinearPCM;
audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
audioFormat.mFramesPerPacket = 1;
audioFormat.mChannelsPerFrame = 1;
audioFormat.mBitsPerChannel = 16;
audioFormat.mBytesPerPacket = 2;
audioFormat.mBytesPerFrame = 2;
- (void) applyFormat
OSStatus err = AudioUnitSetProperty(unit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
kInputBus,
&audioFormat,
sizeof(audioFormat));
if (noErr != err)
[self showStatus:err];
- (void) start
NSLog(@"starting");
OSStatus err = AudioOutputUnitStart(unit);
//AUGraphStart(graph);
if (noErr != err)
[self showStatus:err];
- (void) end
NSLog(@"ending");
OSStatus err = AudioOutputUnitStop(unit);
//AUGraphStop(graph);
if (noErr != err)
[self showStatus:err];
- (void) showStatus:(OSStatus) st
NSString *text = nil;
switch (st)
case kAudioUnitErr_CannotDoInCurrentContext: text = @"kAudioUnitErr_CannotDoInCurrentContext"; break;
case kAudioUnitErr_FailedInitialization: text = @"kAudioUnitErr_FailedInitialization"; break;
case kAudioUnitErr_FileNotSpecified: text = @"kAudioUnitErr_FileNotSpecified"; break;
case kAudioUnitErr_FormatNotSupported: text = @"kAudioUnitErr_FormatNotSupported"; break;
case kAudioUnitErr_IllegalInstrument: text = @"kAudioUnitErr_IllegalInstrument"; break;
case kAudioUnitErr_Initialized: text = @"kAudioUnitErr_Initialized"; break;
case kAudioUnitErr_InstrumentTypeNotFound: text = @"kAudioUnitErr_InstrumentTypeNotFound"; break;
case kAudioUnitErr_InvalidElement: text = @"kAudioUnitErr_InvalidElement"; break;
case kAudioUnitErr_InvalidFile: text = @"kAudioUnitErr_InvalidFile"; break;
case kAudioUnitErr_InvalidOfflineRender: text = @"kAudioUnitErr_InvalidOfflineRender"; break;
case kAudioUnitErr_InvalidParameter: text = @"kAudioUnitErr_InvalidParameter"; break;
case kAudioUnitErr_InvalidProperty: text = @"kAudioUnitErr_InvalidProperty"; break;
case kAudioUnitErr_InvalidPropertyValue: text = @"kAudioUnitErr_InvalidPropertyValue"; break;
case kAudioUnitErr_InvalidScope: text = @"kAudioUnitErr_InvalidScope"; break;
case kAudioUnitErr_NoConnection: text = @"kAudioUnitErr_NoConnection"; break;
case kAudioUnitErr_PropertyNotInUse: text = @"kAudioUnitErr_PropertyNotInUse"; break;
case kAudioUnitErr_PropertyNotWritable: text = @"kAudioUnitErr_PropertyNotWritable"; break;
case kAudioUnitErr_TooManyFramesToProcess: text = @"kAudioUnitErr_TooManyFramesToProcess"; break;
case kAudioUnitErr_Unauthorized: text = @"kAudioUnitErr_Unauthorized"; break;
case kAudioUnitErr_Uninitialized: text = @"kAudioUnitErr_Uninitialized"; break;
case kAudioUnitErr_UnknownFileType: text = @"kAudioUnitErr_UnknownFileType"; break;
default: text = @"unknown error";
NSLog(@"TRANSLATED_ERROR = %li = %@", st, text);
- (void) dealloc
AudioUnitUninitialize(unit);
[super dealloc];
@end
【问题讨论】:
看起来你做的一切都非常正确。但是,我看不到您实际将输入范围的输出元素连接到输出范围的输入元素的位置。 RemoteIO 单元的特殊之处在于它同时处理硬件输入和输出,但在实例化该单元时它们并没有隐式连接。 hmmm,您能否给我一个提示,我该如何实现它?你说的是AUAudioGraph吗?还是有其他方法可以在元素之间创建连接?谢谢。 谢谢,使用 AudioUnitConnection conn 完成; conn.destInputNumber = 0; conn.sourceAudioUnit = 单位; conn.sourceOutputNumber = 1; err = AudioUnitSetProperty(unit, kAudioUnitProperty_MakeConnection, kAudioUnitScope_Input, 0, &conn, sizeof(conn)); if (noErr != err) [self showStatus:err]; 【参考方案1】:正如 warrenm 所说,在远程 IO 元素之间建立连接会有所帮助。 所以在所有初始化完成后放置的代码:
AudioUnitConnection conn;
conn.destInputNumber = kOutputBus;
conn.sourceAudioUnit = unit;
conn.sourceOutputNumber = kInputBus;
err = AudioUnitSetProperty(unit, kAudioUnitProperty_MakeConnection, kAudioUnitScope_Input, kOutputBus, &conn, sizeof(conn));
if (noErr != err) [self showStatus:err];
更新 为了方便其他人使用该解决方案,我将在此处发布完整代码:
.h 文件
#import <Foundation/Foundation.h>
@interface AudioController : NSObject
- (void)setUp;
- (void)start;
- (void)end;
@end
.m 文件
#import "AudioController.h"
#import <AudioToolbox/AudioToolbox.h>
#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioServices.h>
#define kInputBus 1
#define kOutputBus 0
@interface AudioController ()
AudioComponentDescription desc;
AudioComponent component;
AudioUnit unit;
AudioStreamBasicDescription audioFormat;
double rate;
@end
@implementation AudioController
- (void)setUp
AVAudioSession *sess = [AVAudioSession sharedInstance];
NSError *error = nil;
rate = 44100.0;
[sess setPreferredSampleRate:rate error:&error];
[sess setCategory:AVAudioSessionCategoryPlayAndRecord error:&error];
[sess setActive:YES error:&error];
rate = [sess sampleRate];
if (error)
NSLog(@"%@", error);
NSLog(@"Initing");
[self createUnitDesc];
[self getComponent];
[self getAudioUnit];
[self enableIORec];
[self enableIOPb];
[self createFormat];
[self applyFormat];
OSStatus err = AudioUnitInitialize(unit);
if (noErr != err)
[self showStatus:err];
AudioUnitConnection conn;
conn.destInputNumber = 0;
conn.sourceAudioUnit = unit;
conn.sourceOutputNumber = 1;
err = AudioUnitSetProperty(unit, kAudioUnitProperty_MakeConnection, kAudioUnitScope_Input, 0, &conn, sizeof(conn));
if (noErr != err)
[self showStatus:err];
- (void)createUnitDesc
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_RemoteIO;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
- (void)getComponent
component = AudioComponentFindNext(NULL, &desc);
- (void)getAudioUnit
OSStatus res = AudioComponentInstanceNew(component, &unit);
if (noErr != res)
[self showStatus:res];
- (void)enableIORec
UInt32 flag = 1;
OSStatus err = AudioUnitSetProperty(unit,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Input,
kInputBus,
&flag,
sizeof(flag));
if (noErr != err)
[self showStatus:err];
- (void)enableIOPb
UInt32 flag = 1;
OSStatus err = AudioUnitSetProperty(unit,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Output,
kOutputBus,
&flag,
sizeof(flag));
if (noErr != err)
[self showStatus:err];
- (void)createFormat
// Describe format
audioFormat.mSampleRate = rate;
audioFormat.mFormatID = kAudioFormatLinearPCM;
audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
audioFormat.mFramesPerPacket = 1;
audioFormat.mChannelsPerFrame = 1;
audioFormat.mBitsPerChannel = 16;
audioFormat.mBytesPerPacket = 2;
audioFormat.mBytesPerFrame = 2;
- (void)applyFormat
OSStatus err = AudioUnitSetProperty(unit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
kInputBus,
&audioFormat,
sizeof(audioFormat));
if (noErr != err)
[self showStatus:err];
- (void)start
NSLog(@"starting");
OSStatus err = AudioOutputUnitStart(unit);
if (noErr != err)
[self showStatus:err];
- (void)end
NSLog(@"ending");
OSStatus err = AudioOutputUnitStop(unit);
if (noErr != err)
[self showStatus:err];
- (void)showStatus:(OSStatus)st
NSString *text = nil;
switch (st)
case kAudioUnitErr_CannotDoInCurrentContext: text = @"kAudioUnitErr_CannotDoInCurrentContext"; break;
case kAudioUnitErr_FailedInitialization: text = @"kAudioUnitErr_FailedInitialization"; break;
case kAudioUnitErr_FileNotSpecified: text = @"kAudioUnitErr_FileNotSpecified"; break;
case kAudioUnitErr_FormatNotSupported: text = @"kAudioUnitErr_FormatNotSupported"; break;
case kAudioUnitErr_IllegalInstrument: text = @"kAudioUnitErr_IllegalInstrument"; break;
case kAudioUnitErr_Initialized: text = @"kAudioUnitErr_Initialized"; break;
case kAudioUnitErr_InstrumentTypeNotFound: text = @"kAudioUnitErr_InstrumentTypeNotFound"; break;
case kAudioUnitErr_InvalidElement: text = @"kAudioUnitErr_InvalidElement"; break;
case kAudioUnitErr_InvalidFile: text = @"kAudioUnitErr_InvalidFile"; break;
case kAudioUnitErr_InvalidOfflineRender: text = @"kAudioUnitErr_InvalidOfflineRender"; break;
case kAudioUnitErr_InvalidParameter: text = @"kAudioUnitErr_InvalidParameter"; break;
case kAudioUnitErr_InvalidProperty: text = @"kAudioUnitErr_InvalidProperty"; break;
case kAudioUnitErr_InvalidPropertyValue: text = @"kAudioUnitErr_InvalidPropertyValue"; break;
case kAudioUnitErr_InvalidScope: text = @"kAudioUnitErr_InvalidScope"; break;
case kAudioUnitErr_NoConnection: text = @"kAudioUnitErr_NoConnection"; break;
case kAudioUnitErr_PropertyNotInUse: text = @"kAudioUnitErr_PropertyNotInUse"; break;
case kAudioUnitErr_PropertyNotWritable: text = @"kAudioUnitErr_PropertyNotWritable"; break;
case kAudioUnitErr_TooManyFramesToProcess: text = @"kAudioUnitErr_TooManyFramesToProcess"; break;
case kAudioUnitErr_Unauthorized: text = @"kAudioUnitErr_Unauthorized"; break;
case kAudioUnitErr_Uninitialized: text = @"kAudioUnitErr_Uninitialized"; break;
case kAudioUnitErr_UnknownFileType: text = @"kAudioUnitErr_UnknownFileType"; break;
default: text = @"unknown error";
NSLog(@"TRANSLATED_ERROR = %li = %@", st, text);
- (void)dealloc
AudioUnitUninitialize(unit);
[super dealloc];
@end
【讨论】:
您能否详细说明您是如何做到的?我无法让它工作 @Srikanth,请查看我发布的代码。首先需要创建AudioController
的对象,然后调用setUp
,然后通过调用start
和end
方法控制播放。
@Srikanth 创建两个按钮,即开始和停止,然后为开始按钮出口调用 start 方法,为停止按钮出口调用 end 方法。希望这会有所帮助。
很清晰的代码,谢谢,但是我这里没有看到回调记录函数以上是关于iOS AudioUnits 通过的主要内容,如果未能解决你的问题,请参考以下文章
如何从 AudioUnits C 函数调用 Objective-C 方法? (iOS)
从 Springboard 返回后导致通用跳过的 AudioUnits