593 lines
16 KiB
C++
593 lines
16 KiB
C++
|
||
#ifdef OS_WINDOWS
|
||
//< 为了检测可用声卡
|
||
#include <mmdeviceapi.h>
|
||
#include <endpointvolume.h>
|
||
#endif
|
||
|
||
#include <QDir>
|
||
#include <QDateTime>
|
||
#include <QAudioDeviceInfo>
|
||
#include <QMediaPlaylist>
|
||
#include "CAlarmMediaPlayer.h"
|
||
#include "pub_utility_api/FileUtil.h"
|
||
#include "pub_logger_api/logger.h"
|
||
#include "pub_utility_api/I18N.h"
|
||
#include "CAlarmSetMng.h"
|
||
#include "service/alarm_server_api/AlarmCommonDef.h"
|
||
#include "CAlarmMsgManage.h"
|
||
|
||
using namespace iot_public;
|
||
CAlarmMediaPlayer * CAlarmMediaPlayer::m_pInstance = NULL;
|
||
CAlarmMediaPlayer *CAlarmMediaPlayer::instance()
|
||
{
|
||
if(NULL == m_pInstance)
|
||
{
|
||
m_pInstance = new CAlarmMediaPlayer();
|
||
}
|
||
return m_pInstance;
|
||
}
|
||
|
||
CAlarmMediaPlayer::CAlarmMediaPlayer()
|
||
:m_bHaveValidAudioDev(true),m_pMediaPlayer(Q_NULLPTR),m_pTextToSpeech(Q_NULLPTR),m_pTimerCheckAudioDev(Q_NULLPTR),m_voice(100)
|
||
{
|
||
m_readFlag = true;
|
||
QDir dir(QString::fromStdString(iot_public::CFileUtil::getCurModuleDir()));
|
||
dir.cdUp();
|
||
dir.cdUp();
|
||
dir.cd("data");
|
||
dir.cd("sound");
|
||
initSetCfg();
|
||
m_strMediaPath = dir.absolutePath() + QDir::separator();
|
||
m_bChange = true;
|
||
m_pTimerCheckAudioDev = new QTimer();
|
||
m_pTimerCheckAudioDev->setInterval(5000);
|
||
connect(m_pTimerCheckAudioDev, SIGNAL(timeout()), this, SLOT(checkAudioDev()),Qt::QueuedConnection);
|
||
m_pTimerCheckAudioStatus = new QTimer();
|
||
m_pTimerCheckAudioStatus->setInterval(30000);
|
||
connect(m_pTimerCheckAudioStatus,&QTimer::timeout, this, &CAlarmMediaPlayer::checkAudioStatus,Qt::QueuedConnection);
|
||
checkAudioDev();
|
||
checkAudioStatus();
|
||
m_pTimerCheckAudioDev->start();
|
||
m_pTimerCheckAudioStatus->start();
|
||
|
||
//< 需在checkAudioDev()之后调用
|
||
|
||
if(m_act == (int)E_ALARM_SOUND)
|
||
{
|
||
initPlayer();
|
||
}else
|
||
{
|
||
initSpeech();
|
||
}
|
||
}
|
||
|
||
void CAlarmMediaPlayer::updateAudioCues()
|
||
{
|
||
if(m_act == (int)E_ALARM_SOUND)
|
||
{
|
||
updateAudioCuesPlayer();
|
||
}else
|
||
{
|
||
updateAudioCuesSpeech();
|
||
}
|
||
}
|
||
|
||
CAlarmMediaPlayer::~CAlarmMediaPlayer()
|
||
{
|
||
if(Q_NULLPTR != m_pTimerCheckAudioDev)
|
||
{
|
||
m_pTimerCheckAudioDev->stop();
|
||
m_pTimerCheckAudioDev->deleteLater();
|
||
}
|
||
m_pTimerCheckAudioDev = NULL;
|
||
if(Q_NULLPTR != m_pTimerCheckAudioStatus)
|
||
{
|
||
m_pTimerCheckAudioStatus->stop();
|
||
m_pTimerCheckAudioStatus->deleteLater();
|
||
}
|
||
m_pTimerCheckAudioStatus = NULL;
|
||
if(Q_NULLPTR != m_pMediaPlayer)
|
||
{
|
||
if(QMediaPlayer::StoppedState != m_pMediaPlayer->state())
|
||
{
|
||
m_pMediaPlayer->disconnect();
|
||
m_pMediaPlayer->stop();
|
||
}
|
||
delete m_pMediaPlayer;
|
||
}
|
||
m_pMediaPlayer = Q_NULLPTR;
|
||
|
||
if(Q_NULLPTR != m_pTextToSpeech)
|
||
{
|
||
if(QTextToSpeech::Ready != m_pTextToSpeech->state())
|
||
{
|
||
m_pTextToSpeech->disconnect();
|
||
m_pTextToSpeech->stop();
|
||
}
|
||
delete m_pTextToSpeech;
|
||
}
|
||
m_pTextToSpeech = Q_NULLPTR;
|
||
delete m_pInstance;
|
||
m_pInstance = Q_NULLPTR;
|
||
}
|
||
|
||
void CAlarmMediaPlayer::initPlayer()
|
||
{
|
||
if(Q_NULLPTR != m_pMediaPlayer)
|
||
{
|
||
return;
|
||
}
|
||
m_pMediaPlayer = new QMediaPlayer();
|
||
m_pMediaPlayer->setVolume(m_voice);
|
||
connect(m_pMediaPlayer, &QMediaPlayer::stateChanged, this, &CAlarmMediaPlayer::playerStateChanged,Qt::QueuedConnection);
|
||
connect(m_pMediaPlayer, SIGNAL(error(QMediaPlayer::Error)), this, SLOT(printError(QMediaPlayer::Error)),Qt::QueuedConnection);
|
||
|
||
QMediaPlaylist *pPlayList = new QMediaPlaylist(this);
|
||
pPlayList->setPlaybackMode(QMediaPlaylist::Sequential);
|
||
pPlayList->clear();
|
||
m_pMediaPlayer->setPlaylist(pPlayList);
|
||
}
|
||
|
||
void CAlarmMediaPlayer::initSpeech()
|
||
{
|
||
if(Q_NULLPTR != m_pTextToSpeech)
|
||
{
|
||
return;
|
||
}
|
||
|
||
QStringList engineList = QTextToSpeech::availableEngines();
|
||
|
||
if(engineList.isEmpty())
|
||
{
|
||
return ;
|
||
}
|
||
if(m_engine.isEmpty() || !engineList.contains(m_engine))
|
||
{
|
||
#ifdef OS_LINUX
|
||
m_pTextToSpeech = Q_NULLPTR;
|
||
return;
|
||
#else
|
||
m_pTextToSpeech = new QTextToSpeech(this);
|
||
#endif
|
||
}else
|
||
{
|
||
m_pTextToSpeech = new QTextToSpeech(m_engine,this);
|
||
}
|
||
m_pTextToSpeech->setVolume(m_voice);
|
||
connect(m_pTextToSpeech, &QTextToSpeech::stateChanged, this, &CAlarmMediaPlayer::speechStateChanged,Qt::QueuedConnection);
|
||
QVector<QLocale> locales = m_pTextToSpeech->availableLocales();
|
||
if(!m_language.isEmpty())
|
||
{
|
||
foreach (const QLocale &locale, locales) {
|
||
if (locale.name() == m_language)
|
||
{
|
||
m_pTextToSpeech->setLocale(locale);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
QVector<QVoice> voices = m_pTextToSpeech->availableVoices();
|
||
if(!m_voiceName.isEmpty())
|
||
{
|
||
foreach (const QVoice &voice, voices) {
|
||
if (voice.name() == m_voiceName)
|
||
{
|
||
m_pTextToSpeech->setVoice(voice);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
void CAlarmMediaPlayer::initSetCfg()
|
||
{
|
||
CAlarmSetMng::instance()->getActAndNum(m_act,m_num,m_style);
|
||
CAlarmSetMng::instance()->getEngine(m_engine,m_language,m_voiceName);
|
||
LOGDEBUG("获取当前语音引擎:%s-%s-%s",m_engine.toStdString().c_str(),m_language.toStdString().c_str(),m_voiceName.toStdString().c_str());
|
||
}
|
||
|
||
void CAlarmMediaPlayer::removeAudioCuesStop()
|
||
{
|
||
if(m_act == (int)E_ALARM_SOUND)
|
||
{
|
||
if(m_pMediaPlayer != NULL)
|
||
{
|
||
m_pMediaPlayer->stop();
|
||
}
|
||
}else
|
||
{
|
||
if(m_pTextToSpeech != NULL)
|
||
{
|
||
m_pTextToSpeech->stop();
|
||
emit m_pTextToSpeech->stateChanged(m_pTextToSpeech->state());
|
||
}
|
||
}
|
||
}
|
||
|
||
void CAlarmMediaPlayer::insertAudioCuesStop(const AlarmMsgPtr &info)
|
||
{
|
||
if(m_act == (int)E_ALARM_SOUND && ALM_ACT_SOUND == (info->m_alarmAction & ALM_ACT_SOUND))
|
||
{
|
||
if(m_pMediaPlayer != NULL)
|
||
{
|
||
m_pMediaPlayer->stop();
|
||
}
|
||
}else if(m_act == (int)E_ALARM_VOICE && ALM_ACT_VOICE == (info->m_alarmAction & ALM_ACT_VOICE))
|
||
{
|
||
if(m_pTextToSpeech != NULL)
|
||
{
|
||
m_pTextToSpeech->stop();
|
||
emit m_pTextToSpeech->stateChanged(m_pTextToSpeech->state());
|
||
}
|
||
}
|
||
}
|
||
|
||
void CAlarmMediaPlayer::setVolumeEnable(bool bEnable)
|
||
{
|
||
if(bEnable)
|
||
{
|
||
m_voice = 100;
|
||
if(m_pMediaPlayer != Q_NULLPTR)
|
||
{
|
||
m_pMediaPlayer->setVolume(m_voice);
|
||
}
|
||
|
||
if(m_pTextToSpeech != Q_NULLPTR)
|
||
{
|
||
m_pTextToSpeech->setVolume(m_voice);
|
||
}
|
||
|
||
}
|
||
else
|
||
{
|
||
m_voice = 0;
|
||
if(m_pMediaPlayer != Q_NULLPTR)
|
||
{
|
||
m_pMediaPlayer->setVolume(m_voice);
|
||
}
|
||
|
||
if(m_pTextToSpeech != Q_NULLPTR)
|
||
{
|
||
m_pTextToSpeech->setVolume(m_voice);
|
||
}
|
||
}
|
||
}
|
||
|
||
void CAlarmMediaPlayer::release()
|
||
{
|
||
LOGINFO("CAlarmMediaPlayer::release()");
|
||
if(m_pMediaPlayer)
|
||
{
|
||
m_pMediaPlayer->stop();
|
||
}
|
||
if(m_pTextToSpeech)
|
||
{
|
||
m_pTextToSpeech->stop();
|
||
}
|
||
}
|
||
|
||
void CAlarmMediaPlayer::destory()
|
||
{
|
||
if(m_pMediaPlayer)
|
||
{
|
||
m_pMediaPlayer->disconnect();
|
||
m_pMediaPlayer->stop();
|
||
}
|
||
if(m_pTextToSpeech)
|
||
{
|
||
m_pTextToSpeech->disconnect();
|
||
m_pTextToSpeech->stop();
|
||
}
|
||
m_pInstance = NULL;
|
||
deleteLater();
|
||
}
|
||
|
||
void CAlarmMediaPlayer::slotLoadConfig()
|
||
{
|
||
LOGINFO("CAlarmMediaPlayer::slotLoadConfig()");
|
||
if(m_pMediaPlayer)
|
||
{
|
||
m_pMediaPlayer->disconnect();
|
||
m_pMediaPlayer->stop();
|
||
delete m_pMediaPlayer;
|
||
m_pMediaPlayer = Q_NULLPTR;
|
||
}
|
||
if(m_pTextToSpeech)
|
||
{
|
||
m_pTextToSpeech->disconnect();
|
||
m_pTextToSpeech->stop();
|
||
delete m_pTextToSpeech;
|
||
m_pTextToSpeech = Q_NULLPTR;
|
||
}
|
||
initSetCfg();
|
||
|
||
|
||
if(m_act == (int)E_ALARM_SOUND)
|
||
{
|
||
initPlayer();
|
||
updateAudioCuesPlayer();
|
||
}else
|
||
{
|
||
initSpeech();
|
||
updateAudioCuesSpeech();
|
||
}
|
||
}
|
||
|
||
void CAlarmMediaPlayer::slotReadFlag()
|
||
{
|
||
LOGDEBUG("slotReadFlag");
|
||
m_readFlag = true;
|
||
|
||
if(m_style != E_STYLE_NO_ALARM)
|
||
{
|
||
updateAudioCues();
|
||
}
|
||
}
|
||
|
||
void CAlarmMediaPlayer::playerStateChanged(QMediaPlayer::State state)
|
||
{
|
||
if(m_act != (int)E_ALARM_SOUND)
|
||
{
|
||
return ;
|
||
}
|
||
m_bChange = true;
|
||
if(state == QMediaPlayer::StoppedState)
|
||
{
|
||
updateAudioCuesPlayer();
|
||
}
|
||
}
|
||
|
||
void CAlarmMediaPlayer::speechStateChanged(QTextToSpeech::State state)
|
||
{
|
||
if(m_act != (int)E_ALARM_VOICE)
|
||
{
|
||
return ;
|
||
}
|
||
if(state == QTextToSpeech::Ready)
|
||
{
|
||
updateAudioCuesSpeech();
|
||
}
|
||
}
|
||
|
||
void CAlarmMediaPlayer::updateAudioCuesPlayer()
|
||
{
|
||
if(!m_bHaveValidAudioDev || !m_pMediaPlayer || !m_readFlag || m_pMediaPlayer->state() != QMediaPlayer::StoppedState)
|
||
{
|
||
LOGDEBUG("CAlarmMediaPlayer::updateAudioCuesPlayer(),return");
|
||
return;
|
||
}
|
||
AlarmMsgPtr info;
|
||
if(m_style == E_STYLE_REPEAT)
|
||
{
|
||
info = CAlarmMsgManage::instance()->getOnePlayerAlm(-1);
|
||
}
|
||
else if(m_style == E_STYLE_REPEAT_X)
|
||
{
|
||
info = CAlarmMsgManage::instance()->getOnePlayerAlm(m_num);
|
||
}
|
||
if(info == Q_NULLPTR)
|
||
{
|
||
m_readFlag = false;
|
||
return ;
|
||
}
|
||
QStringList strAudioFileNames = info->sound_file;
|
||
|
||
m_pMediaPlayer->playlist()->clear();
|
||
foreach (QString fileName, strAudioFileNames)
|
||
{
|
||
if(!fileName.isEmpty())
|
||
{
|
||
fileName = m_strMediaPath + fileName;
|
||
if(QFile::exists(fileName))
|
||
{
|
||
m_pMediaPlayer->playlist()->addMedia(QUrl::fromLocalFile(fileName));
|
||
}
|
||
}
|
||
}
|
||
if(!m_pMediaPlayer->playlist()->isEmpty())
|
||
{
|
||
m_pMediaPlayer->play();
|
||
}
|
||
}
|
||
|
||
void CAlarmMediaPlayer::updateAudioCuesSpeech()
|
||
{
|
||
if(!m_bHaveValidAudioDev || !m_pTextToSpeech || !m_readFlag || m_pTextToSpeech->state() != QTextToSpeech::Ready)
|
||
{
|
||
LOGDEBUG("CAlarmMediaPlayer::updateAudioCuesSpeech(),return");
|
||
return;
|
||
}
|
||
AlarmMsgPtr info;
|
||
if(m_style == E_STYLE_REPEAT)
|
||
{
|
||
info = CAlarmMsgManage::instance()->getOneSpeechAlm(-1);
|
||
}
|
||
else if(m_style == E_STYLE_REPEAT_X)
|
||
{
|
||
info = CAlarmMsgManage::instance()->getOneSpeechAlm(m_num);
|
||
}
|
||
if(info == Q_NULLPTR)
|
||
{
|
||
m_readFlag = false;
|
||
return ;
|
||
}
|
||
QString alarmContent = info->content;
|
||
|
||
if(!alarmContent.isEmpty())
|
||
{
|
||
m_pTextToSpeech->say(alarmContent);
|
||
}
|
||
}
|
||
|
||
void CAlarmMediaPlayer::printError(QMediaPlayer::Error error)
|
||
{
|
||
if(m_pMediaPlayer)
|
||
{
|
||
LOGERROR("QMediaPlayer error == %d , errorString : %s",error,m_pMediaPlayer->errorString().toStdString().c_str());
|
||
}
|
||
}
|
||
|
||
void CAlarmMediaPlayer::checkAudioDev()
|
||
{
|
||
//< 周期性检测音频设备有效性,因为:
|
||
//< 1、声卡是可以热拔插的,比如USB声卡
|
||
//< 2、音频服务(比如Windows Audio系统服务)也是可以动态启停的
|
||
|
||
bool bHaveValidDev = false;
|
||
|
||
//< 注意:在win系统,qt5.9.9以及5.12.9上测试,下面使用QAudioDeviceInfo检测的方法,本身会导致内存上涨
|
||
{
|
||
// //< 测试结果:无论windows audio服务是否启动,defaultOutputDevice看上去都是对的,所以,不能用这个判断是否有效
|
||
|
||
// QList<QAudioDeviceInfo> listDev(QAudioDeviceInfo::availableDevices(QAudio::AudioOutput));
|
||
|
||
// //< 不能仅仅检测列表是否为空,还需要检测有效性
|
||
// //< 当有声卡硬件,但是Windows Audio服务未启动时,设备列表不为空,但如果播放依然可能导致内存上涨问题
|
||
// foreach (QAudioDeviceInfo objDev, listDev)
|
||
// {
|
||
// //< 当Window Audio服务未启动时,无法获取有效的格式信息,以此判断
|
||
// if(objDev.preferredFormat().isValid())
|
||
// {
|
||
// bHaveValidDev = true;
|
||
// break;
|
||
// }
|
||
// }
|
||
}
|
||
|
||
//< 不得已,使用win系统原生API条件编译
|
||
#ifdef OS_WINDOWS
|
||
{
|
||
//< 获取系统默认主设备的音量,如果成功则至少说明:
|
||
//< 1、有声卡; 2、Windows Audio服务正常
|
||
|
||
CoInitialize(NULL);
|
||
IMMDeviceEnumerator *pDevEnumerator = NULL;
|
||
CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (LPVOID *)&pDevEnumerator);
|
||
|
||
if(NULL != pDevEnumerator)
|
||
{
|
||
IMMDevice *pDefaultDev = NULL;
|
||
pDevEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pDefaultDev);
|
||
|
||
pDevEnumerator->Release();
|
||
pDevEnumerator = NULL;
|
||
|
||
if(NULL != pDefaultDev)
|
||
{
|
||
IAudioEndpointVolume *pEndpointVol = NULL;
|
||
pDefaultDev->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (LPVOID *)&pEndpointVol);
|
||
|
||
pDefaultDev->Release();
|
||
pDefaultDev = NULL;
|
||
|
||
if(NULL != pEndpointVol)
|
||
{
|
||
float fVol;
|
||
const HRESULT nResult = pEndpointVol->GetMasterVolumeLevelScalar(&fVol);
|
||
if(S_OK == nResult)
|
||
bHaveValidDev = true;
|
||
|
||
pEndpointVol->Release();
|
||
pEndpointVol = NULL;
|
||
}
|
||
}
|
||
}
|
||
|
||
CoUninitialize();
|
||
}
|
||
#else
|
||
//< 在Linux系统下测试,即使没有声卡也未见问题,暂时不做检测
|
||
bHaveValidDev = true;
|
||
#endif
|
||
if(m_act == (int)E_ALARM_SOUND) //
|
||
{
|
||
if(m_bHaveValidAudioDev && !bHaveValidDev)
|
||
{
|
||
LOGERROR("No valid audio output device !");
|
||
m_bHaveValidAudioDev = false;
|
||
if(m_pMediaPlayer != Q_NULLPTR)
|
||
{
|
||
m_pMediaPlayer->disconnect();
|
||
m_pMediaPlayer->stop();
|
||
delete m_pMediaPlayer;
|
||
m_pMediaPlayer = Q_NULLPTR;
|
||
}
|
||
}
|
||
else if(!m_bHaveValidAudioDev && bHaveValidDev)
|
||
{
|
||
LOGINFO("Valid audio output device detected !");
|
||
|
||
//< 不重新构造可能不能正常播放
|
||
if(m_pMediaPlayer)
|
||
{
|
||
m_pMediaPlayer->disconnect();
|
||
delete m_pMediaPlayer;
|
||
m_pMediaPlayer = Q_NULLPTR;
|
||
}
|
||
|
||
m_bHaveValidAudioDev = true;
|
||
initPlayer();
|
||
updateAudioCuesPlayer();
|
||
}
|
||
}else
|
||
{
|
||
if(m_bHaveValidAudioDev && !bHaveValidDev)
|
||
{
|
||
LOGERROR("No valid audio output device !");
|
||
m_bHaveValidAudioDev = false;
|
||
if(m_pTextToSpeech != Q_NULLPTR)
|
||
{
|
||
m_pTextToSpeech->disconnect();
|
||
m_pTextToSpeech->stop();
|
||
delete m_pTextToSpeech;
|
||
m_pTextToSpeech = Q_NULLPTR;
|
||
}
|
||
}
|
||
else if(!m_bHaveValidAudioDev && bHaveValidDev)
|
||
{
|
||
LOGINFO("Valid audio output device detected !");
|
||
|
||
//< 不重新构造可能不能正常播放
|
||
if(m_pTextToSpeech)
|
||
{
|
||
m_pTextToSpeech->disconnect();
|
||
m_pTextToSpeech->stop();
|
||
delete m_pTextToSpeech;
|
||
m_pTextToSpeech = Q_NULLPTR;
|
||
}
|
||
m_bHaveValidAudioDev = true;
|
||
initSpeech();
|
||
updateAudioCuesSpeech();
|
||
}
|
||
}
|
||
}
|
||
//因QMediaPlayer自身bug问题 此处只检测QMediaPlayer
|
||
void CAlarmMediaPlayer::checkAudioStatus()
|
||
{
|
||
if(!m_readFlag)
|
||
{
|
||
return ;
|
||
}
|
||
if(m_act == (int)E_ALARM_VOICE) //语音告警无需检测
|
||
{
|
||
return ;
|
||
}
|
||
if(!m_bChange)
|
||
{
|
||
//< 不重新构造可能不能正常播放
|
||
if(m_pMediaPlayer)
|
||
{
|
||
m_pMediaPlayer->disconnect();
|
||
m_pMediaPlayer->stop();
|
||
delete m_pMediaPlayer;
|
||
m_pMediaPlayer = Q_NULLPTR;
|
||
}
|
||
m_bHaveValidAudioDev = true;
|
||
initPlayer();
|
||
updateAudioCuesPlayer();
|
||
}
|
||
m_bChange = false;
|
||
}
|