#ifdef OS_WINDOWS //< 为了检测可用声卡 #include #include #endif #include #include #include #include #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 locales = m_pTextToSpeech->availableLocales(); if(!m_language.isEmpty()) { foreach (const QLocale &locale, locales) { if (locale.name() == m_language) { m_pTextToSpeech->setLocale(locale); break; } } } QVector 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 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; }