[SimplePlayer] 5. 向音频设备输出音频
两种SDL音频输出方式
我们这里采用SDL来进行音频输出。SDL提供两种音频输出的方式:
- 如果在SDL_OpenAudio时不指定callback,那么可以调用SDL_QueueAudio主动地向音频输出设备输送音频。这种方式的实现中,SDL维护一个音频队列,并从该队列中提取音频数据输出到音频设备,用户只需要源源不断地向队列添加音频即可。如果用户无法提供所需的音频,那么音频设备会输出静音。
- 如果在SDL_OpenAudio时指定了callback,那么就是通过该callback函数向音频输出设备输送音频。这种方式的实现中,SDL会维护一个固定大小的缓冲区,并创建一个轮询调用callback函数的线程(SDL_RunAudio),该实现要求callback函数每次向该缓冲区输送固定长度的音频数据,然后将该缓冲区的音频数据输出到音频设备。如果用户无法提供所需数据,则应该通过callback提供静音数据(填充0)。
我们这里采用的是SDL传统的音频输出方式,即指定callback函数。
初始化
首先需要初始化SDL的音频子系统
1 | SDL_Init(SDL_INIT_AUDIO); |
设置音频输出的采样率、样本格式、声道、一帧的有多少个样本(每次输出一帧)、以及回调函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | SDL_AudioSpec wanted, obtained; memset(&wanted, 0, sizeof(wanted)); wanted.freq = DEF_SAMPLERATE; wanted.format = AUDIO_S16SYS; wanted.channels = DEF_CHANNELS; wanted.samples = DEF_SAMPLES; wanted.silence = 0; wanted.callback = SimpleCallback; if (0>SDL_OpenAudio(&wanted, &obtained)){ fprintf(stderr, "SDL Open Audio failed, reason:%s\n" , SDL_GetError()); return -1; } fprintf(stdout, "wanted freq:%d, format:%d, channels:%d, samples:%d\n" , wanted.freq, wanted.format, wanted.channels, wanted.samples); fprintf(stdout, "obtained freq:%d, format:%d, channels:%d, samples:%d\n" , obtained.freq, obtained.format, obtained.channels, obtained.samples); |
不过由于系统(声卡)的限制,系统所能接受的参数不一定就是我们设置的参数。
音频输出
如前面所述,我们需要在callback函数中填充一块固定大小的buffer,该buffer的大小为SDL_OpenAudio时设定的音频帧大小,buffer中的音频数据会被输出到音频输出设备。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | void SimpleCallback(void* userdata, Uint8 *stream, int queryLen){ unsigned char *buf, *itr; int readsize = 0, len, bufsize, lengthOfRead; len = queryLen; buf = (unsigned char *)malloc(len); memset(buf, 0, len); itr = buf; while (len > 0){ readsize = fread(itr, 1, len, pFile); if (!readsize) len = 0; len = len - readsize; itr = itr + readsize; } memcpy(stream, buf, queryLen); free(buf); } |
分类:
SimplePlayer
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
2012-11-05 Linux输入子系统框架