Posts

Post not yet marked as solved
1 Replies
2.8k Views
Hi all:I'm working on audio unit record with remote i/o unit.When I use "Voice Memos" on iPad Pro with stereo mic, I can get L/R channel seperate stereo voice data,But when I try to use Audio Unit Remote I/O api to record , I got L/R mixed channel copy data. What am I missing?My Test code as follows:#define OutputElement 0 #define InputElement 1 AudioBufferList *buffList = nullptr; AudioComponentInstance audioUnit; ExtAudioFileRef mOutputAudioFile; ExtAudioFileRef mInputAudioFile; NSMutableData* outputData; NSMutableData* inputData; NSString* fourCharNSStringForFourCharCode(OSStatus aCode){ char fourChar[5] = {static_cast<char>((aCode >> 24) & 0xFF), static_cast<char>((aCode >> 16) & 0xFF), static_cast<char>((aCode >> 8) & 0xFF), static_cast<char>(aCode & 0xFF), 0}; NSString *fourCharString = [NSString stringWithCString:fourChar encoding:NSUTF8StringEncoding]; return fourCharString; } void checkStatus(OSStatus status){ NSLog(@"%@",fourCharNSStringForFourCharCode(status)); } static OSStatus RecordCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData); static OSStatus PlayCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData); @implementation SimpleAUImplement - (void)initAudioSession{ NSError *audioSessionError = nil; AVAudioSession *mysession = [AVAudioSession sharedInstance];//1 [mysession setActive:YES error:&audioSessionError];//4 [mysession setCategory:AVAudioSessionCategoryPlayAndRecord withOptions: AVAudioSessionCategoryOptionDefaultToSpeaker | AVAudioSessionCategoryOptionMixWithOthers | AVAudioSessionCategoryOptionAllowBluetooth | AVAudioSessionCategoryOptionAllowBluetoothA2DP error:&audioSessionError]; // Do any additional setup after loading the view. NSArray* avaribleInput = mysession.availableInputs; for (AVAudioSessionPortDescription *input in avaribleInput) { NSLog(@"input name %@, TypeName:%@",input.portName, input.portType); NSString *inputString = input.portType; /* input port types */ if ([inputString hasPrefix:AVAudioSessionPortLineIn]) { NSLog(@"AVAudioSessionPortLineIn"); } if ([inputString hasPrefix:AVAudioSessionPortBuiltInMic]) { NSLog(@"AVAudioSessionPortBuiltInMic"); } if ([inputString hasPrefix:AVAudioSessionPortHeadsetMic]) { NSLog(@"AVAudioSessionPortHeadsetMic"); [mysession setPreferredInput:input error:&audioSessionError]; NSLog(@"setPreferredInput to AVAudioSessionPortHeadsetMic"); } /* port types that refer to either input or output */ if ([inputString hasPrefix:AVAudioSessionPortBluetoothHFP]) { NSLog(@"AVAudioSessionPortBluetoothHFP"); } if ([inputString hasPrefix:AVAudioSessionPortUSBAudio]) { NSLog(@"AVAudioSessionPortUSBAudio"); } if ([inputString hasPrefix:AVAudioSessionPortCarAudio]) { NSLog(@"AVAudioSessionPortCarAudio"); } } NSArray* avaribleOutput = mysession.currentRoute.outputs; if(avaribleOutput.count <= 0){ NSLog(@"No Output source."); } for (AVAudioSessionPortDescription *output in avaribleOutput) { NSLog(@"output name %@, TypeName:%@",output.portName, output.portType); NSString *outputString = output.portType; /* output port types */ if ([outputString hasPrefix:AVAudioSessionPortLineOut]) { NSLog(@"AVAudioSessionPortLineOut"); } if ([outputString hasPrefix:AVAudioSessionPortHeadphones]) { NSLog(@"AVAudioSessionPortHeadphones"); } if ([outputString hasPrefix:AVAudioSessionPortBluetoothA2DP]) { NSLog(@"AVAudioSessionPortBluetoothA2DP"); } if ([outputString hasPrefix:AVAudioSessionPortBuiltInReceiver]) { NSLog(@"AVAudioSessionPortBuiltInReceiver"); } if ([outputString hasPrefix:AVAudioSessionPortBuiltInSpeaker]) { NSLog(@"AVAudioSessionPortBuiltInSpeaker"); } if ([outputString hasPrefix:AVAudioSessionPortHDMI]) { NSLog(@"AVAudioSessionPortHDMI"); } if ([outputString hasPrefix:AVAudioSessionPortAirPlay]) { NSLog(@"AVAudioSessionPortAirPlay"); } if ([outputString hasPrefix:AVAudioSessionPortBluetoothLE]) { NSLog(@"AVAudioSessionPortBluetoothLE"); } /* port types that refer to either input or output */ if ([outputString hasPrefix:AVAudioSessionPortBluetoothHFP]) { NSLog(@"AVAudioSessionPortBluetoothHFP"); } if ([outputString hasPrefix:AVAudioSessionPortUSBAudio]) { NSLog(@"AVAudioSessionPortUSBAudio"); } if ([outputString hasPrefix:AVAudioSessionPortCarAudio]) { NSLog(@"AVAudioSessionPortCarAudio"); } } } - (void)initBuffer { UInt32 flag = 0; AudioUnitSetProperty(audioUnit, kAudioUnitProperty_ShouldAllocateBuffer, kAudioUnitScope_Output, InputElement, &flag, sizeof(flag)); buffList = (AudioBufferList*)malloc(sizeof(AudioBufferList)); buffList->mNumberBuffers = 1; buffList->mBuffers[0].mNumberChannels = 1; buffList->mBuffers[0].mDataByteSize = 2048 * sizeof(short); buffList->mBuffers[0].mData = (short *)malloc(sizeof(short) * 2048); inputData = [[NSMutableData alloc] init]; outputData = [[NSMutableData alloc] init]; } - (void)writeDataToFile{ // Generate the file path NSString *documentsDirectory = [[SimpleAudioFileHelper sharedInstance] GetDefaultFilePath]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:@"input.caf"]; // Save it into file system [inputData writeToFile:dataPath atomically:YES]; }); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:@"output.caf"]; // Save it into file system [outputData writeToFile:dataPath atomically:YES]; }); } - (void)initAudioComponent { AudioComponentDescription audioDesc; audioDesc.componentType = kAudioUnitType_Output; audioDesc.componentSubType = kAudioUnitSubType_RemoteIO; audioDesc.componentManufacturer = kAudioUnitManufacturer_Apple; audioDesc.componentFlags = 0; audioDesc.componentFlagsMask = 0; AudioComponent inputComponent = AudioComponentFindNext(NULL, &audioDesc); AudioComponentInstanceNew(inputComponent, &audioUnit); } - (void)printASBD:(AudioStreamBasicDescription)asbd { char formatIDString[5]; UInt32 formatID = CFSwapInt32HostToBig (asbd.mFormatID); bcopy (&formatID, formatIDString, 4); formatIDString[4] = '\0'; NSLog (@" Sample Rate: %10.0f", asbd.mSampleRate); NSLog (@" Format ID: %10s", formatIDString); NSLog (@" Format Flags: %10X", (unsigned int)asbd.mFormatFlags); NSLog (@" Bytes per Packet: %10d", (unsigned int)asbd.mBytesPerPacket); NSLog (@" Frames per Packet: %10d", (unsigned int)asbd.mFramesPerPacket); NSLog (@" Bytes per Frame: %10d", (unsigned int)asbd.mBytesPerFrame); NSLog (@" Channels per Frame: %10d", (unsigned int)asbd.mChannelsPerFrame); NSLog (@" Bits per Channel: %10d", (unsigned int)asbd.mBitsPerChannel); } - (void)initFormat{ AudioStreamBasicDescription audioFormat; audioFormat.mSampleRate = 44100; audioFormat.mFormatID = kAudioFormatLinearPCM; audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; audioFormat.mFramesPerPacket = 1; audioFormat.mChannelsPerFrame = 2; audioFormat.mBitsPerChannel = 16; audioFormat.mBytesPerPacket = 4; audioFormat.mBytesPerFrame = 4; AudioUnitSetProperty(audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, InputElement, &audioFormat, sizeof(audioFormat)); AudioUnitSetProperty(audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, OutputElement, &audioFormat, sizeof(audioFormat)); AudioStreamBasicDescription dstFormat; dstFormat.mSampleRate = 44100.00; dstFormat.mFormatID = kAudioFormatLinearPCM; dstFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; dstFormat.mFramesPerPacket = 1; dstFormat.mChannelsPerFrame = 2; dstFormat.mBitsPerChannel = 16; dstFormat.mBytesPerPacket = 4; dstFormat.mBytesPerFrame = 4; dstFormat.mReserved = 0; // [[SimpleAudioFileHelper sharedInstance] InitAudioFileByFormat:&dstFormat FileName:@"inputData" AudioFile:mInputAudioFile]; // [[SimpleAudioFileHelper sharedInstance] InitAudioFileByFormat:&dstFormat FileName:@"outputData" AudioFile:mOutputAudioFile]; } - (void)initRecordeCallback { AURenderCallbackStruct recordCallback; recordCallback.inputProc = RecordCallback; recordCallback.inputProcRefCon = (__bridge void *)self; AudioUnitSetProperty(audioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, // kAudioUnitScope_Input, InputElement, // OutputElement, &recordCallback, sizeof(recordCallback)); } - (void)initPlayCallback { AURenderCallbackStruct playCallback; playCallback.inputProc = PlayCallback; playCallback.inputProcRefCon = (__bridge void *)self; AudioUnitSetProperty(audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, // kAudioUnitScope_Output, OutputElement, // InputElement, &playCallback, sizeof(playCallback)); } - (void)initAudioProperty { UInt32 flag = 1; AudioUnitSetProperty(audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, InputElement, &flag, sizeof(flag)); AudioUnitSetProperty(audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, OutputElement, &flag, sizeof(flag)); } - (void)InitRemoteIO{ AudioUnitInitialize(audioUnit); [self initAudioSession]; [self initBuffer]; [self initAudioComponent]; [self initFormat]; [self initAudioProperty]; [self initRecordeCallback]; [self initPlayCallback]; } - (void)Start{ OSStatus status = AudioOutputUnitStart(audioUnit); checkStatus(status); } - (void)Stop{ OSStatus status; status = AudioOutputUnitStop(audioUnit); checkStatus(status); [self writeDataToFile]; } - (void)Exit{ // AudioOutputUnitStop(audioUnit); AudioUnitUninitialize(audioUnit); AudioComponentInstanceDispose(audioUnit); if (buffList != NULL) { free(buffList); buffList = NULL; } } static OSStatus RecordCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) { AudioUnitRender(audioUnit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, buffList); [inputData appendBytes:buffList->mBuffers[0].mData length:buffList->mBuffers[0].mDataByteSize/sizeof(short)]; NSLog(@"RecordCallback size = %d inBusNumber:%d", buffList->mBuffers[0].mDataByteSize,inBusNumber); return noErr; } static OSStatus PlayCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) { NSLog(@"PlayCallback size2 = %d inBusNumber:%d, inNumberFrames:%d", buffList->mBuffers[0].mDataByteSize,inBusNumber,inNumberFrames); // memcpy(ioData->mBuffers[0].mData, buffList->mBuffers[0].mData, ioData->mBuffers[0].mDataByteSize); AudioUnitRender(audioUnit, ioActionFlags, inTimeStamp, 1, inNumberFrames, buffList); [outputData appendBytes:buffList->mBuffers[0].mData length:buffList->mBuffers[0].mDataByteSize/sizeof(short)]; return noErr; }
Posted
by vrhikaru.
Last updated
.