2

タイトルは、私が達成しようとしていることをほぼ要約しています。循環バッファが着信オーディオ データでいっぱいになっている間に、レンダー コールバック内で Michael Tyson の TPCircularBuffer を使用しようとしています。デバイスのスピーカーから聞こえるように、レンダリング コールバックから RemoteIO オーディオ ユニットの出力要素にオーディオを送信したいと考えています。

オーディオは、2048 フレームのパケットとして入ってくるインターリーブされたステレオ 16 ビットです。オーディオセッションを設定した方法は次のとおりです。

#define kInputBus 1
#define kOutputBus 0
NSError *err = nil;
NSTimeInterval ioBufferDuration = 46;
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthers error:&err];
[session setPreferredIOBufferDuration:ioBufferDuration error:&err];
[session setActive:YES error:&err];
AudioComponentDescription defaultOutputDescription;
defaultOutputDescription.componentType = kAudioUnitType_Output;
defaultOutputDescription.componentSubType = kAudioUnitSubType_RemoteIO;
defaultOutputDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
defaultOutputDescription.componentFlags = 0;
defaultOutputDescription.componentFlagsMask = 0;

AudioComponent defaultOutput = AudioComponentFindNext(NULL, &defaultOutputDescription);
NSAssert(defaultOutput, @"Can't find default output.");

AudioComponentInstanceNew(defaultOutput, &remoteIOUnit);
UInt32 flag = 0;

OSStatus status = AudioUnitSetProperty(remoteIOUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, kOutputBus, &flag, sizeof(flag));
size_t bytesPerSample = sizeof(AudioUnitSampleType);
AudioStreamBasicDescription streamFormat = {0};
streamFormat.mSampleRate = 44100.00;
streamFormat.mFormatID = kAudioFormatLinearPCM;
streamFormat.mFormatFlags = kAudioFormatFlagsCanonical;
streamFormat.mBytesPerPacket = bytesPerSample;
streamFormat.mFramesPerPacket = 1;
streamFormat.mBytesPerFrame = bytesPerSample;
streamFormat.mChannelsPerFrame = 2;
streamFormat.mBitsPerChannel = bytesPerSample * 8;
streamFormat.mReserved = 0;

status = AudioUnitSetProperty(remoteIOUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &streamFormat, sizeof(streamFormat));

AURenderCallbackStruct callbackStruct;
callbackStruct.inputProc = render;
callbackStruct.inputProcRefCon = self;
status = AudioUnitSetProperty(remoteIOUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, kOutputBus, &callbackStruct, sizeof(callbackStruct));

ここでは、オーディオ データが循環バッファーに読み込まれ、レンダー コールバックで使用されます。

#define kBufferLength 2048
-(void)loadBytes:(Byte *)byteArrPtr{
TPCircularBufferProduceBytes(&buffer, byteArrPtr, kBufferLength);
}

OSStatus render(
                void *inRefCon,
                AudioUnitRenderActionFlags *ioActionFlags,
                const AudioTimeStamp *inTimeStamp,
                UInt32 inBusNumber,
                UInt32 inNumberFrames,
                AudioBufferList *ioData)
{
AUDIOIO *audio = (__bridge AUDIOIO *)inRefCon;
AudioSampleType *outSample = (AudioSampleType *)ioData->mBuffers[0].mData;
//Zero outSample
memset(outSample, 0, kBufferLength);
int bytesToCopy = ioData->mBuffers[0].mDataByteSize;
SInt16 *targetBuffer = (SInt16 *)ioData->mBuffers[0].mData;
//Pull audio
int32_t availableBytes;
SInt16 *buffer = TPCircularBufferTail(&audio->buffer, &availableBytes);
memcpy(targetBuffer, buffer, MIN(bytesToCopy, availableBytes));
TPCircularBufferConsume(&audio->buffer, MIN(bytesToCopy, availableBytes));
return noErr;
}

スピーカーからオーディオが聞こえないため、このセットアップには問題がありますが、デバイスでテストしてもエラーは発生しません。私が知る限り、TPCircularBuffer は正しく読み込まれ、読み取られています。オーディオ セッションの設定については、Apple のドキュメントに従っています。次に AUGraph をセットアップしようと考えていますが、ここでやろうとしていることの解決策を誰かが提案できるかどうかを知りたいです。ありがとう!

4

3 に答える 3

0

あなたの問題の1つは使用にあると思いますstreamFormat.mBitsPerChannel = bytesPerSample * 8;

基本的に 4 バイトbytesPerSampleの beに割り当てます。sizeof(AudioUnitSampleType)

それでstreamFormat.mBytesPerPacket = bytesPerSample;OKです。しかし、割り当てstreamFormat.mBitsPerChannel = bytesPerSample * 8; は、サンプルあたり 16 ビットではなく、サンプルあたり 32 ビットが必要だと言っています。

AudioUnitSampleType に基づいてオーディオ形式を作成することはありません。これは、利用したい個人の形式とは関係がないためです。定義を作成して、次のようにします。

#define BITS_PER_CHANNEL 16
#define SAMPLE_RATE 44100.0
#define CHANNELS_PER_FRAME 2
#define BYTES_PER_FRAME CHANNELS_PER_FRAME * (BITS_PER_CHANNEL / 8)  //ie 4
#define FRAMES_PER_PACKET 1
#define BYTES_PER_PACKET FRAMES_PER_PACKET * BYTES_PER_FRAME




    streamFormat.mSampleRate = SAMPLE_RATE;  // 44100.0
    streamFormat.mBitsPerChannel = BITS_PER_CHANNEL; //16
    streamFormat.mChannelsPerFrame = CHANNELS_PER_FRAME; // 2
    streamFormat.mFramesPerPacket = FRAMES_PER_PACKET; //1
    streamFormat.mBytesPerFrame = BYTES_PER_FRAME; // 4 total,  2 for left ch,  2 for right ch

    streamFormat.mBytesPerPacket = BYTES_PER_PACKET;

    streamFormat.mReserved = 0;
    streamFormat.mFormatID = kAudioFormatLinearPCM;  // double check this also
    streamFormat.mFormatFlags = kAudioFormatFlagsCanonical;`

また、それぞれが実行された直後に err と status に設定された戻り値を確認する必要があります。次のようないくつかの呼び出しでエラーチェックを追加する必要があります

checkMyReturnValueToo = AudioComponentInstanceNew(defaultOutput, &remoteIOUnit);

また、バッファ期間の値が非常に高くなっています。あなたは46を持っていますが、それがどこから来たのかわかりません。つまり、オーディオ コールバックごとに 46 秒分のオーディオが必要です。通常、レイテンシの要件に応じて、1 秒未満が必要です。ほとんどの場合、iOS はそれほど高い値を使用しませんが、0.025 程度 (25ms) に設定してみてください。より速いレイテンシーが必要な場合は、値を下げてみてください。

于 2014-01-11T19:11:25.230 に答える
0

一見すると、すべてが正しく設定されているように見えます。ただし、呼び出しがAudioOutputUnitStart()ありません:

...
// returns an OSStatus indicating success / fail
AudioOutputUnitStart(remoteIOUnit);

// now your callback should be being called
...
于 2014-01-10T15:59:16.640 に答える