流程:
打开音频设备->给设备设置音频参数->向声卡喂pcm 数据->播放音频->关闭设备
设置音频参数,包括声道,采样率,位深,使得设备知道怎么播放这些音频
播放音频的基本原则:
1.声卡向你要数据而不是你主动推给声卡,无论使用sdl还是其他库都是这样,这是声卡的工作原理。当声卡需要数据时它会调用回调函数,来向我们要数据。我们要写这个回调函数。
2.每次要的数据大小由之前设置的音频参数决定。且声卡会维护一个缓冲区,用来存放接收的数据。
SDL_OpenAudio()/SDL_CloseAudio() //打开音频设备和关闭音频设备
SDL_PauseAudio() //暂停或播放,有两个状态
SDL_MixAudio //混音,多路音频叠加,要注意值越界带来的失真。
每次从文件中读取4M的pcm放在缓冲区buf,声卡缓冲区不足时调用回调函数从buf中读取,若buf被读完数据,则再次去文件中读取4M,直到文件中的数据被读取完毕。
推荐一套音视频免费课程,笔者听完了,nice!免费报名可听!
#include <stdio.h>
#include <SDL.h>#define BLOCK_SIZE 4096000static Uint8 *audio_buf = NULL;
static Uint8 *audio_pos = NULL;
static size_t buffer_len = 0;//callback function for audio devcie
void read_audio_data(void *udata, Uint8 *stream, int len){if(buffer_len == 0){return;}SDL_memset(stream, 0, len);len = (len < buffer_len) ? len : buffer_len;SDL_MixAudio(stream, audio_pos, len, SDL_MIX_MAXVOLUME);audio_pos += len;buffer_len -= len;
}int main(int argc, char *argv[])
{int ret = -1;FILE *audio_fd = NULL;SDL_AudioSpec spec;char *path = "./test.pcm";//SDL initializeif(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)){fprintf(stderr, "Could not initialize SDL - %sn", SDL_GetError());return ret;}//open pcm fileaudio_fd = fopen(path, "r");if(!audio_fd){fprintf(stderr, "Failed to open pcm file!n");goto __FAIL;}//alloc memory for audioaudio_buf = (Uint8*)malloc(BLOCK_SIZE);if(!audio_buf){goto __FAIL;}//SDL_AudioSpecspec.freq = 44100;spec.format = AUDIO_S16SYS;spec.channels = 2;spec.silence = 0;spec.samples = 2048;spec.callback = read_audio_data;spec.userdata = NULL;//open audio devcieif(SDL_OpenAudio(&spec, NULL)){fprintf(stderr, "Failed to open audio device, %sn", SDL_GetError());goto __FAIL;}//play audioSDL_PauseAudio(0);//此时已启动线程,开始调用回调函数从缓冲区读取数据,并且播放。do{//read data from pcm filebuffer_len = fread(audio_buf, 1, BLOCK_SIZE, audio_fd);fprintf(stderr, "block size is %zun", buffer_len);audio_pos = audio_buf;//the main thread wait for a momentwhile(audio_pos < (audio_buf + buffer_len)) {SDL_Delay(1);//主线程每隔1ms检查一下audio_buf中的数据是否已被回调函数读取完毕。}}while(buffer_len !=0);//close audio deviceSDL_CloseAudio();ret = 0;__FAIL://release some resourcesif(audio_buf){free(audio_buf);}if(audio_fd){fclose(audio_fd);}//quit SDLSDL_Quit();return ret;
}
//这个程序还有一个小问题,就是最后一次从文件中读取的内容可能还没来得及全部被回调函数读完,程序就停止了。
本文发布于:2024-02-02 07:29:08,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170683014742279.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |