ubuntu / 麒麟 播放PCM音频文件

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。最终还是要安装上面的库才行。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值