簡體   English   中英

在附加到remoteio音頻單元輸入范圍的渲染回調中使用循環緩沖區中的音頻數據

[英]consuming audio data from circular buffer in a render callback attached to the input scope of a remoteio audio unit

標題幾乎總結了我要達到的目標。 我試圖在循環緩沖區中充滿傳入音頻數據的同時,在渲染回調中使用Michael Tyson的TPCircularBuffer。 我想將音頻從render回調發送到RemoteIO音頻單元的輸出元素,以便可以通過設備揚聲器聽到它。

音頻是交錯的立體聲16位,以2048幀的數據包的形式出現。 這是我設置音頻會話的方法:

#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,但我想看看是否有人可以為我在這里嘗試的工作提出解決方案。 謝謝!

對於立體聲(每幀2個通道),每幀的字節數和每個數據包的字節數必須是樣本大小(以字節為單位)的兩倍。 與每個通道的位數相同。

補充:如果availableBytes / yourFrameSize幾乎不總是比inNumberFrames大或大,那么您將不會得到連續的聲音。

乍一看,您似乎已經正確設置了所有內容。 但是,您缺少對AudioOutputUnitStart()的調用:

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

// now your callback should be being called
...

我相信您的問題是使用streamFormat.mBitsPerChannel = bytesPerSample * 8;

您將bytesPerSample分配為sizeof(AudioUnitSampleType) ,它實際上是4個字節。

所以streamFormat.mBytesPerPacket = bytesPerSample; 還可以 但是賦值streamFormat.mBitsPerChannel = bytesPerSample * 8; 就是說您希望每個樣本32位,而不是每個樣本16位。

我不會基於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和狀態的返回值。 您仍然需要在某些調用中添加錯誤檢查,例如

checkMyReturnValueToo = AudioComponentInstanceNew(defaultOutput, &remoteIOUnit);

您的緩沖持續時間也具有極高的價值。 你有46歲,我不確定那是哪里來的。 這意味着在每個音頻回調過程中,您需要46秒的音頻。 通常,您需要少於一秒鍾的時間,具體取決於您的延遲要求。 iOS很可能不會使用任何高電平,但您應嘗試將其設置為0.025左右(25毫秒)。 如果需要更快的延遲,可以嘗試降低它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM