使用SDL来播放音频非常简单,只需要根据指定的参数开启音频设备,然后设置音频回调函数,在音频回调函数中,将数据写入到指定的buffer中即可。
对于音频播放来讲,是音频设备主动向我们要数据,而并非我们主动写入数据到音频设备,音频设备维护了一个数据缓冲区,会将数据存放在缓冲区中进行逐一播放,当缓冲区中有空位时,就会通过回调函数向我们要数据,当缓冲区中数据已经填满时,则不会回调。
开启音频设备
SDL_AudioSpec是对音频参数的组合,开启音频设备的时候需要传入一组期望的参数组合,开启成功后会返回一个真正开启的参数组合。
1 | SDL_AudioSpec wanted_spec, spec; |
回调函数
回调函数是在一个单独的线程中,第一个参数就是开启设备时设置的回调函数上下文。第二个参数就是需要写入的缓冲区,第三个参数是需要的数据字节大小。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27static void sdl_audio_callback(void *opaque, Uint8 *stream, int len) {
VideoState *is = opaque;
int audio_size, len1;
while (len > 0) {
// 计算还未读取的字节大小
len1 = is->audio_buf_size - is->audio_buf_index;
// 如果为读取的字节大小大于音频设备想要的大小,则使用音频设备想要的大小
if (len1 > len) len1 = len;
// 将audio_buf中的数据copy到stream中
if (!is->muted && is->audio_buf && is->audio_volume == SDL_MIX_MAXVOLUME)
memcpy(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1);
else {
memset(stream, 0, len1);
if (!is->muted && is->audio_buf)
SDL_MixAudioFormat(stream,
(uint8_t *)is->audio_buf + is->audio_buf_index,
AUDIO_S16SYS, len1, is->audio_volume);
}
// 减去已经传递给音频设备的buffer大小,如果剩下的还有,则再次读取传递
len -= len1;
// stream加上偏移量
stream += len1;
// 更新audio_buf的偏移量
is->audio_buf_index += len1;
}
}