【问题标题】:Portaudio Callback Function ExamplePortaudio 回调函数示例
【发布时间】:2014-11-28 03:11:10
【问题描述】:

我目前正在使用 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);

所以它以无符号字符(输出)形式返回数据,字节在大小变量中解码。 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*/

一个好的回调函数的例子会非常有用,但当然感谢任何帮助,

谢谢

【问题讨论】:

  • 您需要清楚从编解码器输出的数据的格式和通道数,以及 PortAudio 配置期望的数据格式和通道数。编解码器的输出是无符号字符吗?或者是其他东西?是立体声还是单声道?
  • 谢谢罗斯,我已经添加了缺失的部分。感谢您的帮助!
  • 我在解释中添加了缺失的部分,当然,不是我的程序;)。
  • 使用 lame 代替 mpg123 可能是更好的解码方案。

标签: c++ audio mp3 portaudio


【解决方案1】:

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

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

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

  • 流样本格式是 paFloat,即使如果源是 short,您可能应该只输出 paInt16。 scale 变量用于转换为 paFloat [-1,1] 的适当范围
  • 将 data_struct->data 保留为 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;
    }
    

【讨论】:

    猜你喜欢
    • 2014-04-21
    • 1970-01-01
    • 1970-01-01
    • 2018-10-07
    • 2016-03-23
    • 2016-01-03
    • 2015-04-23
    • 2023-04-05
    • 1970-01-01
    相关资源
    最近更新 更多