音频图输出单元回调函数-无法读取数据
Callback function of output unit of audio graph - can't read data
我正在尝试将输入数据流捕获到音频图中的输出单元,以便将其写入文件。创建图形后,我已经为输出单元(默认输出)注册了一个输入回调函数:
AudioComponent comp = AudioComponentFindNext (NULL, &cd);
if (comp == NULL) {
printf ("can't get output unit");
exit (-1);
}
CheckError (AudioComponentInstanceNew(comp, &player->outputUnit),
"Couldn't open component for outputUnit"); // outputUnit is of type AudioUnit
// register render callback
AURenderCallbackStruct input;
input.inputProc = MyRenderProc;
input.inputProcRefCon = player;
CheckError(AudioUnitSetProperty(player->outputUnit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input,
0,
&input,
sizeof(input)),
"AudioUnitSetProperty failed");
// initialize unit
CheckError (AudioUnitInitialize(player->outputUnit),"Couldn't initialize output unit");
回调函数被调用,但是当我尝试从 ioData->mBuffers[0].mData 读取输入数据流时,我得到的只是零。这是回调函数:
OSStatus MyRenderProc(void *inRefCon, // PLAYER CODE
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList * ioData) {
int frame = 0;
Float32 leftFloat = 0;
Float32 rightFloat = 0;
NSNumber *leftNumber;
NSNumber *rightNumber;
for (frame = 0; frame < inNumberFrames; ++frame)
{
Float32 *data = (Float32*)ioData->mBuffers[0].mData;
leftFloat = (data)[frame];
leftNumber = [NSNumber numberWithDouble:leftFloat];
(data)[frame] = 0;
// copy to right channel too
data = (Float32*)ioData->mBuffers[1].mData;
rightFloat = (data)[frame];
rightNumber = [NSNumber numberWithDouble:(data)[frame]];
(data)[frame] = 0;
[leftData addObject:leftNumber];
[rightData addObject:rightNumber];
}
return noErr;
}
此外,如果我不将数据清零,我会在播放过程中听到噪音,这表明我误解了 mBuffers 的功能。我在这里做错了什么?
如果从AUGraph
捕获输入数据是任务,则代码的关键部分(或多或少)归结为这个最简单的单通道演示示例:
OSStatus MyRenderProc(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList * ioData)
{
Float32 buf [inNumberFrames]; //just for one channel!
MyMIDIPlayer *player = (MyMIDIPlayer *)inRefCon;
if (*ioActionFlags & kAudioUnitRenderAction_PostRender){
static int TEMP_kAudioUnitRenderAction_PostRenderError = (1 << 8);
if (!(*ioActionFlags & TEMP_kAudioUnitRenderAction_PostRenderError)){
Float32* data = (Float32 *)ioData->mBuffers[0].mData; //just for one channel!
memcpy(buf, data, inNumberFrames*sizeof(Float32));
//do something with buff - there are nice examples of ExtAudioFileWriteAsync()
}
}
return noErr;
}
在setupAUGraph()
中可以通过以下方式设置此回调:
void setupAUGraph(MyMIDIPlayer *player)
{
// the beginning follows the textbook example setup pattern
{… … …}
// this is the specific part
AURenderCallbackStruct input = {0};
input.inputProc = MyRenderProc;
input.inputProcRefCon = player->instrumentUnit;
CheckError(AudioUnitAddRenderNotify(player->instrumentUnit,
MyRenderProc,
&player),
"AudioUnitAddRenderNotify Failed");
// now initialize the graph (causes resources to be allocated)
CheckError(AUGraphInitialize(player->graph),
"AUGraphInitialize failed");
}
请注意渲染回调"taps" 仪器节点的输出和输出节点的输入之间的连接,捕获来自上游的内容。回调只是将 ioData
复制到其他可以保存的缓冲区中。据我所知,这是访问 ioData
的最简单方法,我知道它可以工作,而不会破坏 API.
另请注意,有非常有效的纯 C 方法可用于测试这是否适用于特定实现 - 回调中不需要 Objective-C 方法。在纯 C 实时回调中摆弄一些 NSArray
s、添加对象等会引入优先级问题的风险,这可能会在以后变得难以调试。 CoreAudio API 是用 plain-C 编写的,这是有原因的。在 Obj-C 运行时的核心,有很多事情不能在不冒故障风险的情况下在实时线程上发生(锁、内存管理等)。因此,在 实时线程 上远离 Obj-C 会更安全。
希望这可以帮助。
输出音频单元上的渲染回调不用于捕获输出数据。就是提供输出数据(sample mBuffers)供输出单元播放。
我正在尝试将输入数据流捕获到音频图中的输出单元,以便将其写入文件。创建图形后,我已经为输出单元(默认输出)注册了一个输入回调函数:
AudioComponent comp = AudioComponentFindNext (NULL, &cd);
if (comp == NULL) {
printf ("can't get output unit");
exit (-1);
}
CheckError (AudioComponentInstanceNew(comp, &player->outputUnit),
"Couldn't open component for outputUnit"); // outputUnit is of type AudioUnit
// register render callback
AURenderCallbackStruct input;
input.inputProc = MyRenderProc;
input.inputProcRefCon = player;
CheckError(AudioUnitSetProperty(player->outputUnit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input,
0,
&input,
sizeof(input)),
"AudioUnitSetProperty failed");
// initialize unit
CheckError (AudioUnitInitialize(player->outputUnit),"Couldn't initialize output unit");
回调函数被调用,但是当我尝试从 ioData->mBuffers[0].mData 读取输入数据流时,我得到的只是零。这是回调函数:
OSStatus MyRenderProc(void *inRefCon, // PLAYER CODE
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList * ioData) {
int frame = 0;
Float32 leftFloat = 0;
Float32 rightFloat = 0;
NSNumber *leftNumber;
NSNumber *rightNumber;
for (frame = 0; frame < inNumberFrames; ++frame)
{
Float32 *data = (Float32*)ioData->mBuffers[0].mData;
leftFloat = (data)[frame];
leftNumber = [NSNumber numberWithDouble:leftFloat];
(data)[frame] = 0;
// copy to right channel too
data = (Float32*)ioData->mBuffers[1].mData;
rightFloat = (data)[frame];
rightNumber = [NSNumber numberWithDouble:(data)[frame]];
(data)[frame] = 0;
[leftData addObject:leftNumber];
[rightData addObject:rightNumber];
}
return noErr;
}
此外,如果我不将数据清零,我会在播放过程中听到噪音,这表明我误解了 mBuffers 的功能。我在这里做错了什么?
如果从AUGraph
捕获输入数据是任务,则代码的关键部分(或多或少)归结为这个最简单的单通道演示示例:
OSStatus MyRenderProc(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList * ioData)
{
Float32 buf [inNumberFrames]; //just for one channel!
MyMIDIPlayer *player = (MyMIDIPlayer *)inRefCon;
if (*ioActionFlags & kAudioUnitRenderAction_PostRender){
static int TEMP_kAudioUnitRenderAction_PostRenderError = (1 << 8);
if (!(*ioActionFlags & TEMP_kAudioUnitRenderAction_PostRenderError)){
Float32* data = (Float32 *)ioData->mBuffers[0].mData; //just for one channel!
memcpy(buf, data, inNumberFrames*sizeof(Float32));
//do something with buff - there are nice examples of ExtAudioFileWriteAsync()
}
}
return noErr;
}
在setupAUGraph()
中可以通过以下方式设置此回调:
void setupAUGraph(MyMIDIPlayer *player)
{
// the beginning follows the textbook example setup pattern
{… … …}
// this is the specific part
AURenderCallbackStruct input = {0};
input.inputProc = MyRenderProc;
input.inputProcRefCon = player->instrumentUnit;
CheckError(AudioUnitAddRenderNotify(player->instrumentUnit,
MyRenderProc,
&player),
"AudioUnitAddRenderNotify Failed");
// now initialize the graph (causes resources to be allocated)
CheckError(AUGraphInitialize(player->graph),
"AUGraphInitialize failed");
}
请注意渲染回调"taps" 仪器节点的输出和输出节点的输入之间的连接,捕获来自上游的内容。回调只是将 ioData
复制到其他可以保存的缓冲区中。据我所知,这是访问 ioData
的最简单方法,我知道它可以工作,而不会破坏 API.
另请注意,有非常有效的纯 C 方法可用于测试这是否适用于特定实现 - 回调中不需要 Objective-C 方法。在纯 C 实时回调中摆弄一些 NSArray
s、添加对象等会引入优先级问题的风险,这可能会在以后变得难以调试。 CoreAudio API 是用 plain-C 编写的,这是有原因的。在 Obj-C 运行时的核心,有很多事情不能在不冒故障风险的情况下在实时线程上发生(锁、内存管理等)。因此,在 实时线程 上远离 Obj-C 会更安全。
希望这可以帮助。
输出音频单元上的渲染回调不用于捕获输出数据。就是提供输出数据(sample mBuffers)供输出单元播放。