Portaudio回调函数示例

Portaudio Callback Function Example

本文关键字:函数 回调 Portaudio      更新时间:2023-10-16

我目前正在使用live555、mpg123和portaudio构建一个mp3流媒体/接收器,并刚刚开始流媒体、解码和播放mp3的概念。

我的问题是当我需要用portaudio播放声音时。我不知道如何编写一个回调函数来播放我解码的mp3。

这是我在某个地方找到并尝试过的回调函数,但它并没有给我带来好的结果(除了噪音和嗡嗡声)。

static int patestCallback( const void *inputBuffer, void *outputBuffer,
                           unsigned long framesPerBuffer,
                           const PaStreamCallbackTimeInfo* timeInfo,
                           PaStreamCallbackFlags statusFlags,
                           void *userData )
{
    /* Cast data passed through stream to our structure. */
    paTestData *data_struct = (paTestData*)userData; 
    float *out = (float*)outputBuffer;
    unsigned int i;
    (void) inputBuffer; /* Prevent unused variable warning. */
    for( i=0; i<framesPerBuffer; i++ )
    {
        if(data_struct->cursor < data_struct->num_frames)
        {
            out[i] = data_struct->data[data_struct->cursor];
            data_struct->cursor++;
        }
        else
        {
            out[i] = 0; // if you've used up all the data, just fill the rest with silence.
            //finished = paComplete;
        }
    }
    return 0;
}

回调函数接收一个结构,该结构包含无符号字符数组中的解码数据和解码的字节数:

typedef struct
{
    unsigned char* data;
    unsigned long cursor;
    unsigned long num_frames;
}
paTestData;

编解码器功能如下:

mpg123_decode(m,fBuffer,frameSize,out,OUTBUFF,&size);

因此,它以无符号字符(out)的形式返回数据,并在大小变量中解码字节。fBuffer是编码的数据,frameSize是编码的字节数。

我以与portaudio教程相同的方式配置了portaudio流:

err = Pa_OpenDefaultStream( &stream,
                                        0,          /* no input channels */
                                        2,          /* stereo output */
                                        paFloat32,  /* 32 bit floating point output */
                                        SAMPLE_RATE,
                                        paFramesPerBufferUnspecified,        /* frames per buffer, i.e. the number
                                                            of sample frames that PortAudio will
                                                            request from the callback. Many apps
                                                            may want to use
                                                            paFramesPerBufferUnspecified, which
                                                            tells PortAudio to pick the best,
                                                            possibly changing, buffer size.*/
                                        patestCallback, /* this is your callback function */
                                        &paData ); /*This is a pointer that will be passed to
                                                            your callback*/

一个好的回调函数的例子将非常有用,但当然任何帮助都是值得赞赏的,

感谢

我认为您可以非常确信mpg123_decode输出的实际音频数据格式不是无符号字符。很可能它是以这种方式声明为通用指针的。你应该研究一下实际的类型。它可能是你可以配置的。

我的第一个猜测是mpg123_decode的输出是立体声16位int(假设是立体声源)。如果是这种情况,下面的代码可能会起作用。

请注意,我对您的代码做了最小的更改,以使其正常工作。这不是一个如何做到这一点的好例子。我的代码问题:

  • 流样本格式是paFloat,尽管如果源是short,您可能只应该输出paInt16。scale变量用于转换为paFloat[-1,1]的正确范围
  • 讨厌的强制转换将您的data_struct->数据保持为char*,即使如果源代码是short,它可能应该是short*
  • 循环覆盖framesPerBuffer*2个样本(因为1帧是所有通道,我假设是立体声)。这并不能使代码变得非常清晰(查看其他PA示例,了解立体声通常是如何处理的)。

    static int patestCallback( const void *inputBuffer, void *outputBuffer,
                               unsigned long framesPerBuffer,
                               const PaStreamCallbackTimeInfo* timeInfo,
                               PaStreamCallbackFlags statusFlags,
                               void *userData )
    {
        /* Cast data passed through stream to our structure. */
        paTestData *data_struct = (paTestData*)userData; 
        float *out = (float*)outputBuffer;
        unsigned int i;
        (void) inputBuffer; /* Prevent unused variable warning. */
        static const float scale = 1./32768.;
        for( i=0; i<framesPerBuffer*2; i++ ) // source and dest are interleaved
        {
            if(data_struct->cursor < data_struct->num_frames)
            {
                out[i] = *((short*)(&data_struct->data[data_struct->cursor])) * scale;
                data_struct->cursor += sizeof(short);
            }
            else
            {
                out[i] = 0; // if you've used up all the data, just fill the rest with silence.
                //finished = paComplete;
            }
        }
        return 0;
    }