ubuntu18.04 / 麒麟 播放PCM音频文件,源码来源于网友文章再修改,仅测试用!
如果应用在产品上需要再优化。
/**
* 最简单的SDL2播放音频的例子(SDL2播放PCM)
* Simplest Audio Play SDL2 (SDL2 play PCM)
*
* 本程序使用SDL2播放PCM音频采样数据。SDL实际上是对底层绘图
* API(Direct3D,OpenGL)的封装,使用起来明显简单于直接调用底层
* API。
*
* 函数调用步骤如下:
*
* [初始化]
* SDL_Init(): 初始化SDL。
* SDL_OpenAudio(): 根据参数(存储于SDL_AudioSpec)打开音频设备。
* SDL_PauseAudio(): 播放音频数据。
*
* [循环播放数据]
* SDL_Delay(): 延时等待播放完成。
*
* This software plays PCM raw audio data using SDL2.
* SDL is a wrapper of low-level API (DirectSound).
* Use SDL is much easier than directly call these low-level API.
*
* The process is shown as follows:
*
* [Init]
* SDL_Init(): Init SDL.
* SDL_OpenAudio(): Opens the audio device with the desired
* parameters (In SDL_AudioSpec).
* SDL_PauseAudio(): Play Audio.
*
* [Loop to play data]
* SDL_Delay(): Wait for completetion of playback.
*/
// gcc pcm_demo.c -o pcm_demo -L../SDL2-2.0.14/build/.libs/ -lSDL2
#include <stdio.h>
#include <bits/types.h>
typedef __uint8_t uint8_t;
typedef __uint16_t uint16_t;
typedef __uint32_t uint32_t;
typedef __uint64_t uint64_t;
//extern "C" {
#include "../SDL2-2.0.14/include/SDL.h"
#include "../SDL2-2.0.14/include/SDL_audio.h"
//};
int32_t data_len = 0;//音频数据大小
uint8_t *pData = NULL;//指向音频数据的指针
/**回调函数(由系统调用)
* 函数声明:typedef void (SDLCALL * SDL_AudioCallback)
* (void *userdata, uint8_t * stream, int len);
* This function is called when the audio device needs more data.
*
* userdata: An application-specific parameter saved in the SDL_AudioSpec structure(SDL_AudioSpec结构中的用户自定义数据,一般情况下可以不用)
* stream: A pointer to the audio data buffer.(该指针指向需要填充的音频缓冲区)
* len: The length of that buffer in bytes.(音频缓冲区的大小,以字节为单位)
*
* Once the callback returns, the buffer will no longer be valid.
* Stereo samples are stored in a LRLRLR ordering.
*
* You can choose to avoid callbacks and use SDL_QueueAudio() instead, if
* you like. Just open your audio device with a NULL callback.
*/
void fill_audio(void *userdata, uint8_t *stream, int len)
{
//SDL2中必须首先使用SDL_memset()将stream中的数据设置为0
int stream_len = 0;
if (data_len <= 0) /* Only play if we have data left */
{
return;
}
if(data_len > len)
{
stream_len = len;
}
else
{
stream_len = data_len;
}
/* Mix as much data as possible */
SDL_memset(stream, 0, len);
/**
* 函数声明:extern DECLSPEC void SDLCALL
* SDL_MixAudio(uint8_t * dst, const uint8_t * src, Uint32 len, int volume);
* This takes two audio buffers of the playing audio format and mixes
* them, performing addition, volume adjustment, and overflow clipping.
* The volume ranges from 0 - 128, and should be set to ::SDL_MIX_MAXVOLUME
* for full audio volume. Note this does not change hardware volume.
* This is provided for convenience -- you can mix your own audio data.
*
* #define SDL_MIX_MAXVOLUME 128
*/
SDL_MixAudio(stream, pData, len, SDL_MIX_MAXVOLUME);
pData += stream_len;
data_len -= stream_len;
}
int main(int argc, char* argv[])
{
//初始化SDL
if (SDL_Init(SDL_INIT_AUDIO))
{
printf("Could not initialize SDL - %s\n", SDL_GetError());
return -1;
}
//SDL_AudioSpec初始化
SDL_AudioSpec wanted, have;
wanted.freq = 48000; //音频数据的采样率(常用的有48000,44100等)
wanted.format = AUDIO_S16SYS; //音频数据的格式 AUDIO_S16LSB
wanted.channels = 1; //声道数(例如单声道取值为1,立体声取值为2)
wanted.silence = 0; //设置静音的值
wanted.samples = 1024; //音频缓冲区中的采样个数(要求必须是2的n次方)
wanted.callback = fill_audio; //填充音频缓冲区的回调函数
//打开音频
if (SDL_OpenAudio(&wanted, NULL) < 0)
{
printf("%s\n", SDL_GetError());
goto clean;
}
FILE *fp_pcm = fopen(argv[1], "rb");
if (fp_pcm == NULL)
{
printf("cannot open file:%s\n", argv[1]);
goto clean;
}
int pcm_buffer_size = 8192;//每次读取4096字节的数据,同时也是音频帧大小
char *pcm_buffer = (char *)malloc(pcm_buffer_size);
//播放音频数据
SDL_PauseAudio(0);
while (1)
{
if(0 == data_len)
{
int ret = fread(pcm_buffer, 1, pcm_buffer_size, fp_pcm);
printf("playing %d Bytes data.\n", ret);
if(ret > 0)
{
pData = (uint8_t *)pcm_buffer;
//Audio buffer length
data_len = pcm_buffer_size;
}
else
{
break;
}
}
else
{
SDL_Delay(10);
}
}
free(pcm_buffer);
fclose(fp_pcm);
clean:
SDL_CloseAudio();
SDL_Quit();
printf("exit\n");
return 0;
}
1.编译SDL2-2.0.14:直接进入目录./configure, make -j4
2.编译demo:gcc方法在文件顶部。
3.运行demo:./demo test.pcm
关于No such audio device 错误,是因为sdl用了dsp驱动播放声音,不是期望的声卡驱动pulseaudio。
可以运行测试程序:SDL2-2.0.14/test中的 ./testaudioinfo
只显示有1,2,3,驱动(下图)
1.安装完libasound2-dev和 libpulse-dev后重启。
sudo apt-get install libasound2-dev
sudo apt-get install libpulse-dev
解决安装错误报依赖关系时可以用aptitude install代替apt-get install。
2. 再编译SDL库。
./configure
make -j4
make install
3.运行测试程序:./testaudioinfo
新增0:pulseaudio驱动。
4.问题解决。
这个错误还会表现为在终端上运行测试程序正常,在QT中运行又报No such audio device (猜测跟环境变量有关)
如:设置SDL_AUDIODRIVER=pulse。最终还是要安装上面的库才行。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)