Fix audio corruption after 2nd run by properly cleaning up audio state

This commit is contained in:
Cameron Gutman 2014-10-21 04:18:20 -04:00
parent d83ac48a73
commit b2236b5dad

View File

@ -86,6 +86,71 @@ void ArInit(void)
opusDecoder = opus_decoder_create(48000, 2, &err);
audioLock = [[NSLock alloc] init];
// Configure the audio session for our app
NSError *audioSessionError = nil;
AVAudioSession* audioSession = [AVAudioSession sharedInstance];
[audioSession setPreferredSampleRate:48000.0 error:&audioSessionError];
[audioSession setCategory: AVAudioSessionCategoryPlayback error: &audioSessionError];
[audioSession setPreferredOutputNumberOfChannels:2 error:&audioSessionError];
[audioSession setPreferredIOBufferDuration:0.005 error:&audioSessionError];
[audioSession setActive: YES error: &audioSessionError];
OSStatus status;
AudioComponentDescription audioDesc;
audioDesc.componentType = kAudioUnitType_Output;
audioDesc.componentSubType = kAudioUnitSubType_RemoteIO;
audioDesc.componentFlags = 0;
audioDesc.componentFlagsMask = 0;
audioDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
status = AudioComponentInstanceNew(AudioComponentFindNext(NULL, &audioDesc), &audioUnit);
if (status) {
NSLog(@"Unable to instantiate new AudioComponent: %d", (int32_t)status);
}
AudioStreamBasicDescription audioFormat = {0};
audioFormat.mSampleRate = 48000;
audioFormat.mBitsPerChannel = 16;
audioFormat.mFormatID = kAudioFormatLinearPCM;
audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
audioFormat.mChannelsPerFrame = 2;
audioFormat.mBytesPerFrame = audioFormat.mChannelsPerFrame * (audioFormat.mBitsPerChannel / 8);
audioFormat.mBytesPerPacket = audioFormat.mBytesPerFrame;
audioFormat.mFramesPerPacket = audioFormat.mBytesPerPacket / audioFormat.mBytesPerFrame;
audioFormat.mReserved = 0;
status = AudioUnitSetProperty(audioUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
OUTPUT_BUS,
&audioFormat,
sizeof(audioFormat));
if (status) {
NSLog(@"Unable to set audio unit to input: %d", (int32_t)status);
}
AURenderCallbackStruct callbackStruct = {0};
callbackStruct.inputProc = playbackCallback;
callbackStruct.inputProcRefCon = NULL;
status = AudioUnitSetProperty(audioUnit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input,
OUTPUT_BUS,
&callbackStruct,
sizeof(callbackStruct));
if (status) {
NSLog(@"Unable to set audio unit callback: %d", (int32_t)status);
}
status = AudioUnitInitialize(audioUnit);
if (status) {
NSLog(@"Unable to initialize audioUnit: %d", (int32_t)status);
}
}
void ArRelease(void)
@ -95,6 +160,15 @@ void ArRelease(void)
opusDecoder = NULL;
}
OSStatus status = AudioUnitUninitialize(audioUnit);
if (status) {
NSLog(@"Unable to uninitialize audioUnit: %d", (int32_t)status);
}
// Audio session is now inactive
AVAudioSession* audioSession = [AVAudioSession sharedInstance];
[audioSession setActive: YES error: nil];
// This is safe because we're guaranteed that nobody
// is touching this list now
struct AUDIO_BUFFER_QUEUE_ENTRY *entry;
@ -108,10 +182,18 @@ void ArRelease(void)
void ArStart(void)
{
OSStatus status = AudioOutputUnitStart(audioUnit);
if (status) {
NSLog(@"Unable to start audioUnit: %d", (int32_t)status);
}
}
void ArStop(void)
{
OSStatus status = AudioOutputUnitStop(audioUnit);
if (status) {
NSLog(@"Unable to stop audioUnit: %d", (int32_t)status);
}
}
void ArDecodeAndPlaySample(char* sampleData, int sampleLength)
@ -241,78 +323,6 @@ void ClDisplayTransientMessage(char* message)
_clCallbacks.displayMessage = ClDisplayMessage;
_clCallbacks.displayTransientMessage = ClDisplayTransientMessage;
// Configure the audio session for our app
NSError *audioSessionError = nil;
AVAudioSession* audioSession = [AVAudioSession sharedInstance];
[audioSession setPreferredSampleRate:48000.0 error:&audioSessionError];
[audioSession setCategory: AVAudioSessionCategoryPlayAndRecord error: &audioSessionError];
[audioSession setPreferredOutputNumberOfChannels:2 error:&audioSessionError];
[audioSession setPreferredIOBufferDuration:0.005 error:&audioSessionError];
[audioSession setActive: YES error: &audioSessionError];
OSStatus status;
AudioComponentDescription audioDesc;
audioDesc.componentType = kAudioUnitType_Output;
audioDesc.componentSubType = kAudioUnitSubType_RemoteIO;
audioDesc.componentFlags = 0;
audioDesc.componentFlagsMask = 0;
audioDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
status = AudioComponentInstanceNew(AudioComponentFindNext(NULL, &audioDesc), &audioUnit);
if (status) {
NSLog(@"Unable to instantiate new AudioComponent: %d", (int32_t)status);
}
AudioStreamBasicDescription audioFormat = {0};
audioFormat.mSampleRate = 48000;
audioFormat.mBitsPerChannel = 16;
audioFormat.mFormatID = kAudioFormatLinearPCM;
audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
audioFormat.mChannelsPerFrame = 2;
audioFormat.mBytesPerFrame = audioFormat.mChannelsPerFrame * (audioFormat.mBitsPerChannel / 8);
audioFormat.mBytesPerPacket = audioFormat.mBytesPerFrame;
audioFormat.mFramesPerPacket = audioFormat.mBytesPerPacket / audioFormat.mBytesPerFrame;
audioFormat.mReserved = 0;
status = AudioUnitSetProperty(audioUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
OUTPUT_BUS,
&audioFormat,
sizeof(audioFormat));
if (status) {
NSLog(@"Unable to set audio unit to input: %d", (int32_t)status);
}
AURenderCallbackStruct callbackStruct = {0};
callbackStruct.inputProc = playbackCallback;
callbackStruct.inputProcRefCon = NULL;
status = AudioUnitSetProperty(audioUnit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input,
OUTPUT_BUS,
&callbackStruct,
sizeof(callbackStruct));
if (status) {
NSLog(@"Unable to set audio unit callback: %d", (int32_t)status);
}
status = AudioUnitInitialize(audioUnit);
if (status) {
NSLog(@"Unable to initialize audioUnit: %d", (int32_t)status);
}
// We start here because it seems to need some warmup time
// before it starts accepting samples
status = AudioOutputUnitStart(audioUnit);
if (status) {
NSLog(@"Unable to start audioUnit: %d", (int32_t)status);
}
return self;
}