HM-SPMS/product/src/gui/plugin/AlarmWidget_pad/CAlarmMediaPlayer.cpp

593 lines
16 KiB
C++
Raw Normal View History

2025-03-17 16:59:30 +08:00

#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;
}