问题
I am trying to write an iOS application that will pass the sound received from microphone to speaker without any changes. I've read apple docs and guides. I choosed the first pattern from this guide. But nothing happening - silence. As you can see I've tried to use the AUAudioGraph (commented) - same result (do I need it in this simple example at all?).
I saw few examples in the internet where callbacks are used, but I do not want use any. Is it possible?
Any suggestions? Thanks for attention.
The actual code
#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
回答1:
As warrenm said setting up a connection between Remote IO elements helped. So the code placed after all initialization done:
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]; }
UPDATE To make it easy to others to use the solution I will post full code here:
The .h file
#import <Foundation/Foundation.h>
@interface AudioController : NSObject
- (void)setUp;
- (void)start;
- (void)end;
@end
The .m file
#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
来源:https://stackoverflow.com/questions/13664087/ios-audiounits-pass-through