iPad 2 の iOS 5 の renderCallback で、RemoteIO ユニットから AAC に直接記録しようとしています。それが不可能であり、可能であるという矛盾する情報を見てきました (ここのコメントで)。私がそうしたいと思った理由は、PCM への録音は、たとえ後で AAC に変換されたとしても、どんな長さの録音でも非常に多くのディスク容量を必要とするからです。
私はあきらめる準備ができています。Google、SO、Core Audio book、Apple Core-Audio メーリング リストとフォーラムをかき集めて、エラーが発生しないところまで来ました。これは、シミュレータとデバイスの両方に当てはまります。
だから...誰かがこれを経験したことがあるなら、正しい方向に少しずつ動かしていただければ幸いです。セットアップは、RemoteIO が AUSamplers からの出力を再生し、正常に動作していることです。
以下のコードで私がやっていることは次のとおりです
AudioStreamBasicDescription
remoteIO ユニットのフォーマットを指定します。kAudioFormatLinearPCM
ExtAudioFileRef
クライアントのフォーマットをRemoteIOユニットから取得して指定RemoteID ユニットの renderCallback を指定する
renderCallback では、
kAudioUnitRenderAction_PostRender
フェーズにデータを書き込みます
前述のとおり、エラーは発生していません。結果のオーディオ ファイル サイズは、何かが書き込まれていることを示していますが、ファイルは再生できません。おそらく、フォーマットが台無しになっていますか?
とにかく、これは Core-Audio の闇の海に勇敢に立ち向かっている他の人へのボトルおよび/または「Be Here Dragons」フラグでの私のメッセージです。
//ファイルを再生しようとしたときに表示される不幸なメッセージ:
// remoteIO セットアップの一部
// Enable IO for recording
UInt32 flag = 1;
result = AudioUnitSetProperty(ioUnit,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Input,
kInputBus, // == 1
&flag,
sizeof(flag));
if (noErr != result) {[self printErrorMessage: @"Enable IO for recording" withStatus: result]; return;}
// Describe format - - - - - - - - - -
size_t bytesPerSample = sizeof (AudioUnitSampleType);
AudioStreamBasicDescription audioFormat;
memset(&audioFormat, 0, sizeof(audioFormat));
audioFormat.mSampleRate = 44100.00;
audioFormat.mFormatID = kAudioFormatLinearPCM;
audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
audioFormat.mFramesPerPacket = 1;
audioFormat.mChannelsPerFrame = 1;
audioFormat.mBitsPerChannel = 16;
audioFormat.mBytesPerPacket = 2;
audioFormat.mBytesPerFrame = 2;
result = AudioUnitSetProperty(ioUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
kInputBus, // == 1
&audioFormat,
sizeof(audioFormat));
result = AudioUnitSetProperty(ioUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
kOutputBus, // == 0
&audioFormat,
sizeof(audioFormat));
// ファイルを設定する関数 & rendercallback
- (void)startRecordingAAC
{
OSStatus result;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *recordFile = [documentsDirectory stringByAppendingPathComponent: @"audio.m4a"];
CFURLRef destinationURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
(__bridge CFStringRef)recordFile,
kCFURLPOSIXPathStyle,
false);
AudioStreamBasicDescription destinationFormat;
memset(&destinationFormat, 0, sizeof(destinationFormat));
destinationFormat.mChannelsPerFrame = 2;
destinationFormat.mFormatID = kAudioFormatMPEG4AAC;
UInt32 size = sizeof(destinationFormat);
result = AudioFormatGetProperty(kAudioFormatProperty_FormatInfo, 0, NULL, &size, &destinationFormat);
if(result) printf("AudioFormatGetProperty %ld \n", result);
result = ExtAudioFileCreateWithURL(destinationURL,
kAudioFileM4AType,
&destinationFormat,
NULL,
kAudioFileFlags_EraseFile,
&extAudioFileRef);
if(result) printf("ExtAudioFileCreateWithURL %ld \n", result);
AudioStreamBasicDescription clientFormat;
memset(&clientFormat, 0, sizeof(clientFormat));
result = AudioUnitGetProperty(ioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, & clientFormat, &size);
if(result) printf("AudioUnitGetProperty %ld \n", result);
result = ExtAudioFileSetProperty(extAudioFileRef,kExtAudioFileProperty_ClientDataFormat,sizeof(clientFormat),&clientFormat);
if(result) printf("ExtAudioFileSetProperty %ld \n", result);
result = ExtAudioFileWriteAsync(extAudioFileRef, 0, NULL);
if (result) {[self printErrorMessage: @"ExtAudioFileWriteAsync error" withStatus: result];}
result = AudioUnitAddRenderNotify(ioUnit, renderCallback, (__bridge void*)self);
if (result) {[self printErrorMessage: @"AudioUnitAddRenderNotify" withStatus: result];}
}
// そして最後に、rendercallback
static OSStatus renderCallback (void * inRefCon,
AudioUnitRenderActionFlags * ioActionFlags,
const AudioTimeStamp * inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList * ioData)
{
OSStatus result;
if (*ioActionFlags == kAudioUnitRenderAction_PostRender){
MusicPlayerController* THIS = (__bridge MusicPlayerController *)inRefCon;
result = ExtAudioFileWriteAsync(THIS->extAudioFileRef, inNumberFrames, ioData);
if(result) printf("ExtAudioFileWriteAsync %ld \n", result);
}
return noErr;
}