Qt解决麦克风热插拔的问题

       一个音频发送接收的程序,服务器端发送音频,客户端进行音频接收并播放。需要增加一个麦克风热插拔的功能,就是在音频传输过程中,拔掉麦克风会导致音频发送中断,重新连接麦克风后保证音频仍能继续发送。

       源程序的音频代码使用windows下waveIn系列函数,waveInOpen函数采用回调的形式获取音频。当发生麦克风热插拔操作后,会无法重新获取音频。我想到的办法是,加入麦克风热插拔检测的功能,在录音过程中实时检测麦克风的连接,当检测到麦克风断开连接后,就使用waveInStop、waveInReset和waveInClose函数关闭音频设备接口。当检测到麦克风重新连接后,再调用waveInOpen函数开启设备连接,从而继续录音并发送。

       结果这么做并不能实现,在debug过程中,发现只要程序执行到任何一句waveIn函数,都会产生死锁,这个思路时不可行的。

       后来尝试了很多方法,都不可以实现,网上说在waveInOpen函数中采用线程的形式获取音频,但我并不知道该怎么写。最终决定修改整个音频代码,放弃waveIn,采用qt中的QAudioInput类,最后成功解决问题。实现过程如下。

       为音频发送模块开辟一个工作线程,主线程用来控制软件界面操作,两个线程之间采用QMutex进行线程同步。以下是音频部分代码。

工作线程头文件:

#include <QThread>
#include <QMutex>
#include <iostream>
#include <Qlist.h>
#include <qaudiodeviceinfo.h>
#include <qaudioinput.h>
#include <qaudioformat.h>
#include <QIODevice>
#include <qthread.h>
#include <qobject.h>
#include <qdebug.h>
#include <qaudio.h>
#include <QtNetwork\qudpsocket.h>
#define AUDIOBUFFER_SIZE 2048
using namespace std;

typedef enum
{
	OPENED,
	CLOSED
}AudioDeviceState;

typedef enum
{
	FIRST,
	SECOND
}IODeviceState;

struct audioBuffer{
	char audioData[2048];
	int lens;
};

class WorkerThread : public QThread
{
	Q_OBJECT
protected:
	void run();
public:
	explicit WorkerThread(QObject *parent = NULL);
	~WorkerThread();
	bool openAudioDevice(void);
	void initAudioDevice(void);
	void mystop();
	int isAudioReady(void);
	void waveInGetSound();
private:
	QList<QAudioDeviceInfo> devicelist;	//音频设备列表
	QAudioInput *audioInput;	//音频输入
	QAudioFormat   pFormat; //音频格式
	QIODevice *inputDevice;	//音频设备
	audioBuffer  buff;	//音频数据存储
	AudioDeviceState state;
	IODeviceState iostate;
	QUdpSocket *udpSocket;
};

工作线程.cpp

#include "workerthread.h"

WorkerThread::WorkerThread(QObject *parent): QThread(parent)
{
	message = MS_NULL;
	iostate=FIRST;
}

WorkerThread::~WorkerThread(){}

void WorkerThread::initAudioDevice(void)
{
	pFormat.setCodec("audio/pcm");
	pFormat.setChannelCount(1);
	pFormat.setSampleRate(8000);	
	pFormat.setSampleSize(16);		
	pFormat.setByteOrder(QAudioFormat::LittleEndian);
	pFormat.setSampleType(QAudioFormat::SignedInt);
	audioInput = new QAudioInput(pFormat);
}

bool WorkerThread::openAudioDevice(void)
{
	devicelist=QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
	if(devicelist.size()>0)
	{
		state=OPENED;
		qDebug() << "true";
		return true;
	}else
	{
		state=CLOSED;
		qDebug() << "false";
		return false;
	}
	
}

void WorkerThread::mystop()
{
	audioInput->stop();
	state=CLOSED;
}

void WorkerThread::waveInGetSound()	//音频发送
{
	memset(&buff,0,sizeof(buff));
	buff.lens=inputDevice->read(buff.audioData,AUDIOBUFFER_SIZE);
	udpSocket->writeDatagram((const char*)&buff,sizeof(buff),QHostAddress::Broadcast,port_num);	//广播形式发送音频
	qDebug() << buff.lens;
}

void WorkerThread::run()
{
	udpSocket = new QUdpSocket();
	udpSocket->bind(QHostAddress::Any,port_num);
	initAudioDevice();
	while(true)
	{	
		if(iostate==FIRST)
		{
			openAudioDevice();	//检测麦克风连接状态
			if(state==OPENED)
			{
				inputDevice = audioInput->start(); //开始录音
				waveInGetSound();
				iostate=SECOND;
			}
		}else{
			openAudioDevice();
			if(state==OPENED){
				waveInGetSound();
			}else{
				mystop(); //关闭录音
				iostate=FIRST;
			}
		}
		usleep(10);	
	}
}

       上述代码中,用iostate判断音频设备接口状态,保证每次发送过程中,音频设备接口只开启和关闭一次。当麦克风插拔后,重新开启音频设备接口,进行录音发送。

主线程中开启工作线程,头文件中添加:

#include "workerthread.h"
WorkerThread  *worker;

主线程.cpp中添加:

worker = new WorkerThread();
worker->start();

这么改虽说像在把感冒当癌症治,但最终完成了需求,还是比较有用的。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

泊零绮梦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值