可视门禁音频模块的代码组织

来源:互联网 发布:郑州网络电视台直播 编辑:程序博客网 时间: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)是做线程退出时的一些处理工作。

原创粉丝点击