alexbw / novocaine

Painless high-performance audio on iOS and Mac OS X
http://alexbw.github.com/novocaine/
MIT License
2.23k stars 274 forks source link

inputblock + outputblock + forceOutputToSpeaker = Error: Couldn't render the output unit (-50) #119

Closed nickwah closed 8 years ago

nickwah commented 8 years ago

On my iphone 6s (ios 9.1), if I have an input block, an output block, and set forceOutputToSpeaker, then this call fails the second time it's called with the generic error -50:

    CheckError( AudioUnitRender(sm.inputUnit, ioActionFlags, inTimeStamp, inOutputBusNumber, inNumberFrames, sm.inputBuffer), "Couldn't render the output unit");

Here's my test code that reproduces it consistently:

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    Novocaine *audioManager = [Novocaine audioManager];

    __block float magnitude = 0.0;
    [audioManager setInputBlock:^(float *data, UInt32 numFrames, UInt32 numChannels, CMTime pts)
     {
         vDSP_rmsqv(data, 1, &magnitude, numFrames*numChannels);
     }];

    __block float frequency = 100.0;
    __block float phase = 0.0;
    [audioManager setOutputBlock:^(float *data, UInt32 numFrames, UInt32 numChannels)
     {

         printf("Magnitude: %f\n", magnitude);
         float samplingRate = audioManager.samplingRate;
         for (int i=0; i < numFrames; ++i)
         {
             for (int iChannel = 0; iChannel < numChannels; ++iChannel)
             {
                 float theta = phase * M_PI * 2;
                 data[i*numChannels + iChannel] = magnitude*sin(theta);
             }
             phase += 1.0 / (samplingRate / (frequency));
             if (phase > 1.0) phase = -1;
         }
     }];
    audioManager.forceOutputToSpeaker = YES;
    [audioManager play];
}

log is:

2015-11-01 00:27:30.542 NWMicrophone[2995:1484767] AudioRoute: Speaker
2015-11-01 00:27:30.544 NWMicrophone[2995:1484767] Input available? 1
2015-11-01 00:27:30.679 NWMicrophone[2995:1484767] AudioRoute: ReceiverAndMicrophone
2015-11-01 00:27:30.681 NWMicrophone[2995:1484767] Input available? 1
2015-11-01 00:27:30.683 NWMicrophone[2995:1484767] We've got 1 input channels
2015-11-01 00:27:30.684 NWMicrophone[2995:1484767] We've got 1 output channels
2015-11-01 00:27:30.685 NWMicrophone[2995:1484767] Current sampling rate: 44100.000000
Not interleaved!
Magnitude: 0.017199
Error: Couldn't render the output unit (-50)

Similarly, if I set the audiosession route myself before creating the novocaine instance, I run into the same problem.

    NSError *error;
    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:&error];
    [[AVAudioSession sharedInstance] overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:&error];
    Novocaine *audioManager = [Novocaine audioManager];
    // ... same blocks as before
    [audioManager play];
nickwah commented 8 years ago

For anyone who runs into this, the fix was to update the sample rate to 48000.