Linux下使用SDL播放音频


考虑到跨平台,在Linux上播放音频我们一般都会使用SDL库来进行开发。这里就介绍一下如何在Linux下使用SDL库来进行音频应用的开发。

编译SDL

在编译SDL库之前先安装对应的依赖库,否则在使用SDL应用打开音频设备的时候会报no such audio device的错误。安装命令如下:

sudo apt-get install libasound2-dev libpulse-dev 

这里最好使用Ubuntu 16.04来进行开发,在使用一些国产操作系统的时候会报源找不到的错误不知道为啥。
SDL库源码文件的下载地址如下:
SDL下载地址

SDL编译命令如下:

#解压代码包
tar xvf SDL2-2.0.14.tar.gz
#安装修复
sudo apt --fix-broken install
#进入源码目录
cd SDL2-2.0.14/
#指定安装目录
./configure --prefix=$PWD/_install  
#清理
make clean
#安装
make && make install

安装完成之后在对应的目录下就会有相应的库文件和头文件了

项目集成SDL

将编译好的SDL库拷贝到对应的工程目录下进行使用,这里以一个QT项目为例说明一下在pro文件中如何调用SDL库

#包含对应的静态库
unix 
{
    
    
LIBS += -L$$PWD/3rd/SDL2/ -lSDL2
LIBS += -L$$PWD/3rd/SDL2/ -lSDL2main
}
#添加对应的依赖目录
INCLUDEPATH += $$PWD/3rd/SDL2
DEPENDPATH += $$PWD/3rd/SDL2

代码调用

在项目中导入了SDL库之后 我们就可以使用SDL库来进行开发使用了,这里介绍一下如何使用SDL库来播放WAV音频数据

#include "SDL2/SDL.h"

//音频数据
struct AudioData
{
    
    
    Uint8 *idx; //数据索引
    Uint32 len; //数据长度
};

//buf为数据 size为数据长度 uRepeat为重复次数 vol为音量(0~1)
void RaiseVolume(char* buf, int size, int uRepeat, double vol)
{
    
    
    if (!size)
    {
    
    
        return;
    }
    for (int i = 0; i < size; i += 2)
    {
    
    
        short wData;
        wData = MAKEWORD(buf[i], buf[i + 1]);
        long dwData = wData;
        for (int j = 0; j < uRepeat; j++)
        {
    
    
            dwData = dwData * vol;
            if (dwData < -0x8000)
            {
    
    
                dwData = -0x8000;
            }
            else if (dwData > 0x7FFF)
            {
    
    
                dwData = 0x7FFF;
            }
        }
        wData = LOWORD(dwData);
        buf[i] = LOBYTE(wData);
        buf[i + 1] = HIBYTE(wData);
    }
}

//全局音量控制
float gvolume = 1.0;

//音频输出的回调函数
void callbackfun(void *data, Uint8 *buffer, int buffer_len)
{
    
    
    //调用的时候清空数据
    SDL_memset(buffer, 0, buffer_len);
    AudioData *audio = (AudioData*)data;
    if( audio->len <= 0)
    {
    
    
        return;
    }
   
    Uint32 length = (Uint32)buffer_len;
    length = (length > audio->len ? audio->len : length);

    RaiseVolume((char*)(audio->idx), length, 1, gvolume);
    SDL_memcpy(buffer, audio->idx, length);

    audio->idx += length;
    audio->len -= length;

}

int main()
{
    
    
    SDL_Init(SDL_INIT_AUDIO);
    SDL_AudioSpec aud_wav_spec;
    Uint8 *wav_start;
    Uint32 wav_len;

    if(SDL_LoadWAV("/home/username/test.wav", &aud_wav_spec, &wav_start, &wav_len) == NULL)
    {
    
    
        std::cout << "load wav error";
        return;
    }

    AudioData audio;
    audio.idx = wav_start;
    audio.len = wav_len;
    aud_wav_spec.callback = callbackfun;
    aud_wav_spec.userdata = &audio;

    //查找设备 检查设备
    int num = SDL_GetNumAudioDevices(0);
    for (int i=0;i<num;i++)
    {
    
    
        const char* device_name = SDL_GetAudioDeviceName(i, 0);
        printf("play device:%s", device_name);
    }

    if (SDL_OpenAudio(&aud_wav_spec, nullptr)) {
    
    

        const char* error_msg = SDL_GetError();
        std::cout << "打开音频设备失败";
        SDL_FreeWAV(wav_start);
        SDL_Quit();
        return;
    }

    //启动设备
    SDL_PauseAudio(0);
    while(audio.len > 0)
    {
    
    
        SDL_Delay(300);
    }
    SDL_Delay(300);
    SDL_PauseAudio(1);
    SDL_CloseAudio();
    SDL_FreeWAV(wav_start);
    SDL_Quit();
}

要点说明

1.在音频回调函数中一定要调用SDL_memset(buffer, 0, buffer_len)清空缓存,否则在列表播放切换文件的时候会出现杂音。
2.在列表切换播放文件的时候一定要做延时操作 否则会出现文件结尾播放不完整的问题。

猜你喜欢

转载自blog.csdn.net/yang1fei2/article/details/128879431