#include "CAudioPlayerProc.h" #include //#include #include #include #include #include #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 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()<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)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()<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; }