sdl作为一个强大的跨平台多媒体库,音频播放是线性连续的,调用相对简单,其后端是通过一个音频回调函数不断向音频设备输出buf,以下是所涉及的接口:
SDL_Init(SDL_INIT_AUDIO):初始化音频设备。
SDL_OpenAudio(SDL_AudioSpec * desired, SDL_AudioSpec * obtained):这个函数用于设置音频设备的参数,并准备音频设备以便进行音频播放。
desired:这是一个指向 SDL_AudioSpec 结构体的指针,该结构体包含了开发者希望的音频设备参数。这些参数包括音频的采样率、音频格式、通道数、缓冲区大小等。
obtained:这也是一个指向 SDL_AudioSpec 结构体的指针,但是它是用于输出实际获得的音频设备参数的。当 SDL_OpenAudio() 成功返回后,这个结构体将被填充为音频设备实际支持的参数。
SDL_PauseAudio(0):用于暂停或恢复音频播放。
SDL_CloseAudio():关闭音频子系统。
SDL_Quit():完全退出 SDL 库。
其中,比较重要的是desired中参数的配置和回调函数的实现:
SDL_AudioSpec spec;
spec.freq; //音频一秒采样率
spec.channels; //音频通道数
spec.format; //音频样本类型
spec.silence; //静音
spec.samples; //缓冲区大小
spec.callback; //回调函数
spec.userdata; //传入回调函数的数据
sdl中的音频回调函数接口声明是固定,我们可以自己实现函数内部,只要将播放的音频数据赋值给stream即可,以下是一个简易的音频回调函数实现:
void AudioPlayer::Callback(void* userdata,unsigned char* stream, int len)
{
SDL_memset(stream, 0, len);
//userdata转成ifstream便于数据传输
auto ifs = (ifstream*)userdata;
ifs->read((char*)stream, len);
if (ifs->gcount() <= 0)
{
SDL_PauseAudio(1);
}
cout << "CallBack" << endl;
}
以下是一个简单的dome:
#include<iostream>
#include<fstream>
extern"C"
{
#include<SDL.h>
}
#pragma comment(lib,"SDL2.lib")
using namespace std;
void CallBack(void* userdata, Uint8* stream, int len);
#undef main
int main()
{
ifstream ifs("48000_2_s16le.pcm",ios::binary);
if (!ifs)
{
return -1;
}
if (SDL_Init(SDL_INIT_AUDIO) < 0)
{
return -1;
}
SDL_AudioSpec spec;
spec.freq = 48000; //一秒的采样率
spec.channels = 2; //通道数,双声道
spec.samples = 1024; //设置缓冲区大小为 1024 个音频帧
spec.format = AUDIO_S16SYS; //系统原生的 16 位音频格式
spec.silence = 0; //不静音
spec.userdata =&ifs; //将文件句柄传入回调函数,便于取数据
spec.callback = CallBack; //音频回调函数
if (SDL_OpenAudio(&spec, nullptr) < 0)
{
return -1;
}
//播放音频
SDL_PauseAudio(0);
//阻塞等音频播放完
getchar();
SDL_CloseAudio();
ifs.close();
return 0;
}
void CallBack(void* userdata, Uint8* stream,int len)
{
SDL_memset(stream, 0, len);
//userdata转成ifstream便于数据传输
auto ifs = (ifstream*)userdata;
ifs->read((char*)stream, len);
if (ifs->gcount() <= 0)
{
SDL_PauseAudio(1);
}
cout << "CallBack" << endl;
}
喜欢的朋友可以给个赞和关注,谢谢!