Audio相关的API很少,按几个功能分别列一下,下文中的图是用visio画的,其中颜色表示看下图的标识
1.音频子系统操作 API
SDL_Init(SDL_INIT_AUDIO)
SDL_Quit(void)
SDL_AudioInit(const char* driver_name)
SDL_AudioQuit
其中的SDL_AudioInit、SDL_AudioQuit一般在内部使用,除非特别要指定使用的音频驱动程序,否则通常用SDL_Init()、SDL_InitSubSyste()、SDL_Quit() 、 SDL_QuitSubSystem()
2.操作音频设备 API
SDL_OpenAudio(SDL_AudioSpec* desired,SDL_AudioSpec* obtained)
SDL_OpenAudioDevice(const char* device, int iscapture,
const SDL_AudioSpec* desired,SDL_AudioSpec* obtained, int allowed_changes)
SDL_CloseAudio(void)
SDL_CloseAudioDevice
SDL_PauseAudio(int pause_on)
SDL_PauseAudioDevice(SDL_AudioDeviceID dev,int pause_on)
SDL_LockAudio(void)
SDL_LockAudioDevice(SDL_AudioDeviceID dev)
SDL_UnlockAudio(void)
SDL_UnlockAudioDevice(SDL_AudioDeviceID dev)
3.将音频转换为需要的格式 API
SDL_BuildAudioCVT(SDL_AudioCVT* cvt,SDL_AudioFormat src_format,Uint8 src_channels,
int src_rate,SDL_AudioFormat dst_format,Uint8 dst_channels,int dst_rate)
SDL_ConvertAudio(SDL_AudioCVT* cvt)
4.按指定的格式混合音频数据,用来回调
SDL_MixAudio(Uint8* dst,const Uint8* src,Uint32 len, int volume)
SDL_MixAudioFormat(Uint8* dst,const Uint8* src,SDL_AudioFormat format,Uint32 len, int volume)
5.获取音频设备相关信息API
SDL_GetNumAudioDevices(int iscapture)
SDL_GetNumAudioDrivers(void)
SDL_GetAudioDeviceName(int index, int iscapture)
SDL_GetAudioDeviceStatus(SDL_AudioDeviceID dev)
SDL_GetCurrentAudioDriver(void)
SDL_GetAudioStatus(void)
SDL_GetAudioDriver(int index)
6.音频队列处理
SDL_QueueAudio(SDL_AudioDeviceID dev,const void* data,Uint32 len)
SDL_DequeueAudio
SDL_GetQueuedAudioSize
SDL_ClearQueuedAudio(SDL_AudioDeviceID dev)
这系列的函数在2.0.4上开始支持,在非回调设备上使用。
在创建队列之前之前,不应该在设备上调用SDL_LockAudio(); SDL在内部处理这个功能的锁定。
音频播放过程
1.初始化音频子系统(SDL_Init(SDL_INIT_AUDIO))
2.打开音频设备(SDL_OpenAudio(SDL_AudioSpec* desired,SDL_AudioSpec* obtained)),需要填充SDL_AudioSpec结构体
3.播放音频(SDL_PauseAudio(int pause_on)),//参数pause_on:非零暂停,零则播放,播放过程中需要一个回调函数去获取音频数据
以下示例程序来自github和官网,可用来增加对API的了解,全部程序在VS2013上测试运行没问题
获取音频设备的相关信息:
项目下载地址:http://download.csdn.NET/detail/kiazhu/9745344
- // testSDL_AudioSample.cpp : 定义控制台应用程序的入口点。
- //
- #include "stdafx.h"
- #include "include\SDL.h"
- #include "include\SDL_audio.h"
- void print_devices(int iscapture)
- {
- const charchar *typestr = ((iscapture) ? "capture" : "output");
- int n = SDL_GetNumAudioDevices(iscapture);
- printf("Found %d %s device%s:\n", n, typestr, n != 1 ? "s" : "");
- if (n == -1)
- printf(" Driver can't detect specific %s devices.\n\n", typestr);
- else if (n == 0)
- printf(" No %s devices found.\n\n", typestr);
- else {
- int i;
- for (i = 0; i < n; i++) {
- const charchar *name = SDL_GetAudioDeviceName(i, iscapture);
- if (name != NULL)
- printf(" %d: %s\n", i, name);
- else
- printf(" %d Error: %s\n", i, SDL_GetError());
- }
- printf("\n");
- }
- }
- int _tmain(int argc, _TCHAR* argv[])
- {
- int n;
- /* Load the SDL library */
- if (SDL_Init(SDL_INIT_AUDIO) < 0) {
- printf("Couldn't initialize SDL: %s\n", SDL_GetError());
- return (1);
- }
- else{
- printf("init SDL success.\n");
- }
- /* Print available audio drivers */
- n = SDL_GetNumAudioDrivers();
- if (n == 0) {
- printf("No built-in audio drivers\n\n");
- }
- else {
- int i;
- printf("Built-in audio drivers:\n");
- for (i = 0; i < n; ++i) {
- printf(" %d: %s\n", i, SDL_GetAudioDriver(i));
- }
- printf("Select a driver with the SDL_AUDIODRIVER environment variable.\n");
- }
- printf("Using audio driver: %s\n\n", SDL_GetCurrentAudioDriver());
- //参数:0表示回放设备,1表示录制设备
- print_devices(0);
- print_devices(1);
- switch (SDL_GetAudioStatus())
- {
- case SDL_AUDIO_STOPPED: printf("Current Audio Status:stopped\n"); break;
- case SDL_AUDIO_PLAYING: printf("Current Audio Status:playing\n"); break;
- case SDL_AUDIO_PAUSED: printf("Current Audio Status:paused\n"); break;
- default: printf("Current Audio Status:???"); break;
- }
- SDL_Quit();
- return 0;
- }
运行结果:
插入耳机前:
插入耳机后:
录音并回放:
- // testSDL_AudioCapture.cpp : 定义控制台应用程序的入口点。
- //
- #include "stdafx.h"
- extern "C"
- {
- #include "include\SDL.h"
- #include "include\SDL_audio.h"
- }
- static SDL_Window *window = NULL;
- static SDL_Renderer *renderer = NULL;
- static SDL_AudioSpec spec;
- static SDL_AudioDeviceID devid_in = 0;
- static SDL_AudioDeviceID devid_out = 0;
- static void
- loop()
- {
- SDL_bool please_quit = SDL_FALSE;
- SDL_Event e;
- while (SDL_PollEvent(&e)) {
- if (e.type == SDL_QUIT) {
- please_quit = SDL_TRUE;
- }
- else if (e.type == SDL_KEYDOWN) {
- if (e.key.keysym.sym == SDLK_ESCAPE) {
- please_quit = SDL_TRUE;
- }
- }
- else if (e.type == SDL_MOUSEBUTTONDOWN) {
- if (e.button.button == 1) {
- SDL_PauseAudioDevice(devid_out, SDL_TRUE);
- SDL_PauseAudioDevice(devid_in, SDL_FALSE);
- }
- }
- else if (e.type == SDL_MOUSEBUTTONUP) {
- if (e.button.button == 1) {
- SDL_PauseAudioDevice(devid_in, SDL_TRUE);
- SDL_PauseAudioDevice(devid_out, SDL_FALSE);
- }
- }
- }
- if (SDL_GetAudioDeviceStatus(devid_in) == SDL_AUDIO_PLAYING) {
- SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255);
- }
- else {
- SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
- }
- SDL_RenderClear(renderer);
- SDL_RenderPresent(renderer);
- if (please_quit) {
- /* stop playing back, quit. */
- SDL_Log("Shutting down.\n");
- SDL_PauseAudioDevice(devid_in, 1);
- SDL_CloseAudioDevice(devid_in);
- SDL_PauseAudioDevice(devid_out, 1);
- SDL_CloseAudioDevice(devid_out);
- SDL_DestroyRenderer(renderer);
- SDL_DestroyWindow(window);
- SDL_Quit();
- #ifdef __EMSCRIPTEN__
- emscripten_cancel_main_loop();
- #endif
- exit(0);
- }
- /* Note that it would be easier to just have a one-line function that
- calls SDL_QueueAudio() as a capture device callback, but we're
- trying to test the API, so we use SDL_DequeueAudio() here. */
- while (SDL_TRUE) {
- Uint8 buf[1024];
- const Uint32 br = SDL_DequeueAudio(devid_in, buf, sizeof(buf));
- SDL_QueueAudio(devid_out, buf, br);
- if (br < sizeof(buf)) {
- break;
- }
- }
- }
- int
- main(int argc, charchar **argv)
- {
- /* (argv[1] == NULL means "open default device.") */
- const charchar *devname = argv[1];
- SDL_AudioSpec wanted;
- int devcount;
- int i;
- /* Enable standard application logging */
- SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
- /* Load the SDL library */
- if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) {
- SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError());
- return (1);
- }
- window = SDL_CreateWindow("testaudiocapture", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 320, 240, 0);
- renderer = SDL_CreateRenderer(window, -1, 0);
- SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
- SDL_RenderClear(renderer);
- SDL_RenderPresent(renderer);
- SDL_Log("Using audio driver: %s\n", SDL_GetCurrentAudioDriver());
- devcount = SDL_GetNumAudioDevices(SDL_TRUE);
- for (i = 0; i < devcount; i++) {
- SDL_Log(" Capture device #%d: '%s'\n", i, SDL_GetAudioDeviceName(i, SDL_TRUE));
- }
- SDL_zero(wanted);
- wanted.freq = 44100;
- wanted.format = AUDIO_F32SYS;
- wanted.channels = 1;
- wanted.samples = 4096;
- wanted.callback = NULL;
- SDL_zero(spec);
- /* DirectSound can fail in some instances if you open the same hardware
- for both capture and output and didn't open the output end first,
- according to the docs, so if you're doing something like this, always
- open your capture devices second in case you land in those bizarre
- circumstances. */
- SDL_Log("Opening default playback device...\n");
- devid_out = SDL_OpenAudioDevice(NULL, SDL_FALSE, &wanted, &spec, SDL_AUDIO_ALLOW_ANY_CHANGE);
- if (!devid_out) {
- SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open an audio device for playback: %s!\n", SDL_GetError());
- SDL_Quit();
- exit(1);
- }
- SDL_Log("Opening capture device %s%s%s...\n",
- devname ? "'" : "",
- devname ? devname : "[[default]]",
- devname ? "'" : "");
- devid_in = SDL_OpenAudioDevice(argv[1], SDL_TRUE, &spec, &spec, 0);
- if (!devid_in) {
- SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open an audio device for capture: %s!\n", SDL_GetError());
- SDL_Quit();
- exit(1);
- }
- SDL_Log("Ready! Hold down mouse or finger to record!\n");
- #ifdef __EMSCRIPTEN__
- emscripten_set_main_loop(loop, 0, 1);
- #else
- while (1) { loop(); SDL_Delay(16); }
- #endif
- return 0;
- }
播放wav音频:
-
- // testSDL_AudioLoopWave.cpp : 定义控制台应用程序的入口点。
- //
- #include "stdafx.h"
- extern "C"{
- #include "include\SDL.h"
- }
- struct
- {
- SDL_AudioSpec spec;
- Uint8 *sound; /* Pointer to wave data */
- Uint32 soundlen; /* Length of wave data */
- int soundpos; /* Current play position */
- } wave;
- /* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */
- static void
- quit(int rc)
- {
- SDL_Quit();
- exit(rc);
- }
- void SDLCALL
- fillerup(voidvoid *unused, Uint8 * stream, int len)
- {
- Uint8 *waveptr;
- int waveleft;
- /* Set up the pointers */
- waveptr = wave.sound + wave.soundpos;
- waveleft = wave.soundlen - wave.soundpos;
- /* Go! */
- /*这里有2种情况
- 1.如果waveleft>len,则直接拷贝数据播放
- 2.如果waveleft<=len,则先把剩下的数据拷贝到stream,同时拷贝开头剩下的len-waveleft数据到stream*/
- while (waveleft <= len) {
- /*播放完升下的数据*/
- SDL_memcpy(stream, waveptr, waveleft);
- stream += waveleft;
- len -= waveleft;
- /*播放完毕后将指针指向音频数据的开头*/
- waveptr = wave.sound;
- waveleft = wave.soundlen;
- wave.soundpos = 0;
- }
- SDL_memcpy(stream, waveptr, len);
- wave.soundpos += len;
- }
- static int done = 0;
- void
- poked(int sig)
- {
- done = 1;
- }
- #ifdef __EMSCRIPTEN__
- void
- loop()
- {
- if (done || (SDL_GetAudioStatus() != SDL_AUDIO_PLAYING))
- emscripten_cancel_main_loop();
- }
- #endif
- int
- main(int argc, charchar *argv[])
- {
- int i;
- char filename[4096];
- /* Enable standard application logging */
- SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
- /* Load the SDL library */
- if (SDL_Init(SDL_INIT_AUDIO) < 0) {
- SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError());
- return (1);
- }
- if (argc > 1) {
- SDL_strlcpy(filename, argv[1], sizeof(filename));
- }
- else {
- SDL_strlcpy(filename, "sample.wav", sizeof(filename));
- }
- /* Load the wave file into memory */
- /*SDL_LoadWAV这个函数读取wav音频文件后会进行下面操作
- 1.填充wave.spec结构体
- 2.将音频数据填充到wave.sound
- 3.将音频数据长度填到wave.soundlen*/
- if (SDL_LoadWAV(filename, &wave.spec, &wave.sound, &wave.soundlen) == NULL) {
- SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s\n", filename, SDL_GetError());
- quit(1);
- }
- /*播放的时候需要数据时会回调到fillerup获取音频播放数据*/
- wave.spec.callback = fillerup;
- #if HAVE_SIGNAL_H
- /* Set the signals */
- #ifdef SIGHUP
- signal(SIGHUP, poked);
- #endif
- signal(SIGINT, poked);
- #ifdef SIGQUIT
- signal(SIGQUIT, poked);
- #endif
- signal(SIGTERM, poked);
- #endif /* HAVE_SIGNAL_H */
- /* Show the list of available drivers */
- SDL_Log("Available audio drivers:");
- for (i = 0; i < SDL_GetNumAudioDrivers(); ++i) {
- SDL_Log("%i: %s", i, SDL_GetAudioDriver(i));
- }
- /* Initialize fillerup() variables */
- if (SDL_OpenAudio(&wave.spec, NULL) < 0) {
- SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open audio: %s\n", SDL_GetError());
- SDL_FreeWAV(wave.sound);
- quit(2);
- }
- SDL_Log("Using audio driver: %s\n", SDL_GetCurrentAudioDriver());
- /* Let the audio run */
- /*开始播放*/
- SDL_PauseAudio(0);
- #ifdef __EMSCRIPTEN__
- emscripten_set_main_loop(loop, 0, 1);
- #else
- while (!done && (SDL_GetAudioStatus() == SDL_AUDIO_PLAYING))
- SDL_Delay(1000);
- #endif
- /* Clean up on signal */
- SDL_CloseAudio();
- SDL_FreeWAV(wave.sound);
- SDL_Quit();
- return (0);
- }