7

iPad 2 の iOS 5 の renderCallback で、RemoteIO ユニットから AAC に直接記録しようとしています。それが不可能であり、可能であるという矛盾する情報を見てきました (ここのコメントで)。私がそうしたいと思った理由は、PCM への録音は、たとえ後で AAC に変換されたとしても、どんな長さの録音でも非常に多くのディスク容量を必要とするからです。

私はあきらめる準備ができています。Google、SO、Core Audio book、Apple Core-Audio メーリング リストとフォーラムをかき集めて、エラーが発生しないところまで来ました。これは、シミュレータとデバイスの両方に当てはまります。

だから...誰かがこれを経験したことがあるなら、正しい方向に少しずつ動かしていただければ幸いです。セットアップは、RemoteIO が AUSamplers からの出力を再生し、正常に動作していることです。

以下のコードで私がやっていることは次のとおりです

  • AudioStreamBasicDescriptionremoteIO ユニットのフォーマットを指定します。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; 
}
4

3 に答える 3

15

だから私はついにこれを整理しました!うーん、なんという情報スカベンジャーハント。

とにかく、ExtAudioFile のドキュメントで見逃していた部分を次に示します (太字のテキストを参照)。私はこのプロパティを設定していませんでした。データは .m4a ファイルに書き込まれていましたが、再生時に読み取ることができませんでした。要約すると、私はたくさんの AUSamplers -> AUMixer -> RemoteIO を持っています。RemoteIO インスタンスのレンダリング コールバックは、圧縮された m4a 形式でデータをディスクに書き込みます。そのため、オンザフライで圧縮オーディオを生成できます (iOS 5/iPad 2)

かなり堅牢なようです-rendercallbackにいくつかのprintfステートメントがあり、書き込みは正常に機能しました。

わーい!

ExtAudioFileProperty_CodecManufacturer 拡張オーディオ ファイル オブジェクトが使用するコーデックのメーカー。値は読み取り/書き込みの UInt32 です。kExtAudioFileProperty_ClientDataFormat (page 20) プロパティを設定する前に、このプロパティを指定する必要があります。これにより、コーデックの作成がトリガーされます。iOS でこのプロパティを使用して、kAppleHardwareAudioCodecManufacturer または kAppleSoftwareAudioCodecManufacturer を指定して、ハードウェア エンコーダーまたはソフトウェア エンコーダーを選択します。Mac OS X v10.7 以降で利用できます。ExtendedAudioFile.h で宣言されています。

// specify codec
UInt32 codec = kAppleHardwareAudioCodecManufacturer;
size = sizeof(codec);
result = ExtAudioFileSetProperty(extAudioFileRef, 
                                 kExtAudioFileProperty_CodecManufacturer, 
                                 size, 
                                 &codec);

if(result) printf("ExtAudioFileSetProperty %ld \n", result);
于 2012-04-12T18:01:53.943 に答える
0

これには、出力オーディオ ファイル ID のコーデックを指定するだけではありません。

このスレッドによると、ExtAudioFileWrite to m4a/aac がデュアルコア デバイス (ipad 2、iphone 4s) で失敗する場合、たとえば、特定の iPhone モデル (4S) は、ハードウェア デコーダーで適切に再生されません。

4S での私の経験から、ハードウェア コーデックで AAC ファイルをエンコードしようとすると、a) 時々動作する、b) エラー -66567 (kExtAudioFileError_MaxPacketSizeUnknown) で失敗する、または c) いくつかのサンプルを書き出すと、追跡可能なエラーなしでハングする.

ソフトウェア コーデックは iPhone 4S で問題なく動作しますが、パフォーマンスは低下します。

編集: 一部の人は、ハードウェア コーデックが 44.1kHz のサンプル レートを好まないと主張しています。私はまだこれを確認していません。

于 2013-07-03T14:00:45.837 に答える