SDL播放PCM音频文件—拉方式(pull)
2023-11-27 00:40:48
前言
在前几篇文章中,我们已经学习了如何使用SDL播放YUV视频文件。接下来,我们将学习如何使用SDL播放PCM音频文件。SDL播放音频文件有两种方法,可以理解为推(push)和拉(pull)两种模式。推就是我们主动向设备缓冲区填充Buffer,而拉就是由设备拉取Buffer。
推模式
推模式是通过调用SDL_QueueAudio()函数来实现的。SDL_QueueAudio()函数会把一段音频数据复制到SDL的音频缓冲区中。当缓冲区满了之后,SDL就会开始播放音频数据。推模式的优点是简单易用,但缺点是容易造成音频数据的丢失。
拉模式
拉模式是通过调用SDL_LockAudioDevice()和SDL_UnlockAudioDevice()函数来实现的。SDL_LockAudioDevice()函数会锁定SDL的音频缓冲区,SDL_UnlockAudioDevice()函数会解锁SDL的音频缓冲区。在锁定音频缓冲区之后,我们就可以往缓冲区中填充音频数据了。当缓冲区满了之后,SDL就会开始播放音频数据。拉模式的优点是能够避免音频数据的丢失,但缺点是比较复杂。
SDL相关函数和结构体介绍
在使用SDL播放PCM音频文件之前,我们需要先了解一下SDL的相关函数和结构体。
SDL_AudioSpec结构体
SDL_AudioSpec结构体用于音频格式和参数。SDL_AudioSpec结构体的定义如下:
typedef struct SDL_AudioSpec {
Uint16 freq; /**< sample rate in Hz */
Uint8 format; /**< audio data format */
Uint8 channels; /**< number of channels (1 mono, 2 stereo) */
Uint8 silence; /**< 'silence' value in 16-bit signed audio */
Uint32 samples; /**< sample size in bytes */
Uint32 padding; /**< non-audio data padding in bytes */
Uint32 size; /**< total size in bytes */
SDL_AudioCallback callback; /**< callback function called when buffer needs filling */
void *userdata; /**< passed as argument to callback */
} SDL_AudioSpec;
其中,freq表示采样率,format表示音频数据格式,channels表示声道数,silence表示静音值,samples表示采样大小(以字节为单位),padding表示非音频数据填充(以字节为单位),size表示总大小(以字节为单位),callback表示当缓冲区需要填充时调用的回调函数,userdata表示传递给回调函数的参数。
SDL_AudioDeviceID类型
SDL_AudioDeviceID类型表示音频设备的ID。SDL_AudioDeviceID类型的定义如下:
typedef Uint32 SDL_AudioDeviceID;
SDL_LockAudioDevice()函数
SDL_LockAudioDevice()函数用于锁定SDL的音频缓冲区。SDL_LockAudioDevice()函数的定义如下:
SDL_AudioDeviceID SDL_LockAudioDevice(SDL_AudioDeviceID devid);
其中,devid表示音频设备的ID。
SDL_UnlockAudioDevice()函数
SDL_UnlockAudioDevice()函数用于解锁SDL的音频缓冲区。SDL_UnlockAudioDevice()函数的定义如下:
void SDL_UnlockAudioDevice(SDL_AudioDeviceID devid);
其中,devid表示音频设备的ID。
SDL_GetAudioDeviceStatus()函数
SDL_GetAudioDeviceStatus()函数用于获取SDL音频设备的状态。SDL_GetAudioDeviceStatus()函数的定义如下:
SDL_AudioStatus SDL_GetAudioDeviceStatus(SDL_AudioDeviceID devid);
其中,devid表示音频设备的ID。
SDL播放PCM音频文件
现在,我们已经了解了SDL的相关函数和结构体,接下来就可以开始学习如何使用SDL播放PCM音频文件了。
步骤1:打开SDL
首先,我们需要打开SDL。SDL的打开方式如下:
SDL_Init(SDL_INIT_AUDIO);
步骤2:设置音频格式和参数
接下来,我们需要设置音频格式和参数。音频格式和参数可以通过SDL_AudioSpec结构体来设置。SDL_AudioSpec结构体的设置方法如下:
SDL_AudioSpec spec;
spec.freq = 44100;
spec.format = AUDIO_S16SYS;
spec.channels = 2;
spec.silence = 0;
spec.samples = 1024;
spec.padding = 0;
spec.size = 0;
spec.callback = NULL;
spec.userdata = NULL;
其中,freq表示采样率,format表示音频数据格式,channels表示声道数,silence表示静音值,samples表示采样大小(以字节为单位),padding表示非音频数据填充(以字节为单位),size表示总大小(以字节为单位),callback表示当缓冲区需要填充时调用的回调函数,userdata表示传递给回调函数的参数。
步骤3:打开音频设备
接下来,我们需要打开音频设备。音频设备的打开方式如下:
SDL_AudioDeviceID devid = SDL_OpenAudioDevice(NULL, 0, &spec, NULL, 0);
其中,第一个参数表示音频设备的名称,第二个参数表示音频设备的索引,第三个参数表示音频格式和参数,第四个参数表示回调函数,第五个参数表示传递给回调函数的参数。
步骤4:播放音频文件
接下来,我们可以开始播放音频文件了。音频文件的播放方式如下:
while (1) {
SDL_AudioStatus status = SDL_GetAudioDeviceStatus(devid);
if (status == SDL_AUDIO_PLAYING) {
// 填充音频数据
SDL_LockAudioDevice(devid);
// ...
SDL_UnlockAudioDevice(devid);
} else if (status == SDL_AUDIO_STOPPED) {
break;
}
}
其中,SDL_GetAudioDeviceStatus()函数用于获取SDL音频设备的状态,SDL_LockAudioDevice()函数用于锁定SDL的音频缓冲区,SDL_UnlockAudioDevice()函数用于解锁SDL的音频缓冲区。
步骤5:关闭音频设备
最后,我们需要关闭音频设备。音频设备的关闭方式如下:
SDL_CloseAudioDevice(devid);
总结
以上就是SDL播放PCM音频文件的方法。SDL播放音频文件有两种方法,可以理解成推(push)和拉(pull)两种模式。推就是我们主动向设备缓冲区填充Buffer,而拉就是由设备拉取Buffer。