CAudioPlayerProc.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. #include "CAudioPlayerProc.h"
  2. #include <QFile>
  3. //#include <mmsystem.h>
  4. #include <mmdeviceapi.h>
  5. #include <endpointvolume.h>
  6. #include <audioclient.h>
  7. #include <QFileInfo>
  8. #include "MediaInfoDLL.h"
  9. #define DITHER_FLAG (1) /**/
  10. /* Select sample format. */
  11. #if 0
  12. #define PA_SAMPLE_TYPE paFloat32
  13. typedef float SAMPLE;
  14. #define SAMPLE_SILENCE (0.0f)
  15. #define PRINTF_S_FORMAT "%.8f"
  16. #elif 1
  17. #define PA_SAMPLE_TYPE paInt16
  18. typedef short SAMPLE;
  19. #define SAMPLE_SILENCE (0)
  20. #define PRINTF_S_FORMAT "%d"
  21. #elif 2
  22. #define PA_SAMPLE_TYPE paInt8
  23. typedef char SAMPLE;
  24. #define SAMPLE_SILENCE (0)
  25. #define PRINTF_S_FORMAT "%d"
  26. #else
  27. #define PA_SAMPLE_TYPE paUInt8
  28. typedef unsigned char SAMPLE;
  29. #define SAMPLE_SILENCE (128)
  30. #define PRINTF_S_FORMAT "%d"
  31. #endif
  32. int CAudioPlayerProc::SAMPLE_RATE = 16000;//采样率
  33. int CAudioPlayerProc::NUM_CHANNELS = 1; //通道
  34. int CAudioPlayerProc::FRAMES_PER_BUFFER = (SAMPLE_RATE/10);
  35. CAudioPlayerProc* CAudioPlayerProc::pThis = NULL;
  36. int CAudioPlayerProc::m_Vol = 0;
  37. std::shared_ptr<CAudioPlayerProc> g_audioPalyerPtr = nullptr;
  38. CAudioPlayerProc::CAudioPlayerProc(QObject *parent) : QObject(parent)
  39. {
  40. std::string device = "default";
  41. m_mic.LinkToDevice(device);
  42. setHeadSetVol(100);
  43. setMicVol(100);
  44. m_Vol = 100;
  45. pThis = this;
  46. m_pAudioPlayer = new QMediaPlayer(this);
  47. }
  48. CAudioPlayerProc::~CAudioPlayerProc()
  49. {
  50. delete m_pAudioPlayer;
  51. m_pAudioPlayer = nullptr;
  52. }
  53. void CAudioPlayerProc::onMetaDataAvailableChanged(bool available)
  54. {
  55. if (available)
  56. {
  57. foreach(QString str, m_pAudioPlayer->availableMetaData())
  58. {
  59. qDebug()<<str<<" :"<<m_pAudioPlayer->metaData(str).toString().toUtf8().data();
  60. }
  61. qint64 time = m_pAudioPlayer->metaData("Duration").toInt();
  62. QString str = QString("%1").arg((time+999)/1000);
  63. int m_nAudioSecond = (time+999)/1000;
  64. emit durationChange(m_nAudioSecond);
  65. }
  66. }
  67. int CAudioPlayerProc::GetMediaDuration(QString sAudio)
  68. {
  69. QFileInfo fileInfo(sAudio);
  70. MediaInfoDLL::MediaInfo MI;
  71. QString filepath = fileInfo.absoluteFilePath();
  72. MI.Open(filepath.toStdWString());
  73. int nDuration = (QString::fromStdWString((std::basic_string<wchar_t>)MI.Get(MediaInfoDLL::stream_t::Stream_Audio, 0, __T("Duration"))).toLong()+999)/1000;
  74. MI.Close();
  75. return nDuration;
  76. }
  77. void CAudioPlayerProc::setAudio(QString sAudio)
  78. {
  79. m_pAudioPlayer->setMedia(QUrl::fromLocalFile(sAudio));
  80. }
  81. int CAudioPlayerProc::playAudio(QString sAudio, bool IsRepeat)
  82. {
  83. if(IsRepeat)
  84. {
  85. m_playlist.clear();
  86. m_playlist.addMedia(QUrl(sAudio));
  87. m_playlist.setCurrentIndex(1);
  88. m_playlist.setPlaybackMode(QMediaPlaylist::CurrentItemInLoop);
  89. m_pAudioPlayer->setPlaylist(&m_playlist);
  90. m_pAudioPlayer->play();
  91. }
  92. else
  93. {
  94. m_pAudioPlayer->setMedia(QUrl::fromLocalFile(sAudio));
  95. m_pAudioPlayer->play();
  96. }
  97. qDebug()<<m_pAudioPlayer->duration();
  98. return (m_pAudioPlayer->duration()+999)/1000;
  99. }
  100. void CAudioPlayerProc::stopPlay()
  101. {
  102. m_pAudioPlayer->stop();
  103. }
  104. void CAudioPlayerProc::pausePlay()
  105. {
  106. m_pAudioPlayer->pause();
  107. }
  108. void CAudioPlayerProc::play()
  109. {
  110. m_pAudioPlayer->play();
  111. }
  112. void CAudioPlayerProc::setVol(int vol)
  113. {
  114. if(vol > 100)
  115. {
  116. vol = 100;
  117. }
  118. if(vol < 0)
  119. {
  120. vol= 0;
  121. }
  122. m_pAudioPlayer->setVolume(vol);
  123. m_Vol = vol;
  124. }
  125. //设置系统麦克风音量
  126. void CAudioPlayerProc::setMicVol(int nVol)
  127. {
  128. m_mic.SetVolume(nVol/100.0);
  129. }
  130. //设置系统音量
  131. void CAudioPlayerProc::setHeadSetVol(int nVol)
  132. {
  133. HRESULT hr;
  134. IMMDeviceEnumerator* pDeviceEnumerator=0;
  135. IMMDevice* pDevice=0;
  136. IAudioEndpointVolume* pAudioEndpointVolume=0;
  137. IAudioClient* pAudioClient=0;
  138. try
  139. {
  140. hr = CoCreateInstance(__uuidof(MMDeviceEnumerator),NULL,CLSCTX_ALL,__uuidof(IMMDeviceEnumerator),(void**)&pDeviceEnumerator);
  141. if(FAILED(hr)) throw "CoCreateInstance";
  142. hr = pDeviceEnumerator->GetDefaultAudioEndpoint(eRender,eMultimedia,&pDevice);
  143. if(FAILED(hr)) throw "GetDefaultAudioEndpoint";
  144. hr = pDevice->Activate(__uuidof(IAudioEndpointVolume),CLSCTX_ALL,NULL,(void**)&pAudioEndpointVolume);
  145. if(FAILED(hr)) throw "pDevice->Active";
  146. hr = pDevice->Activate(__uuidof(IAudioClient),CLSCTX_ALL,NULL,(void**)&pAudioClient);
  147. if(FAILED(hr)) throw "pDevice->Active";
  148. float fVolume;
  149. fVolume = nVol/100.0f;
  150. hr = pAudioEndpointVolume->SetMasterVolumeLevelScalar(fVolume,&GUID_NULL);
  151. if(FAILED(hr)) throw "SetMasterVolumeLevelScalar";
  152. pAudioClient->Release();
  153. pAudioEndpointVolume->Release();
  154. pDevice->Release();
  155. pDeviceEnumerator->Release();
  156. }
  157. catch(...)
  158. {
  159. if(pAudioClient) pAudioClient->Release();
  160. if(pAudioEndpointVolume) pAudioEndpointVolume->Release();
  161. if(pDevice) pDevice->Release();
  162. if(pDeviceEnumerator) pDeviceEnumerator->Release();
  163. }
  164. }
  165. bool CAudioPlayerProc::getDeviceinfo(std::string &sName)
  166. {
  167. PaError err = Pa_Initialize();
  168. if( err != paNoError )
  169. {
  170. Pa_Terminate();
  171. m_sErrMsg = QString::fromLocal8Bit(PaGetErrorText(err));
  172. fclose(m_RawFile);
  173. return false;
  174. }
  175. m_inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */
  176. if (m_inputParameters.device == paNoDevice)
  177. {
  178. Pa_Terminate();
  179. m_sErrMsg = QString::fromLocal8Bit("系统无默认录音设备,请检查耳机是否插好!");
  180. return false;
  181. }
  182. const PaDeviceInfo *painfo = Pa_GetDeviceInfo(m_inputParameters.device );
  183. sName = painfo->name;
  184. Pa_Terminate();
  185. return true;
  186. }
  187. bool CAudioPlayerProc::startRecord(std::string sFile)
  188. {
  189. QFile file(sFile.c_str());
  190. if(file.exists())
  191. {
  192. file.remove();
  193. }
  194. m_RawFile = fopen(sFile.c_str(), "wb");
  195. if( m_RawFile == NULL )
  196. {
  197. m_sErrMsg = QString::fromLocal8Bit("创建录音文件失败!,");
  198. return false;
  199. }
  200. fseek(m_RawFile, sizeof(HEADER) + sizeof(FMT) +sizeof(DATA) ,SEEK_SET);
  201. PaError err = Pa_Initialize();
  202. if( err != paNoError )
  203. {
  204. Pa_Terminate();
  205. m_sErrMsg = QString::fromLocal8Bit(PaGetErrorText( err ));
  206. fclose(m_RawFile);
  207. return false;
  208. }
  209. m_inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */
  210. if (m_inputParameters.device == paNoDevice)
  211. {
  212. Pa_Terminate();
  213. fclose(m_RawFile);
  214. m_sErrMsg = QString::fromLocal8Bit("系统无默认录音设备,请检查耳机是否插好!");
  215. return false;
  216. }
  217. m_inputParameters.channelCount = NUM_CHANNELS;
  218. m_inputParameters.sampleFormat = PA_SAMPLE_TYPE;
  219. m_inputParameters.suggestedLatency = Pa_GetDeviceInfo( m_inputParameters.device )->defaultLowInputLatency;
  220. m_inputParameters.hostApiSpecificStreamInfo = NULL;
  221. err = Pa_OpenStream(
  222. &m_stream,
  223. &m_inputParameters,
  224. NULL, /* &outputParameters, */
  225. SAMPLE_RATE,
  226. FRAMES_PER_BUFFER,
  227. paClipOff, /* we won't output out of range samples so don't bother clipping them */
  228. recordCb, /* no callback, use blocking API */
  229. NULL ); /* no callback, so no callback userData */
  230. if( err != paNoError )
  231. {
  232. Pa_Terminate();
  233. fclose(m_RawFile);
  234. m_sErrMsg = QString::fromLocal8Bit(PaGetErrorText( err ));
  235. return false;
  236. }
  237. err = Pa_StartStream( m_stream );
  238. if( err != paNoError )
  239. {
  240. Pa_Terminate();
  241. fclose(m_RawFile);
  242. m_sErrMsg = QString::fromLocal8Bit(PaGetErrorText( err ));
  243. return false;
  244. }
  245. return true;
  246. }
  247. void CAudioPlayerProc::setWavHead()
  248. {
  249. HEADER pcmHEADER;
  250. FMT pcmFMT;
  251. DATA pcmDATA;
  252. memset(&pcmHEADER, 0, sizeof(HEADER));
  253. memset(&pcmFMT, 0, sizeof(FMT));
  254. memset(&pcmDATA, 0, sizeof(DATA));
  255. memcpy(pcmHEADER.fccID,"RIFF", 4);
  256. memcpy(pcmHEADER.fccType,"WAVE", 4);
  257. fseek(m_RawFile, 0,SEEK_END);
  258. int nsize = ftell(m_RawFile);
  259. pcmHEADER.dwSize = nsize - 8;
  260. fseek(m_RawFile, 0, SEEK_SET);
  261. fwrite(&pcmHEADER,sizeof(HEADER),1,m_RawFile);
  262. //以下是创建wav头的FMT;
  263. pcmFMT.dwSamplesPerSec = SAMPLE_RATE;
  264. pcmFMT.wChannels = NUM_CHANNELS;
  265. pcmFMT.uiBitsPerSample = sizeof(SAMPLE)*8;
  266. pcmFMT.dwAvgBytesPerSec =
  267. (pcmFMT.uiBitsPerSample*pcmFMT.wChannels*pcmFMT.dwSamplesPerSec)/8;
  268. memcpy(pcmFMT.fccID,"fmt ", 4);
  269. pcmFMT.dwSize= 16;
  270. pcmFMT.wBlockAlign = (pcmFMT.uiBitsPerSample*pcmFMT.wChannels)/8;
  271. pcmFMT.wFormatTag = 1;
  272. //以上是创建wav头的FMT;
  273. fwrite(&pcmFMT,sizeof(FMT),1,m_RawFile); //将FMT写入.wav文件;
  274. //以下是创建wav头的DATA; 但由于DATA.dwsize未知所以不能写入.wav文件
  275. memcpy(pcmDATA.fccID,"data", 4);
  276. pcmDATA.dwSize = nsize - 44; //给pcmDATA.dwsize 0以便于下面给它赋值
  277. fwrite(&pcmDATA,sizeof(DATA),1,m_RawFile);
  278. }
  279. int CAudioPlayerProc::recordCb(
  280. const void *input, void *output,
  281. unsigned long frameCount,
  282. const PaStreamCallbackTimeInfo* timeInfo,
  283. PaStreamCallbackFlags statusFlags,
  284. void *userData )
  285. {
  286. /* Write recorded data to a file. */
  287. short *pData = new short[frameCount];
  288. memcpy(pData, input, 2*frameCount);
  289. short *pTemp = pData;
  290. float db=96*m_Vol/100-96;
  291. float multiplier = pow(10,db/20);
  292. for(unsigned long i = 0; i < frameCount; i++)
  293. {
  294. // *pTemp = (*pTemp)*pow(10,m_Vol/256.0);
  295. *pTemp = (*pTemp)*multiplier;
  296. if (*pTemp > 32767) {
  297. *pTemp = 32767;
  298. }else if (*pTemp < -32768) {
  299. *pTemp = -32768;
  300. }
  301. pTemp++;
  302. }
  303. fwrite( (char*)pData, NUM_CHANNELS * sizeof(SAMPLE), frameCount, pThis->m_RawFile);
  304. pThis->calcVol(pData, frameCount);
  305. return paContinue;
  306. }
  307. void CAudioPlayerProc::calcVol(short *pData, int nsize)
  308. {
  309. __int64 nTotalVol = 0;
  310. short *pTemp = pData;
  311. for(int i = 0; i < nsize; i++)
  312. {
  313. nTotalVol += (*pTemp)*(*pTemp);
  314. pTemp++;
  315. }
  316. //int nAvgVol = nTotalVol/nsize;
  317. int nAvgVol = nTotalVol/nsize;
  318. int ndb = 0;
  319. if(nAvgVol != 0)
  320. {
  321. ndb = (int)(10.0*log10((double)nAvgVol ));
  322. }
  323. else
  324. {
  325. ndb = 0;
  326. }
  327. delete [] pData;
  328. emit audioLoud(ndb);
  329. }
  330. bool CAudioPlayerProc::stopRecord()
  331. {
  332. Pa_StopStream(m_stream);
  333. PaError err = Pa_CloseStream( m_stream );
  334. if( err != paNoError )
  335. {
  336. Pa_Terminate();
  337. fclose(m_RawFile);
  338. m_sErrMsg = QString::fromLocal8Bit(PaGetErrorText(err));
  339. return false;
  340. }
  341. Pa_Terminate();
  342. setWavHead();
  343. fclose(m_RawFile);
  344. return true;
  345. }
  346. bool CAudioPlayerProc::isRecording()
  347. {
  348. PaError err;
  349. if( ( err = Pa_IsStreamActive(m_stream)) == 1 )
  350. {
  351. return true;
  352. }
  353. else
  354. {
  355. const PaHostErrorInfo *perr = Pa_GetLastHostErrorInfo() ;
  356. m_sErrMsg = QString::fromLocal8Bit(perr->errorText);
  357. if(perr->errorCode == 6)
  358. {
  359. m_sErrMsg = QString::fromLocal8Bit("无录音设备,请检查耳机是否插好!");
  360. }
  361. Pa_Terminate();
  362. fclose(m_RawFile);
  363. return false;
  364. }
  365. }
  366. QString CAudioPlayerProc::getErrMsg()
  367. {
  368. return m_sErrMsg;
  369. }
  370. const char* CAudioPlayerProc::PaGetErrorText( int errorCode )
  371. {
  372. const char *result;
  373. switch( errorCode )
  374. {
  375. case paNoError: result = "成功"; break;
  376. case paNotInitialized: result = "音频SDK没有初始化"; break;
  377. /** @todo could catenate the last host error text to result in the case of paUnanticipatedHostError */
  378. case paUnanticipatedHostError: result = "未知的主机错误"; break;
  379. case paInvalidChannelCount: result = "无效的频道"; break;
  380. case paInvalidSampleRate: result = "无效的采样率"; break;
  381. case paInvalidDevice: result = "无录音设备,请检查耳机是否插好!"; break;
  382. case paInvalidFlag: result = "无效标志"; break;
  383. case paSampleFormatNotSupported: result = "采样格式不支持"; break;
  384. case paBadIODeviceCombination: result = "输入/输出设备的非法组合"; break;
  385. case paInsufficientMemory: result = "内存不足"; break;
  386. case paBufferTooBig: result = "缓冲太大"; break;
  387. case paBufferTooSmall: result = "缓冲太小"; break;
  388. case paNullCallback: result = "未指定回调例程"; break;
  389. case paBadStreamPtr: result = "无效的流指针"; break;
  390. case paTimedOut: result = "等待超时"; break;
  391. case paInternalError: result = "音频SDK内部错误"; break;
  392. case paDeviceUnavailable: result = "设备不可用"; break;
  393. case paIncompatibleHostApiSpecificStreamInfo: result = "主机API特定流信息不兼容"; break;
  394. case paStreamIsStopped: result = "数据流停止了"; break;
  395. case paStreamIsNotStopped: result = "数据流未停止"; break;
  396. case paInputOverflowed: result = "输入溢出"; break;
  397. case paOutputUnderflowed: result = "输出不足"; break;
  398. case paHostApiNotFound: result = "没有发现主机API"; break;
  399. case paInvalidHostApi: result = "主机API无效"; break;
  400. case paCanNotReadFromACallbackStream: result = "无法从回调流中读取"; break;
  401. case paCanNotWriteToACallbackStream: result = "无法向回调流中写入"; break;
  402. case paCanNotReadFromAnOutputOnlyStream: result = "无法从仅输出的流中读取"; break;
  403. case paCanNotWriteToAnInputOnlyStream: result = "无法向仅输入流写入"; break;
  404. default:
  405. if( errorCode > 0 )
  406. result = "无效的错误代码(值大于零)";
  407. else
  408. result = "无效的错误代码";
  409. break;
  410. }
  411. return result;
  412. }