SDL2.0-播放音频

1. 播放原理

  • 设置音频选项,如采样率,通道数等,设置回调函数
  • 当我们播放音频数据时,SDL会不断调用这个回调函数,并要求它填充一定数量的字节的音频数据到音频缓冲区
  • 当调用SDL_OpenAudio时,将打开音频设备并将其返回给另一个AudioSpec结构体

2. 流程

  1. 初始化
    • 初始化SDL
    • 根据参数(SDL_AudioSpec)打开音频设施
  2. 循环播放数据
    • 播放音频数据
    • 延时等待播放完成

3. API

  • 打开音频设施

    int SDLCALL SDL_OpenAudio(SDL_AudioSpec * desired,
                              SDL_AudioSpec * obtained);
    // desired:期望的参数。
    // obtained:实际音频设备的参数,一般情况下设置为NULL即可。
    
  • SDL_AudioSpec结构体

    //在这个结构体中包含了音频的各种参数
    typedef struct SDL_AudioSpec
    {
        int freq;                   // 音频采样率
        SDL_AudioFormat format;     // 音频数据格式
        Uint8 channels;             // 声道数: 1 单声道, 2 立体声
        Uint8 silence;              // 设置静音的值
        Uint16 samples;             // 音频缓冲区中的采样个数,如441000
        Uint16 padding;             // 考虑到兼容性的一个参数
        Uint32 size;                // 音频缓冲区的大小,以字节为单位
        SDL_AudioCallback callback; // 填充音频缓冲区的回调函数
        void *userdata;             // 用户自定义的数据
    } SDL_AudioSpec;
    
    format:音频数据的格式。举例几种格式:
    AUDIO_U16SYS:Unsigned 16-bit samples
    AUDIO_S16SYS:Signed 16-bit samples
    AUDIO_S32SYS:32-bit integer samples
    AUDIO_F32SYS:32-bit floating point samples
    
  • SDL_AudioCallback 向音频设备写入数据

    void (SDLCALL * SDL_AudioCallback) (void *userdata,
                                        Uint8 *stream,
                                        int len);
    userdata 用户自定义数据
    stream 指向要填充的音频缓冲区
    len 音频缓冲区大小
    
  • SDL_PauseAudio 播放音频数据

    void SDLCALL SDL_PauseAudio(int pause_on)
    
    pause_on: 0-可以开始播放音频数据,1-静音
    

4. 完整示例

 
#include "SDLHeader.h"
#include <algorithm>
#include <fstream>
#include <string>
#include <iostream>
 
Uint8* audio_chunk;
Uint32 audio_len;
Uint8* audio_pos;
 
const static uint32_t PCM_BUFFER_SIZE = 4096;
//ffplay.exe -ar 44100 -ac 2 -f s16le -i NocturneNo2inEflat_44.1k_s16le.pcm
const static std::string PCM_PATH = "D:\\vod\\testvideo\\NocturneNo2inEflat_44.1k_s16le.pcm";
 
//数据到来的回调函数
void read_audio_data_cb(void* udata, Uint8* stream, int len)
{
    SDL_memset(stream, 0, len);
    if (audio_len == 0)
        return;
    len = std::min(len, static_cast<int>(audio_len));
 
    SDL_MixAudio(stream, audio_pos, len, SDL_MIX_MAXVOLUME);
    audio_pos += len;
    audio_len -= len;
}
 
int main(int argc, char** argv)
{
    SDL_Init(SDL_INIT_AUDIO);   //init
 
    SDL_AudioSpec spec;
    spec.freq = 44100;
    spec.format = AUDIO_S16SYS;
    spec.channels = 2;
    spec.samples = 1024;
    spec.callback = read_audio_data_cb;
    spec.userdata = NULL;
    //根据参数,打开音频设备
    if (SDL_OpenAudio(&spec, NULL) < 0)
        return -1;
 
    //打开文件
    std::ifstream pcm(PCM_PATH.c_str(), std::ios::in | std::ios::binary);
    if (!pcm.is_open())
        return -1;
    char* pcm_buffer = (char*)malloc(PCM_BUFFER_SIZE);
    //开始播放
    SDL_PauseAudio(0);
 
    while (!pcm.eof())
    {
        pcm.read(pcm_buffer, PCM_BUFFER_SIZE);
        if (pcm.bad())
            break;
        audio_chunk = reinterpret_cast<Uint8*>(pcm_buffer);
        audio_len = pcm.gcount();                           //读取到的字节数
        audio_pos = audio_chunk;
        std::cout << "play " << audio_len << " data" << std::endl;
        while (audio_len > 0)       //等待audio_len长度的数据播放完成  
            SDL_Delay(1);
    }
 
    free(pcm_buffer);
    SDL_Quit();
 
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值