在上一篇文章《DirectSound播放声音入门指南(0)》基础上对声音的录制进行研究,形成了本文。同时,本文也主要参考了Doubango开源项目(该项目现在已经难以维护了,因为其功能太强大了,它什么都想做)。它是一个优秀的声音处理开源框架,不仅有完整的声音录制与播放机制,同时还实现了N种音频编解码。但是,它基于sip协议的通信机制,明文而复杂的数据包,已经被时代所抛弃了。
目录:
在Doubango项目中,DirectSound被封装为两大类:
其中,消费者就是上一篇文章《DirectSound播放声音入门指南(0)》中所讲到的声音的播放。其声音播放的机制是这样的:
RTP就是在音频包上封装以个RTP协议头。opus是目前一种极为优秀的编码格式,笔者在测试过程中,基本上320字节的音频包被编码为14->18字节左右,而且音质还极棒,可见opus的可怕之处。
Doubango另一个极为优秀的地方,就是它有一个抖动缓冲区。在封RTP包的时候,会根据时间戳计算播放时间(因为已经不是PCM音频流了,无法通过data_size计算),而且RTP头中分装了ssrc,这个用来记录是否切换了用户(就是说话人有没有变化)。一旦变化,就要清空各种缓冲,所以,笔者在实现的时候直接是这样:
static const int ssrc = clock();
扯了很长时间的音频播放,其实就是对上一篇文章的补充。
下面将正式开始讲,DirectSound音频录制:
很多原理性的东西,已经在上一篇文章中简单提到了。本文中不打算唠叨这些原理,而是直接给出了C/C++简单实现的DEMO,同上文一样,本文CODE也是来自于开源项目Doubango,笔者自己独立出来的录音部分。
这里,我并不打算给出网络、编解码、RTP包封装、抖动缓冲区实现,而是只给出了PCM脉冲音频的录音,直接存入文件中。当然,其实我也只实现了前三种,抖动缓冲区我并没有深入研究。
DEMO一向很简单粗暴,我只关注具体函数的实现,不去干任何多余的东西。
就是这些简单的东西。
下面我只是将头文件搬运到博客中来了,我并不打算将.cpp实现也粘贴上来。
因为我已经将完整DEMO放在我的git上了,你可以点击这里《DirectSound录制声音实现》就会进入到我的git。
Wow!所有源码都在上面,注释都有,你看起来并不会感到困难。当然,某些人也会有疑问。
#ifndef WIN32_AUDIO_CONTROL_DSRECORDER_H
#define WIN32_AUDIO_CONTROL_DSRECORDER_H
#include <dsound.h>
#include <stdint.h>
#include <stdio.h>
#include "Config.h"
#pragma comment (lib,"dsound.lib")
#pragma comment (lib,"dxguid.lib")
#if !defined(RECORDER_NOTIF_POS_COUNT)
# define RECORDER_NOTIF_POS_COUNT 10
#endif /* RECODER_NOTIF_POS_COUNT */
/*开关,是否将数据写入文件*/
#define OPEN_SAVE_CAPTUREBUFFER_TO_FILE 1
typedef struct RECODER{
RECODER(){
device = NULL;
captureBuffer = NULL;
started = false;
bytes_per_notif_ptr = NULL;
#if OPEN_SAVE_CAPTUREBUFFER_TO_FILE
fp = NULL;
#endif
}
LPDIRECTSOUNDCAPTURE device;
LPDIRECTSOUNDCAPTUREBUFFER captureBuffer;
HANDLE notifEvents[RECORDER_NOTIF_POS_COUNT];
bool started;
size_t bytes_per_notif_size;
uint8_t* bytes_per_notif_ptr;
HANDLE tid[2];
#if OPEN_SAVE_CAPTUREBUFFER_TO_FILE
FILE* fp;
#endif
} Recorder;
/*准备录音*/
int prepare(Recorder* ds);
/*开始录音*/
int startRecorder(Recorder* ds);
/*挂起录音*/
int suspendRecorder(Recorder* ds);
int resumeRecorder(Recorder* ds);
int stopRecorder(Recorder* ds);
/*释放录音资源*/
int unprepare(Recorder* ds);
DWORD WINAPI recorderThreadImpl(LPVOID params);
#if OPEN_SAVE_CAPTUREBUFFER_TO_FILE
int openFile(Recorder* ds);
int closeFile(Recorder* ds);
#endif
#endif