本文主要的目的在于讲解SDL2库常用的函数库以及讲述在项目中遇到的使用SDL,将记录SDL的初始化以及如何使用SDL开启渲染音频和关闭。
一、SDL播放音频使用步骤及函数说明
(1)SDL初始化:
int SDLCALL SDL_Init(Uint32 flags)
说明:该函数是用于激活需要激活的子系统的初始化函数,其中该SDL的子系统有很多例如音频和视频等子系统,传入的参数具有如下,常用的有 SDL_INIT_AUDIO和SDL_INIT_VIDEO :
#define SDL_INIT_TIMER 0x00000001
#define SDL_INIT_AUDIO 0x00000010
#define SDL_INIT_VIDEO 0x00000020
#define SDL_INIT_JOYSTICK 0x00000200
#define SDL_INIT_HAPTIC 0x00001000
#define SDL_INIT_GAMECONTROLLER 0x00002000
#define SDL_INIT_EVENTS 0x00004000
#define SDL_INIT_NOPARACHUTE 0x00100000
#define SDL_INIT_EVERYTHING ( \
SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_VIDEO | SDL_INIT_EVENTS | \
SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER \
)
(2)打开设备函数:
int SDLCALL SDL_OpenAudio(SDL_AudioSpec * desired,SDL_AudioSpec * obtained);
说明:这个函数是用于打开设备使用的,以及通过SDL_AudioSpec * desired传入所需要的参数,如下为该结构体的定义,包括了音频的格式(SDL_AudioFormat format)、音频的通道数(Uint8 channels)以及比较重要的回调函数指针(SDL_AudioCallback callback)等:
typedef struct SDL_AudioSpec
{
int freq; /**< DSP frequency -- samples per second */
SDL_AudioFormat format; /**< Audio data format */
Uint8 channels; /**< Number of channels: 1 mono, 2 stereo */
Uint8 silence; /**< Audio buffer silence value (calculated) */
Uint16 samples; /**< Audio buffer size in samples (power of 2) */
Uint16 padding; /**< Necessary for some compile environments */
Uint32 size; /**< Audio buffer size in bytes (calculated) */
SDL_AudioCallback callback;
void *userdata;
} SDL_AudioSpec;
(3)启停音频设备函数:
void SDLCALL SDL_PauseAudio(int pause_on);
说明:在使用 SDL_OpenAudio()函数后,应该需要使用SDL_PauseAudio(0)函数且传入参数0来使SDL调用回调函数来播放音频;若传入的是大于0的值此时将暂停音频播放设备,期间将传入静音数据。
(4)对音频数据进行混音函数
void SDLCALL SDL_MixAudio(Uint8 * dst, const Uint8 * src,Uint32 len, int volume);
说明:这是一个混音函数,可以将两段音频进行混音播放。
三、关闭函数特别说明:
因为当使用了SDL_OpenAudio()函数后,回调函数就会以线程的方式启动的,同时如果当需要关闭SDL音频设备时 ,仅仅使用SDL_CloseAudio()时不够的,下次如果再次使用SDL_OpenAudio()会报错,此时还需要进行一个操作就是需要停止掉回调线程,本文使用了一个参数int is_stop_sdl_audio_player = false;来控制线程的启停。
如下为回调函数对该参数的判断,和退出情况,当is_stop_sdl_audio_player为true时结束线程,完成关闭SDL全部操作。
…..
if (is_stop_sdl_audio_player == true)
{
//is_stop_sdl_audio_player = false;//清零
xhlog("exit fillaudio\n");
return ;
}
…..
四、代码展示
(1)SDL初始化函数
extern int audio_sample_rate;//rtmp中获取得到的音频采样频率,默认是44.1khz
int SDL_INIT_PLAYER(void)
{
//Init
int ret = 0;
if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_TIMER| SDL_INIT_VIDEO ))
{
//printf("Could not initialize SDL - %s\n", SDL_GetError());
xhlog("Could not initialize SDL - %s\n", SDL_GetError());
return -1;
}
//SDL_AudioSpec
SDL_AudioSpec wanted_spec;
//wanted_spec.freq = 44100;
wanted_spec.freq = audio_sample_rate;
wanted_spec.format = AUDIO_S16SYS;
wanted_spec.channels = 2;
wanted_spec.silence = 0;
wanted_spec.samples = 1024;//1024;
wanted_spec.callback = fill_audio;
if (SDL_OpenAudio(&wanted_spec, NULL)<0) {
//printf("can't open audio.\n");
xhlog("can't open audio.\n");
return -1;
}
SDL_PauseAudio(0);
is_stop_sdl_audio_player = false;
return 0;
}
(2)填充数据播放
/*函数名称:SDL_START_PLAYER
*函数功能:使用SDL播放PCM,使用线程来播放
*传入参数:unsigned char *data_pcm:pcm的数据指针;
* int len_data_pcm:pcm数据的长度
*函数返回值:成功返回0,失败返回-1;
*函数作者:吴豪乐
*日期:2020年7月29日
*/
#if 0
int SDL_START_PLAYER(unsigned char *data_pcm, int len_data_pcm)
#endif
DWORD WINAPI SDL_START_PLAYER(LPVOID lpParam)
{
audio_chunk = (Uint8 *)lpParam;
if (audio_chunk == NULL)
{
xhlog("audio audio_chunk is NULL\n");
return -1;
}
//SDL_LockAudio();
audio_pos = audio_chunk;
int pcm_buffer_size = 4096;
//Audio buffer length
audio_len = pcm_buffer_size;
while (audio_len > 0)//Wait until finish
{
SDL_Delay(1);
}
return 0;
}
(3)循环读取数据线程函数
/* Audio Callback
* The audio function callback takes the following parameters:
* stream: A pointer to the audio buffer to be filled
* len: The length (in bytes) of the audio buffer
*
*/
int is_stop_sdl_audio_player = false;
void fill_audio(void *udata,Uint8 *stream,int len){
int count_played = 0;//已经播放了数据大小
if (is_stop_sdl_audio_player == true)
{
//is_stop_sdl_audio_player = false;//清零
xhlog("exit fillaudio\n");
return ;
}
if (len == 4096 && audio_len == 0)
{
//xhlog("temp:%d\n", temp);
//if(temp == 4096)
//audio_len = len;
SDL_memset(stream, 0, temp);
//return;//这一句测试一下是否导致噪点,检测后发现这个return注释掉会噪点少很多
}
pcm_ptr_save = pcm_ptr;
pcm_ptr = audio_pos;
while (len > 0 && audio_len > 0)
{
SDL_memset(stream, 0, audio_len);
if (audio_len == 0)
{
continue;
}
temp = (len > audio_len ? audio_len : len);
//SDL_MIX_MAXVOLUME
SDL_MixAudio(stream, audio_pos, temp, SDL_MIX_MAXVOLUME);
audio_pos += temp;
audio_len -= temp;
stream += temp;
len -= temp;
}
}
(4)停止播放函数
/*函数名称:SDL_STOP_PLAYER
*函数功能:停止SDL播放PCM,关闭线程来播放
*传入参数:无
*函数返回值:成功返回0,失败返回-1;
*函数作者:吴豪乐
*日期:2020年11月27日
*/
void SDL_STOP_PLAYER(void)
{
printf("stop audioplayer\n");
is_stop_sdl_audio_player = true;
SDL_CloseAudio();
}
每写一篇文章都不容易,尊重别人的知识产权才是对自己和技术的尊重。为了避免发生知识产权被侵权的情况,我决定做出以下声明:
1.博客中标注原创的文章,版权归原作者 吴豪乐工作室 所有;
2.未经原作者允许不得转载本文内容,否则将视为侵权;
3.转载或者引用本文内容请注明来源及原作者;
4.对于不遵守此声明或者其他违法使用本文内容者,本人依法保留追究权等。