123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458 |
- #include "CAudioPlayerProc.h"
- #include <QFile>
- //#include <mmsystem.h>
- #include <mmdeviceapi.h>
- #include <endpointvolume.h>
- #include <audioclient.h>
- #include <QFileInfo>
- #include "MediaInfoDLL.h"
- #define DITHER_FLAG (1) /**/
- /* Select sample format. */
- #if 0
- #define PA_SAMPLE_TYPE paFloat32
- typedef float SAMPLE;
- #define SAMPLE_SILENCE (0.0f)
- #define PRINTF_S_FORMAT "%.8f"
- #elif 1
- #define PA_SAMPLE_TYPE paInt16
- typedef short SAMPLE;
- #define SAMPLE_SILENCE (0)
- #define PRINTF_S_FORMAT "%d"
- #elif 2
- #define PA_SAMPLE_TYPE paInt8
- typedef char SAMPLE;
- #define SAMPLE_SILENCE (0)
- #define PRINTF_S_FORMAT "%d"
- #else
- #define PA_SAMPLE_TYPE paUInt8
- typedef unsigned char SAMPLE;
- #define SAMPLE_SILENCE (128)
- #define PRINTF_S_FORMAT "%d"
- #endif
- int CAudioPlayerProc::SAMPLE_RATE = 16000;//采样率
- int CAudioPlayerProc::NUM_CHANNELS = 1; //通道
- int CAudioPlayerProc::FRAMES_PER_BUFFER = (SAMPLE_RATE/10);
- CAudioPlayerProc* CAudioPlayerProc::pThis = NULL;
- int CAudioPlayerProc::m_Vol = 0;
- std::shared_ptr<CAudioPlayerProc> g_audioPalyerPtr = nullptr;
- CAudioPlayerProc::CAudioPlayerProc(QObject *parent) : QObject(parent)
- {
- std::string device = "default";
- m_mic.LinkToDevice(device);
- setHeadSetVol(100);
- setMicVol(100);
- m_Vol = 100;
- pThis = this;
- m_pAudioPlayer = new QMediaPlayer(this);
- }
- CAudioPlayerProc::~CAudioPlayerProc()
- {
- delete m_pAudioPlayer;
- m_pAudioPlayer = nullptr;
- }
- void CAudioPlayerProc::onMetaDataAvailableChanged(bool available)
- {
- if (available)
- {
- foreach(QString str, m_pAudioPlayer->availableMetaData())
- {
- qDebug()<<str<<" :"<<m_pAudioPlayer->metaData(str).toString().toUtf8().data();
- }
- qint64 time = m_pAudioPlayer->metaData("Duration").toInt();
- QString str = QString("%1").arg((time+999)/1000);
- int m_nAudioSecond = (time+999)/1000;
- emit durationChange(m_nAudioSecond);
- }
- }
- int CAudioPlayerProc::GetMediaDuration(QString sAudio)
- {
- QFileInfo fileInfo(sAudio);
- MediaInfoDLL::MediaInfo MI;
- QString filepath = fileInfo.absoluteFilePath();
- MI.Open(filepath.toStdWString());
- int nDuration = (QString::fromStdWString((std::basic_string<wchar_t>)MI.Get(MediaInfoDLL::stream_t::Stream_Audio, 0, __T("Duration"))).toLong()+999)/1000;
- MI.Close();
- return nDuration;
- }
- void CAudioPlayerProc::setAudio(QString sAudio)
- {
- m_pAudioPlayer->setMedia(QUrl::fromLocalFile(sAudio));
- }
- int CAudioPlayerProc::playAudio(QString sAudio, bool IsRepeat)
- {
- if(IsRepeat)
- {
- m_playlist.clear();
- m_playlist.addMedia(QUrl(sAudio));
- m_playlist.setCurrentIndex(1);
- m_playlist.setPlaybackMode(QMediaPlaylist::CurrentItemInLoop);
- m_pAudioPlayer->setPlaylist(&m_playlist);
- m_pAudioPlayer->play();
- }
- else
- {
- m_pAudioPlayer->setMedia(QUrl::fromLocalFile(sAudio));
- m_pAudioPlayer->play();
- }
- qDebug()<<m_pAudioPlayer->duration();
- return (m_pAudioPlayer->duration()+999)/1000;
- }
- void CAudioPlayerProc::stopPlay()
- {
- m_pAudioPlayer->stop();
- }
- void CAudioPlayerProc::pausePlay()
- {
- m_pAudioPlayer->pause();
- }
- void CAudioPlayerProc::play()
- {
- m_pAudioPlayer->play();
- }
- void CAudioPlayerProc::setVol(int vol)
- {
- if(vol > 100)
- {
- vol = 100;
- }
- if(vol < 0)
- {
- vol= 0;
- }
- m_pAudioPlayer->setVolume(vol);
- m_Vol = vol;
- }
- //设置系统麦克风音量
- void CAudioPlayerProc::setMicVol(int nVol)
- {
- m_mic.SetVolume(nVol/100.0);
- }
- //设置系统音量
- void CAudioPlayerProc::setHeadSetVol(int nVol)
- {
- HRESULT hr;
- IMMDeviceEnumerator* pDeviceEnumerator=0;
- IMMDevice* pDevice=0;
- IAudioEndpointVolume* pAudioEndpointVolume=0;
- IAudioClient* pAudioClient=0;
- try
- {
- hr = CoCreateInstance(__uuidof(MMDeviceEnumerator),NULL,CLSCTX_ALL,__uuidof(IMMDeviceEnumerator),(void**)&pDeviceEnumerator);
- if(FAILED(hr)) throw "CoCreateInstance";
- hr = pDeviceEnumerator->GetDefaultAudioEndpoint(eRender,eMultimedia,&pDevice);
- if(FAILED(hr)) throw "GetDefaultAudioEndpoint";
- hr = pDevice->Activate(__uuidof(IAudioEndpointVolume),CLSCTX_ALL,NULL,(void**)&pAudioEndpointVolume);
- if(FAILED(hr)) throw "pDevice->Active";
- hr = pDevice->Activate(__uuidof(IAudioClient),CLSCTX_ALL,NULL,(void**)&pAudioClient);
- if(FAILED(hr)) throw "pDevice->Active";
- float fVolume;
- fVolume = nVol/100.0f;
- hr = pAudioEndpointVolume->SetMasterVolumeLevelScalar(fVolume,&GUID_NULL);
- if(FAILED(hr)) throw "SetMasterVolumeLevelScalar";
- pAudioClient->Release();
- pAudioEndpointVolume->Release();
- pDevice->Release();
- pDeviceEnumerator->Release();
- }
- catch(...)
- {
- if(pAudioClient) pAudioClient->Release();
- if(pAudioEndpointVolume) pAudioEndpointVolume->Release();
- if(pDevice) pDevice->Release();
- if(pDeviceEnumerator) pDeviceEnumerator->Release();
- }
- }
- bool CAudioPlayerProc::getDeviceinfo(std::string &sName)
- {
- PaError err = Pa_Initialize();
- if( err != paNoError )
- {
- Pa_Terminate();
- m_sErrMsg = QString::fromLocal8Bit(PaGetErrorText(err));
- fclose(m_RawFile);
- return false;
- }
- m_inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */
- if (m_inputParameters.device == paNoDevice)
- {
- Pa_Terminate();
- m_sErrMsg = QString::fromLocal8Bit("系统无默认录音设备,请检查耳机是否插好!");
- return false;
- }
- const PaDeviceInfo *painfo = Pa_GetDeviceInfo(m_inputParameters.device );
- sName = painfo->name;
- Pa_Terminate();
- return true;
- }
- bool CAudioPlayerProc::startRecord(std::string sFile)
- {
- QFile file(sFile.c_str());
- if(file.exists())
- {
- file.remove();
- }
- m_RawFile = fopen(sFile.c_str(), "wb");
- if( m_RawFile == NULL )
- {
- m_sErrMsg = QString::fromLocal8Bit("创建录音文件失败!,");
- return false;
- }
- fseek(m_RawFile, sizeof(HEADER) + sizeof(FMT) +sizeof(DATA) ,SEEK_SET);
- PaError err = Pa_Initialize();
- if( err != paNoError )
- {
- Pa_Terminate();
- m_sErrMsg = QString::fromLocal8Bit(PaGetErrorText( err ));
- fclose(m_RawFile);
- return false;
- }
- m_inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */
- if (m_inputParameters.device == paNoDevice)
- {
- Pa_Terminate();
- fclose(m_RawFile);
- m_sErrMsg = QString::fromLocal8Bit("系统无默认录音设备,请检查耳机是否插好!");
- return false;
- }
- m_inputParameters.channelCount = NUM_CHANNELS;
- m_inputParameters.sampleFormat = PA_SAMPLE_TYPE;
- m_inputParameters.suggestedLatency = Pa_GetDeviceInfo( m_inputParameters.device )->defaultLowInputLatency;
- m_inputParameters.hostApiSpecificStreamInfo = NULL;
- err = Pa_OpenStream(
- &m_stream,
- &m_inputParameters,
- NULL, /* &outputParameters, */
- SAMPLE_RATE,
- FRAMES_PER_BUFFER,
- paClipOff, /* we won't output out of range samples so don't bother clipping them */
- recordCb, /* no callback, use blocking API */
- NULL ); /* no callback, so no callback userData */
- if( err != paNoError )
- {
- Pa_Terminate();
- fclose(m_RawFile);
- m_sErrMsg = QString::fromLocal8Bit(PaGetErrorText( err ));
- return false;
- }
- err = Pa_StartStream( m_stream );
- if( err != paNoError )
- {
- Pa_Terminate();
- fclose(m_RawFile);
- m_sErrMsg = QString::fromLocal8Bit(PaGetErrorText( err ));
- return false;
- }
- return true;
- }
- void CAudioPlayerProc::setWavHead()
- {
- HEADER pcmHEADER;
- FMT pcmFMT;
- DATA pcmDATA;
- memset(&pcmHEADER, 0, sizeof(HEADER));
- memset(&pcmFMT, 0, sizeof(FMT));
- memset(&pcmDATA, 0, sizeof(DATA));
- memcpy(pcmHEADER.fccID,"RIFF", 4);
- memcpy(pcmHEADER.fccType,"WAVE", 4);
- fseek(m_RawFile, 0,SEEK_END);
- int nsize = ftell(m_RawFile);
- pcmHEADER.dwSize = nsize - 8;
- fseek(m_RawFile, 0, SEEK_SET);
- fwrite(&pcmHEADER,sizeof(HEADER),1,m_RawFile);
- //以下是创建wav头的FMT;
- pcmFMT.dwSamplesPerSec = SAMPLE_RATE;
- pcmFMT.wChannels = NUM_CHANNELS;
- pcmFMT.uiBitsPerSample = sizeof(SAMPLE)*8;
- pcmFMT.dwAvgBytesPerSec =
- (pcmFMT.uiBitsPerSample*pcmFMT.wChannels*pcmFMT.dwSamplesPerSec)/8;
- memcpy(pcmFMT.fccID,"fmt ", 4);
- pcmFMT.dwSize= 16;
- pcmFMT.wBlockAlign = (pcmFMT.uiBitsPerSample*pcmFMT.wChannels)/8;
- pcmFMT.wFormatTag = 1;
- //以上是创建wav头的FMT;
- fwrite(&pcmFMT,sizeof(FMT),1,m_RawFile); //将FMT写入.wav文件;
- //以下是创建wav头的DATA; 但由于DATA.dwsize未知所以不能写入.wav文件
- memcpy(pcmDATA.fccID,"data", 4);
- pcmDATA.dwSize = nsize - 44; //给pcmDATA.dwsize 0以便于下面给它赋值
- fwrite(&pcmDATA,sizeof(DATA),1,m_RawFile);
- }
- int CAudioPlayerProc::recordCb(
- const void *input, void *output,
- unsigned long frameCount,
- const PaStreamCallbackTimeInfo* timeInfo,
- PaStreamCallbackFlags statusFlags,
- void *userData )
- {
- /* Write recorded data to a file. */
- short *pData = new short[frameCount];
- memcpy(pData, input, 2*frameCount);
- short *pTemp = pData;
- float db=96*m_Vol/100-96;
- float multiplier = pow(10,db/20);
- for(unsigned long i = 0; i < frameCount; i++)
- {
- // *pTemp = (*pTemp)*pow(10,m_Vol/256.0);
- *pTemp = (*pTemp)*multiplier;
- if (*pTemp > 32767) {
- *pTemp = 32767;
- }else if (*pTemp < -32768) {
- *pTemp = -32768;
- }
- pTemp++;
- }
- fwrite( (char*)pData, NUM_CHANNELS * sizeof(SAMPLE), frameCount, pThis->m_RawFile);
- pThis->calcVol(pData, frameCount);
- return paContinue;
- }
- void CAudioPlayerProc::calcVol(short *pData, int nsize)
- {
- __int64 nTotalVol = 0;
- short *pTemp = pData;
- for(int i = 0; i < nsize; i++)
- {
- nTotalVol += (*pTemp)*(*pTemp);
- pTemp++;
- }
- //int nAvgVol = nTotalVol/nsize;
- int nAvgVol = nTotalVol/nsize;
- int ndb = 0;
- if(nAvgVol != 0)
- {
- ndb = (int)(10.0*log10((double)nAvgVol ));
- }
- else
- {
- ndb = 0;
- }
- delete [] pData;
- emit audioLoud(ndb);
- }
- bool CAudioPlayerProc::stopRecord()
- {
- Pa_StopStream(m_stream);
- PaError err = Pa_CloseStream( m_stream );
- if( err != paNoError )
- {
- Pa_Terminate();
- fclose(m_RawFile);
- m_sErrMsg = QString::fromLocal8Bit(PaGetErrorText(err));
- return false;
- }
- Pa_Terminate();
- setWavHead();
- fclose(m_RawFile);
- return true;
- }
- bool CAudioPlayerProc::isRecording()
- {
- PaError err;
- if( ( err = Pa_IsStreamActive(m_stream)) == 1 )
- {
- return true;
- }
- else
- {
- const PaHostErrorInfo *perr = Pa_GetLastHostErrorInfo() ;
- m_sErrMsg = QString::fromLocal8Bit(perr->errorText);
- if(perr->errorCode == 6)
- {
- m_sErrMsg = QString::fromLocal8Bit("无录音设备,请检查耳机是否插好!");
- }
- Pa_Terminate();
- fclose(m_RawFile);
- return false;
- }
- }
- QString CAudioPlayerProc::getErrMsg()
- {
- return m_sErrMsg;
- }
- const char* CAudioPlayerProc::PaGetErrorText( int errorCode )
- {
- const char *result;
- switch( errorCode )
- {
- case paNoError: result = "成功"; break;
- case paNotInitialized: result = "音频SDK没有初始化"; break;
- /** @todo could catenate the last host error text to result in the case of paUnanticipatedHostError */
- case paUnanticipatedHostError: result = "未知的主机错误"; break;
- case paInvalidChannelCount: result = "无效的频道"; break;
- case paInvalidSampleRate: result = "无效的采样率"; break;
- case paInvalidDevice: result = "无录音设备,请检查耳机是否插好!"; break;
- case paInvalidFlag: result = "无效标志"; break;
- case paSampleFormatNotSupported: result = "采样格式不支持"; break;
- case paBadIODeviceCombination: result = "输入/输出设备的非法组合"; break;
- case paInsufficientMemory: result = "内存不足"; break;
- case paBufferTooBig: result = "缓冲太大"; break;
- case paBufferTooSmall: result = "缓冲太小"; break;
- case paNullCallback: result = "未指定回调例程"; break;
- case paBadStreamPtr: result = "无效的流指针"; break;
- case paTimedOut: result = "等待超时"; break;
- case paInternalError: result = "音频SDK内部错误"; break;
- case paDeviceUnavailable: result = "设备不可用"; break;
- case paIncompatibleHostApiSpecificStreamInfo: result = "主机API特定流信息不兼容"; break;
- case paStreamIsStopped: result = "数据流停止了"; break;
- case paStreamIsNotStopped: result = "数据流未停止"; break;
- case paInputOverflowed: result = "输入溢出"; break;
- case paOutputUnderflowed: result = "输出不足"; break;
- case paHostApiNotFound: result = "没有发现主机API"; break;
- case paInvalidHostApi: result = "主机API无效"; break;
- case paCanNotReadFromACallbackStream: result = "无法从回调流中读取"; break;
- case paCanNotWriteToACallbackStream: result = "无法向回调流中写入"; break;
- case paCanNotReadFromAnOutputOnlyStream: result = "无法从仅输出的流中读取"; break;
- case paCanNotWriteToAnInputOnlyStream: result = "无法向仅输入流写入"; break;
- default:
- if( errorCode > 0 )
- result = "无效的错误代码(值大于零)";
- else
- result = "无效的错误代码";
- break;
- }
- return result;
- }
|