内核技术中文网»首页 论坛 圈点 查看内容

0 评论

0 收藏

分享

directSound播放pcm,回调函数

当使用 DirectSound 播放 PCM 音频时,可以通过回调函数来实现音频数据的传递和处理。以下是一个简单的示例代码,展示了如何使用回调函数来播放 PCM 音频:

#include <dsound.h>

// 定义音频缓冲区大小
const int BUFFER_SIZE = 4096;

// 音频缓冲区结构体
struct AudioBuffer {
    BYTE* data;     // 音频数据指针
    DWORD dataSize; // 音频数据大小
};

// 回调函数,在音频缓冲区需要更多数据时被调用
DWORD WINAPI FillBuffer(LPVOID lpContext, LPVOID lpBufferData, DWORD dwBufferLength)
{
    AudioBuffer* audioBuffer = static_cast<AudioBuffer*>(lpContext);

    // 将音频数据拷贝到缓冲区中
    memcpy(lpBufferData, audioBuffer->data, dwBufferLength);

    // 更新音频数据指针和大小
    audioBuffer->data += dwBufferLength;
    audioBuffer->dataSize -= dwBufferLength;

    if (audioBuffer->dataSize <= 0) {
        // 如果音频数据已经全部播放完毕,返回 DS_OK 停止播放
        return DS_OK;
    } else {
        // 返回 DSBSTATUS_CONTINUE 继续播放下一部分音频数据
        return DSBSTATUS_CONTINUE;
    }
}

int main()
{
    IDirectSound8* pDS = nullptr;         // DirectSound 对象指针
    IDirectSoundBuffer* pDSBPrimary = nullptr;   // 主要缓冲区指针
    IDirectSoundBuffer* pDSBSecondary = nullptr; // 次要缓冲区指针

    // 初始化 DirectSound 对象
    DirectSoundCreate8(nullptr, &pDS, nullptr);
    pDS->SetCooperativeLevel(hwnd, DSSCL_PRIORITY);

    // 设置主要缓冲区参数
    DSBUFFERDESC dsbdPrimary;
    ZeroMemory(&dsbdPrimary, sizeof(DSBUFFERDESC));
    dsbdPrimary.dwSize = sizeof(DSBUFFERDESC);
    dsbdPrimary.dwFlags = DSBCAPS_PRIMARYBUFFER;

    // 创建主要缓冲区
    pDS->CreateSoundBuffer(&dsbdPrimary, &pDSBPrimary, nullptr);

    // 设置次要缓冲区参数
    WAVEFORMATEX waveFormat;
    ZeroMemory(&waveFormat, sizeof(WAVEFORMATEX));

    waveFormat.wFormatTag = WAVE_FORMAT_PCM;
    waveFormat.nChannels = 2;               // 双声道
    waveFormat.nSamplesPerSec = 44100;      // 采样率
    waveFormat.nAvgBytesPerSec = 176400;    // 平均每秒字节数 (采样率 * 位深度 * 声道数 / 8)
    waveFormat.nBlockAlign = 4;             // 每个采样的字节数 (位深度 * 声道数 / 8)
    waveFormat.wBitsPerSample = 16;         // 每个采样的位深度

    // 计算音频数据总大小,这里假设音频数据已经加载到 audioBuffer 中
    DWORD dataSize = ...;

    // 创建次要缓冲区
    DSBUFFERDESC dsbdSecondary;
    ZeroMemory(&dsbdSecondary, sizeof(DSBUFFERDESC));
    dsbdSecondary.dwSize = sizeof(DSBUFFERDESC);
    dsbdSecondary.dwFlags = DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2;
    dsbdSecondary.dwBufferBytes = BUFFER_SIZE;     // 缓冲区大小
    dsbdSecondary.lpwfxFormat = &waveFormat;       // 音频格式

    pDS->CreateSoundBuffer(&dsbdSecondary, &pDSBSecondary, nullptr);

    // 将音频数据传递给回调函数
    AudioBuffer audioBuffer;
    audioBuffer.data = ...;  // 音频数据指针
    audioBuffer.dataSize = dataSize;  // 音频数据大小

    pDSBSecondary->SetBufferData(audioBuffer.data, audioBuffer.dataSize);

    // 设置回调函数
    pDSBSecondary->SetNotificationPositions(1, &positionNotify);

    // 开始播放音频缓冲区
    pDSBPrimary->Play(0, 0, DSBPLAY_LOOPING);
    pDSBSecondary->Play(0, 0, DSBPLAY_LOOPING);

    while (true) {
        // 处理其他逻辑,保持程序运行
    }

    // 释放资源和清理工作

    pDSBPrimary->Stop();
    pDSBPrimary->Release();

    pDSBSecondary->Stop();
    pDSBSecondary->Release();

    pDS->Release();

    return 0;
}

在这个示例代码中,我们创建了一个主要缓冲区和一个次要缓冲区。主要缓冲区用于控制整个 DirectSound 对象,而次要缓冲区用于实际播放 PCM 音频数据。

回调函数 FillBuffer 被设置为次要缓冲区的填充函数,在音频缓冲区需要更多数据时被调用。在回调函数中,我们将音频数据拷贝到缓冲区中,并更新音频数据指针和大小。

最后,我们通过 pDSBSecondary->Play() 方法来启动音频播放,并通过 while(true) 循环来保持程序运行。请注意,在实际开发中,还需要适当处理错误和释放资源的操作。<br/><br/><br/><p style="color:#CCCCCC;font-size:12px;">内容由零声教学AI助手提供,问题来源于学员提问</p>

回复

举报 使用道具

全部回复
暂无回帖,快来参与回复吧
主题 6306
回复 0
粉丝 0
扫码获取每晚技术直播链接
快速回复 返回顶部 返回列表