iOS AudioUnits pass through

audiounit, avaudiosession, core-audio, ios

Solution

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

Problem

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 ```

Original source