Tôi đang viết ứng dụng iOS lấy đầu vào từ micrô, chạy nó qua bộ lọc âm thanh bộ lọc cao và phát lại qua loa. Tôi đã có thể làm điều này thành công bằng cách sử dụng API AUGraph. Trong đó, tôi đặt hai nút: một đơn vị I/O từ xa và một đơn vị âm thanh có hiệu lực (kAudioUnitType_Effect
, kAudioUnitSubType_HighPassFilter
) và kết nối đầu ra của phần tử đầu vào của đơn vị io với đầu vào của đơn vị hiệu ứng và đầu ra của nút hiệu ứng tới đơn vị io phạm vi đầu vào của phần tử đầu ra. Nhưng bây giờ tôi có nhu cầu làm một số phân tích dựa trên các mẫu âm thanh được xử lý, vì vậy tôi cần truy cập trực tiếp vào bộ đệm. Điều này có nghĩa (và hãy sửa tôi nếu tôi sai) Tôi không còn có thể sử dụng AUGraphConnectNodeInput
để tạo kết nối giữa đầu ra của nút hiệu ứng và phần tử đầu ra của đơn vị io và phải đính kèm hàm gọi lại hiển thị cho phần tử đầu ra của đơn vị io, để tôi có thể truy cập bộ đệm bất cứ khi nào loa cần mẫu mới. Tôi đã làm như vậy, nhưng tôi nhận được lỗi -50 khi tôi gọi hàm AudioUnitRender
trong gọi lại hiển thị. Tôi tin rằng tôi có một trường hợp ASBD không phù hợp giữa hai đơn vị âm thanh, vì tôi không làm bất cứ điều gì về điều đó trong gọi lại hiển thị (và biểu đồ AUGraph đã xử lý nó trước đây). Dưới đây là các mã:Sự cố khi ghi I/O từ xa hiển thị chức năng gọi lại
AudioController.h:
@interface AudioController : NSObject
{
AUGraph mGraph;
AudioUnit mEffects;
AudioUnit ioUnit;
}
@property (readonly, nonatomic) AudioUnit mEffects;
@property (readonly, nonatomic) AudioUnit ioUnit;
-(void)initializeAUGraph;
-(void)startAUGraph;
-(void)stopAUGraph;
@end
AudioController.mm:
@implementation AudioController
…
static OSStatus renderInput(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData)
{
AudioController *THIS = (__bridge AudioController*)inRefCon;
AudioBuffer buffer;
AudioStreamBasicDescription fxOutputASBD;
UInt32 fxOutputASBDSize = sizeof(fxOutputASBD);
AudioUnitGetProperty([THIS mEffects], kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &fxOutputASBD, &fxOutputASBDSize);
buffer.mDataByteSize = inNumberFrames * fxOutputASBD.mBytesPerFrame;
buffer.mNumberChannels = fxOutputASBD.mChannelsPerFrame;
buffer.mData = malloc(buffer.mDataByteSize);
AudioBufferList bufferList;
bufferList.mNumberBuffers = 1;
bufferList.mBuffers[0] = buffer;
//TODO prender ARM y solucionar problema de memoria
OSStatus result = AudioUnitRender([THIS mEffects], ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, &bufferList);
[THIS hasError:result:__FILE__:__LINE__];
memcpy(ioData, buffer.mData, buffer.mDataByteSize);
return noErr;
}
- (void)initializeAUGraph
{
OSStatus result = noErr;
// create a new AUGraph
result = NewAUGraph(&mGraph);
AUNode outputNode;
AUNode effectsNode;
AudioComponentDescription effects_desc;
effects_desc.componentType = kAudioUnitType_Effect;
effects_desc.componentSubType = kAudioUnitSubType_LowPassFilter;
effects_desc.componentFlags = 0;
effects_desc.componentFlagsMask = 0;
effects_desc.componentManufacturer = kAudioUnitManufacturer_Apple;
AudioComponentDescription output_desc;
output_desc.componentType = kAudioUnitType_Output;
output_desc.componentSubType = kAudioUnitSubType_RemoteIO;
output_desc.componentFlags = 0;
output_desc.componentFlagsMask = 0;
output_desc.componentManufacturer = kAudioUnitManufacturer_Apple;
// Add nodes to the graph to hold the AudioUnits
result = AUGraphAddNode(mGraph, &output_desc, &outputNode);
[self hasError:result:__FILE__:__LINE__];
result = AUGraphAddNode(mGraph, &effects_desc, &effectsNode);
[self hasError:result:__FILE__:__LINE__];
// Connect the effect node's output to the output node's input
// This is no longer the case, as I need to access the buffer
// result = AUGraphConnectNodeInput(mGraph, effectsNode, 0, outputNode, 0);
[self hasError:result:__FILE__:__LINE__];
// Connect the output node's input scope's output to the effectsNode input
result = AUGraphConnectNodeInput(mGraph, outputNode, 1, effectsNode, 0);
[self hasError:result:__FILE__:__LINE__];
// open the graph AudioUnits
result = AUGraphOpen(mGraph);
[self hasError:result:__FILE__:__LINE__];
// Get a link to the effect AU
result = AUGraphNodeInfo(mGraph, effectsNode, NULL, &mEffects);
[self hasError:result:__FILE__:__LINE__];
// Same for io unit
result = AUGraphNodeInfo(mGraph, outputNode, NULL, &ioUnit);
[self hasError:result:__FILE__:__LINE__];
// Enable input on io unit
UInt32 flag = 1;
result = AudioUnitSetProperty(ioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &flag, sizeof(flag));
[self hasError:result:__FILE__:__LINE__];
// Setup render callback struct
AURenderCallbackStruct renderCallbackStruct;
renderCallbackStruct.inputProc = &renderInput;
renderCallbackStruct.inputProcRefCon = (__bridge void*)self;
// Set a callback for the specified node's specified input
result = AUGraphSetNodeInputCallback(mGraph, outputNode, 0, &renderCallbackStruct);
[self hasError:result:__FILE__:__LINE__];
// Get fx unit's input current stream format...
AudioStreamBasicDescription fxInputASBD;
UInt32 sizeOfASBD = sizeof(AudioStreamBasicDescription);
result = AudioUnitGetProperty(mEffects, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &fxInputASBD, &sizeOfASBD);
[self hasError:result:__FILE__:__LINE__];
// ...and set it on the io unit's input scope's output
result = AudioUnitSetProperty(ioUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
1,
&fxInputASBD,
sizeof(fxInputASBD));
[self hasError:result:__FILE__:__LINE__];
// Set fx unit's output sample rate, just in case
Float64 sampleRate = 44100.0;
result = AudioUnitSetProperty(mEffects,
kAudioUnitProperty_SampleRate,
kAudioUnitScope_Output,
0,
&sampleRate,
sizeof(sampleRate));
[self hasError:result:__FILE__:__LINE__];
// Once everything is set up call initialize to validate connections
result = AUGraphInitialize(mGraph);
[self hasError:result:__FILE__:__LINE__];
}
@end
Như tôi đã nói trước đây, tôi nhận được một lỗi -50 trên AudioUnitRender
cuộc gọi, và Tôi đang tìm kiếm ít hoặc không có tài liệu nào về nó.
Mọi trợ giúp sẽ được đánh giá cao.
Nhờ Tim Bolstad (http://timbolstad.com/2010/03/14/core-audio-getting-started/) để cung cấp hướng dẫn về điểm xuất phát tuyệt vời.