可视门禁音频模块的代码组织
来源:互联网 发布:郑州网络电视台直播 编辑:程序博客网 时间:2024/04/29 21:00
音频模块的代码组织
音频模块不添加压缩编码的话,过程还是很简单。采集音频过程就是打开dsp驱动,读取/dev/dsp文件的数据,然后再通过网络方式传送出去(可视门禁用的是udp)。播放音频过程就是从网络的socket中读取网络数据,然后再写到dsp,就实现了播放。如果需要录音,新建wav文件,写入wav的信息头,然后写入音频数据,保存好就成了wav音频文件了。播放wav音频就是打开wav文件,读取文件的数据,然后写到dsp中。
音频模块主要由以下几部分组成:dsp、udp(或其他通信方式)、makewav和thread。添加线程主要因为一般音频采集和播放都会单独一个线程去跑。下面看这几个类的关系结构:
最下面是三个类:udp、dsp和wav。udp类负责通信,主要提供发送和接收的函数接口;dsp类负责打开和关闭dsp,向dsp写数据和从dsp读取数据。wav类主要是打开wav文件,读取文件数据,添加wav信息头生成wav文件。所以dsp和udp组合可以得到音频采集并发送功能,音频数据接收并播放功能。dsp和wav组合可以得到录音和播放指定wav文件的功能。音频采集和发送:
bool Audio::AudioCollect()
{
assert(dsp_ !=NULL);
assert(udp_ !=NULL);
memset(recvbuf_, '\0', sizeof(recvbuf_));
int readbytes= dsp_->ReadDspDev(recvbuf_, sizeof(recvbuf_));
if (readbytes<= 0) {
cerr<< "Read nothing from dsp." << endl;
returnfalse;
}
if(udp_->SendUdpData(recvbuf_, readbytes) < 0) {
returnfalse;
}
return true;
}
音频接收和播放以及录音:
bool Audio::RecvAudioEvent()
{
int readbytes= RecvAudioData();
if (readbytes< 0) {
cerr<< "Read nothing from UDP socket." << endl;
returnfalse;
}
if(flag_play_) {
AudioPlayBack(readbytes);
}
if (wav_ !=NULL) {
AudioSoundRecord(readbytes);
}
return true;
}
指定音频文件播放:
void Audio::PlayWavFile(const char *filename)
{
if (dsp_ ==NULL){
cout<< "dsp_ is NULL.:-(" << endl;
return;
}
int fd =open(filename, O_RDONLY);
if(fd < 0){
cout<< "open " << filename<< " error"<< endl;
return;
}
intreadbytes, writebytes;
charbuf[3200];
while(1) {
memset(buf,0, sizeof(buf));
readbytes= read(fd, buf, sizeof(buf));
if(readbytes<= 0) {
break;
}
writebytes= dsp_->WriteDspDev(buf, readbytes);
if(writebytes< 0) {
return;
}
}
close(fd);
cout <<"close file" << endl;
}
当需要结合线程时,也就是每个功能都单独线程运行时,那么需要添加线程的类了。线程的类是这样的:
Thread.h:
#ifndef _THREAD_H
#define _THREAD_H
#include <pthread.h>
class Thread {
public:
Thread();
virtual~Thread() {};
bool Start();
void Stop();
voidStopNoCancel();
void Join();
pthread_t tid(){ return tid_; }
intthread_status() { return thread_status_; }
private:
pthread_ttid_;
intthread_status_;
static constint THREAD_STATUS_NEW = 0;
static constint THREAD_STATUS_RUNNING = 1;
static constint THREAD_STATUS_EXIT = -1;
virtual voidHandleEvent() = 0;
virtual voidExitEvent() = 0;
static void*TransferPoint(void* point);
void*Run(void);
};
#endif /* _THREAD_H */
这个线程类有几点需要说明的,首先因为普通成员函数是没有函数地址的,而pthread_creat是需要传入地址的。
void* Thread::TransferPoint(void* point)
{
assert(point!= NULL);
Thread* p =(Thread *)point;
p->Run();
return p;
}
void* Thread::Run()
{
thread_status_= THREAD_STATUS_RUNNING;
//tid_ =pthread_self();
HandleEvent();
thread_status_= THREAD_STATUS_EXIT;
tid_ = 0;
pthread_exit(NULL);
}
bool Thread::Start()
{
if (tid_ != 0){
returnfalse;
}
int ret =pthread_create(&tid_, NULL, TransferPoint, this);
if (ret <0) {
return false;
} else {
return true;
}
}
void Thread::Stop()
{
if (tid_ ==0){
cerr<< "Thread had exit." << endl;
return;
}
ExitEvent();
pthread_cancel(tid_);
thread_status_= THREAD_STATUS_EXIT;
tid_ = 0;
}
这中间做了指针传递,实际的功能函数是HandleEvent();但HandleEvent是纯虚函数,需要在继承类实现。以音频采集发送功能线程为例:
#ifndef _MODULE_INCLUDE_AUDIOEVENT_H_
#define _MODULE_INCLUDE_AUDIOEVENT_H_
#include "thread.h"
#include "audio.h"
using namespace std;
class AudioCollectThread : public Thread {
public:
AudioCollectThread(Audio*audio) : audio_(audio) {}
~AudioCollectThread();
private:
voidHandleEvent();
voidExitEvent();
Audio*audio_;
};
#endif /*_MODULE_INCLUDE_AUDIOEVENT_H_*/
首先该线程是继承了thread类的,类只有两个功能函数HandleEvent()和ExitEvent();下面是两个函数的实现:
/*Handle audio event, called by thread*/
void AudioCollectThread::HandleEvent(void)
{
assert(audio_!= NULL);
cout <<"HandleEvent:audio collect" << endl;
while(audio_->AudioCollect());
}
/*Stop audio thread*/
void AudioCollectThread::ExitEvent(void)
{
cout <<"ExitEvent: audio collect thread." << endl;
}
那么怎么去用这一个类呢?也就怎么开启音频采集发送线程。假如定义了该类的对象audio_collect,执行audio_collect->Start(),那么这个线程就跑起来了,执行audio_collect->Stop(),这个线程就退出了。ExitEvent(void)是做线程退出时的一些处理工作。
- 可视门禁音频模块的代码组织
- 模块设计-代码组织
- 可视门禁中的MVC模式
- 使用HI3518E实现智能社区的可视楼宇门禁系统(手机远程呼叫)
- 视频音频与声音的组织保存
- Node.js 用模块组织代码
- 多模块汇编程序的组织
- 北京龙泉寺:最强科研组织!清华北大学子排队出家,门禁都是指纹识别的
- C++代码的组织
- 代码的物理组织
- 智能社区--HI3516C可视门禁研发出来咯
- AngularJS —— 使用模块组织你的代码 【已翻译100%】(1/3)
- Ruby 代码的组织方式
- WINCE代码的目录组织
- WINCE代码的目录组织
- C++ 代码文件的组织
- 组织好自己的代码
- 模板代码的组织方式
- 女子发现前夫外遇索要2000万
- 杀死进程命令(转)
- 给初学者之三:java企业级应用之硬件篇
- [编辑长度/字符串dp] HDOJ - 4323 Magic Number
- 三帧差法
- 可视门禁音频模块的代码组织
- 给初学者之四:java企业级应用之软件篇
- 用vc进行com编程
- 智障者失踪3年被发现在服刑 家属疑其系顶罪
- Linux下的输出格式
- 给初学者之五:企业级应用之中间件
- inux内核学习之进程和线程
- ubuntu12.04添加快捷方式
- sys和system用户、sysdba和sysoper系统权限、dba角色的区别