123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788 |
- #include "precompile.h"
- #include "audiomicspk.h"
- #include "audiomicspk3.h"
- #include "audiocontext.h"
- #include <assert.h>
- #include "audiolog.h"
- #include "./other/delaybuf.h"
- #include <dmo.h>
- #include <Mmsystem.h>
- #include <objbase.h>
- #include <mediaobj.h>
- #include <uuids.h>
- #include <propidl.h>
- #include <wmcodecdsp.h>
- #include <audioclient.h>
- #include <MMDeviceApi.h>
- #include <AudioEngineEndPoint.h>
- #include <DeviceTopology.h>
- #include <EndpointVolume.h>
- #include <functiondiscoverykeys.h>
- #include <portaudio.h>
- #define CLOCK_PERIOD 30
- #define MAX_STR_LEN 512
- #define AUDIO_CLOCK 8000
- #define MAX_DELAY 100
- #define MS_REF_TICK 10000
- // play use portaudio
- typedef struct tagAUDIO_DEVICE_INFO
- {
- char szDeviceName[MAX_STR_LEN];
- char szDeviceID[MAX_STR_LEN];
- } AUDIO_DEVICE_INFO, *PAUDIO_DEVICE_INFO;
- static HRESULT GetDeviceNum(EDataFlow eDataFlow, UINT *uDevCount)
- {
- IMMDeviceEnumerator *pEnumerator = NULL;
- IMMDeviceCollection *pEndpoints = NULL;
- HRESULT hr;
- hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, (void**)&pEnumerator);
- if (FAILED(hr))
- goto on_error;
- hr = pEnumerator->lpVtbl->EnumAudioEndpoints(pEnumerator, eDataFlow, DEVICE_STATE_ACTIVE, (void**)&pEndpoints);
- if (FAILED(hr))
- goto on_error;
- hr = pEndpoints->lpVtbl->GetCount(pEndpoints, uDevCount);
- if (FAILED(hr))
- goto on_error;
- on_error:
- if (pEndpoints)
- pEndpoints->lpVtbl->Release(pEndpoints);
- if (pEnumerator)
- pEnumerator->lpVtbl->Release(pEnumerator);
- return hr;
- }
- static HRESULT EnumDevice(EDataFlow eDataFlow, UINT uNumElements, AUDIO_DEVICE_INFO *pDevicInfo)
- {
- IMMDeviceEnumerator *pEnumerator = NULL;
- IMMDeviceCollection *pEndpoints = NULL;
- HRESULT hr;
- UINT uCount;
- UINT uIdx;
- hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, (void**)&pEnumerator);
- if (FAILED(hr))
- goto on_error;
- hr = pEnumerator->lpVtbl->EnumAudioEndpoints(pEnumerator, eDataFlow, DEVICE_STATE_ACTIVE, (void**)&pEndpoints);
- if (FAILED(hr))
- goto on_error;
- hr = pEndpoints->lpVtbl->GetCount(pEndpoints, &uCount);
- if (FAILED(hr))
- goto on_error;
- ZeroMemory(pDevicInfo, sizeof(AUDIO_DEVICE_INFO)*uNumElements);
- for (uIdx = 0; uIdx < uCount && uIdx < uNumElements; ++uIdx) {
- IMMDevice *pDevice = NULL;
- IPropertyStore *pPS = NULL;
- WCHAR* pszDeviceId = NULL;
- PROPVARIANT value;
- PropVariantInit(&value);
- pEndpoints->lpVtbl->Item(pEndpoints, uIdx, &pDevice);
- pDevice->lpVtbl->GetId(pDevice, &pszDeviceId);
- pDevice->lpVtbl->OpenPropertyStore(pDevice, STGM_READ, &pPS);
- pPS->lpVtbl->GetValue(pPS, &PKEY_Device_FriendlyName, &value);
- WideCharToMultiByte(CP_ACP, 0, pszDeviceId, -1, pDevicInfo[uIdx].szDeviceID, MAX_STR_LEN-1, NULL, NULL);
- WideCharToMultiByte(CP_ACP, 0, value.pwszVal, -1, pDevicInfo[uIdx].szDeviceName, MAX_STR_LEN-1, NULL, NULL);
- PropVariantClear(&value);
- CoTaskMemFree(pszDeviceId);
- pPS->lpVtbl->Release(pPS);
- pDevice->lpVtbl->Release(pDevice);
- }
- on_error:
- if (pEndpoints)
- pEndpoints->lpVtbl->Release(pEndpoints);
- if (pEnumerator)
- pEnumerator->lpVtbl->Release(pEnumerator);
- return hr;
- }
- static HRESULT DeviceBindTo(
- EDataFlow eDataFlow, // eCapture/eRender
- INT iDevIdx, // Device Index. -1 - default device.
- IAudioClient **ppAudioClient, // pointer pointer to IAudioClient interface
- IAudioEndpointVolume **ppEndpointVolume
- )
- {
- IMMDeviceEnumerator *pEnumerator = NULL;
- IMMDeviceCollection *pEndpoints = NULL;
- IMMDevice *pDevice = NULL;
- HRESULT hr;
- hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, (void**)&pEnumerator);
- if (FAILED(hr))
- goto on_error;
- if (iDevIdx < 0) {
- hr = pEnumerator->lpVtbl->GetDefaultAudioEndpoint(pEnumerator, eDataFlow, eConsole, &pDevice);
- if (FAILED(hr))
- goto on_error;
- } else {
- hr = pEnumerator->lpVtbl->EnumAudioEndpoints(pEnumerator, eDataFlow, DEVICE_STATE_ACTIVE, (void**)&pEndpoints);
- if (FAILED(hr))
- goto on_error;
- hr = pEndpoints->lpVtbl->Item(pEndpoints, iDevIdx, &pDevice);
- if (FAILED(hr))
- goto on_error;
- }
- hr = pDevice->lpVtbl->Activate(pDevice, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, (void**)ppAudioClient);
- if (FAILED(hr))
- goto on_error;
- if (ppEndpointVolume) {
- hr = pDevice->lpVtbl->Activate(pDevice, &IID_IAudioEndpointVolume, CLSCTX_INPROC_SERVER, NULL, (void**)ppEndpointVolume);
- if (FAILED(hr)) {
- if (*ppAudioClient) {
- (*ppAudioClient)->lpVtbl->Release(*ppAudioClient);
- *ppAudioClient = NULL;
- }
- goto on_error;
- }
- }
- on_error:
- if (pDevice) {
- pDevice->lpVtbl->Release(pDevice);
- }
- if (pEndpoints) {
- pEndpoints->lpVtbl->Release(pEndpoints);
- }
- if (pEnumerator) {
- pEnumerator->lpVtbl->Release(pEnumerator);
- }
- return hr;
- }
- static int get_device_index(int indev, const char *key)
- {
- EDataFlow df = indev ? eCapture : eRender;
- UINT i;
- UINT n;
- AUDIO_DEVICE_INFO *pInfo = NULL;
- GetDeviceNum(df, &n);
- pInfo = malloc(sizeof(AUDIO_DEVICE_INFO) * n);
- EnumDevice(df, n, pInfo);
- for (i = 0; i < n; ++i) {
- if (strstr(pInfo[i].szDeviceName, key)) {
- free(pInfo);
- return i;
- }
- }
- free(pInfo);
- return -1;
- }
- static int get_device_index_poartaudio(int indev, const char *key)
- {
- int i;
- int n = Pa_GetDeviceCount();
- for (i = 0; i < n; ++i) {
- const PaDeviceInfo* pInfo = Pa_GetDeviceInfo(i);
- if (indev) {
- if (pInfo->maxInputChannels && strstr(pInfo->name, key))
- return i;
- } else {
- if (pInfo->maxOutputChannels && strstr(pInfo->name, key))
- return i;
- }
- }
- return -1;
- }
- static HRESULT CreateVoiceCaptureDMO(
- int spk_dev_id,
- int rec_dev_id,
- BOOL bNS,
- BOOL bAGC,
- IMediaObject *ppDMO)
- {
- HRESULT hr = S_OK;
- return hr;
- }
- typedef struct IMediaBufferImpl {
- struct IMediaBufferVtbl *lpVtbl;
- struct IMediaBufferVtbl vtbl;
- BYTE *m_pData;
- ULONG m_ulSize;
- ULONG m_ulData;
- ULONG m_cRef;
- }IMediaBufferImpl;
- static HRESULT STDMETHODCALLTYPE QueryInterface(IMediaBuffer * This, REFIID riid, void** ppvObject);
- static ULONG STDMETHODCALLTYPE AddRef(IMediaBuffer * This);
- static ULONG STDMETHODCALLTYPE Release(IMediaBuffer * This);
- static HRESULT STDMETHODCALLTYPE SetLength(IMediaBuffer * This, DWORD ulLength);
- static HRESULT STDMETHODCALLTYPE GetMaxLength(IMediaBuffer * This, DWORD *pcbMaxLength);
- static HRESULT STDMETHODCALLTYPE GetBufferAndLength(IMediaBuffer * This, BYTE **ppBuffer, DWORD *pcbLength);
- static void destroy_media_buffer(IMediaBufferImpl *pImpl)
- {
- free(pImpl->m_pData);
- free(pImpl);
- }
- static IMediaBuffer *create_media_buffer(ULONG len)
- {
- IMediaBufferImpl *pImpl = (IMediaBufferImpl*)malloc(sizeof(IMediaBufferImpl));
- if (pImpl) {
- pImpl->lpVtbl = &pImpl->vtbl;
- pImpl->lpVtbl->QueryInterface = &QueryInterface;
- pImpl->lpVtbl->AddRef = &AddRef;
- pImpl->lpVtbl->Release = &Release;
- pImpl->lpVtbl->SetLength = &SetLength;
- pImpl->lpVtbl->GetMaxLength = &GetMaxLength;
- pImpl->lpVtbl->GetBufferAndLength = &GetBufferAndLength;
- pImpl->m_pData = (BYTE*)malloc(len);
- pImpl->m_ulData = 0;
- pImpl->m_ulSize = len;
- pImpl->m_cRef = 1;
- }
- return (IMediaBuffer*)pImpl;
- }
- static HRESULT STDMETHODCALLTYPE QueryInterface(IMediaBuffer * This, REFIID riid, void** ppvObject)
- {
- if (This == NULL || riid == NULL || ppvObject == NULL || *ppvObject == NULL)
- return E_POINTER;
- if (IsEqualIID(riid, &IID_IUnknown)) {
- *ppvObject = (void*)This;
- return S_OK;
- } else if (IsEqualIID(riid, &IID_IMediaBuffer)) {
- *ppvObject = (void*)This;
- return S_OK;
- }
- return E_NOTIMPL;
- }
- static ULONG STDMETHODCALLTYPE AddRef(IMediaBuffer * This)
- {
- IMediaBufferImpl *pImpl = (IMediaBufferImpl *)This;
- return InterlockedIncrement(&pImpl->m_cRef);
- }
- static ULONG STDMETHODCALLTYPE Release(IMediaBuffer * This)
- {
- IMediaBufferImpl *pImpl = (IMediaBufferImpl *)This;
- ULONG lRet = InterlockedDecrement(&pImpl->m_cRef);
- if (lRet == 0) {
- destroy_media_buffer(pImpl);
- }
- return lRet;
- }
- static HRESULT STDMETHODCALLTYPE SetLength(IMediaBuffer * This, DWORD ulLength)
- {
- IMediaBufferImpl *pImpl = (IMediaBufferImpl *)This;
- pImpl->m_ulData = ulLength;
- return NOERROR;
- }
- static HRESULT STDMETHODCALLTYPE GetMaxLength(IMediaBuffer * This, DWORD *pcbMaxLength)
- {
- IMediaBufferImpl *pImpl = (IMediaBufferImpl *)This;
- *pcbMaxLength = pImpl->m_ulSize;
- return NOERROR;
- }
- static HRESULT STDMETHODCALLTYPE GetBufferAndLength(IMediaBuffer * This, BYTE **ppBuffer, DWORD *pcbLength)
- {
- IMediaBufferImpl *pImpl = (IMediaBufferImpl *)This;
- if (ppBuffer) *ppBuffer = pImpl->m_pData;
- if (pcbLength) *pcbLength = pImpl->m_ulData;
- return NOERROR;
- }
- static int load_data(audiomicspk3_t *micspk, BYTE *pData, UINT32 nCount, UINT32 *pReturnedCount)
- {
- UINT32 frame_samples = AUDIO_CLOCK * FRAME_TIME / 1000;
- UINT32 frame_offset = 0;
- while (nCount >= frame_samples) {
- delay_buf_get(micspk->ply_dbuf, (SHORT*)(pData+frame_offset*2));
- frame_offset += frame_samples;
- nCount -= frame_samples;
- }
- *pReturnedCount = frame_offset;
- return 0;
- }
- static int save_data(audiomicspk3_t *micspk, IMediaBuffer *pBuffer)
- {
- UINT32 frame_samples = AUDIO_CLOCK * FRAME_TIME / 1000;
- UINT32 frame_offset = 0;
- BYTE *pData;
- DWORD dwLength;
- pBuffer->lpVtbl->GetBufferAndLength(pBuffer, &pData, &dwLength);
- //AUDIO_LOG_INFO("micspk2 rec samples:%d", dwLength>>1);
- while (dwLength >= frame_samples*2) {
- delay_buf_put(micspk->rec_dbuf, (SHORT*)(pData+frame_offset*2));
- frame_offset += frame_samples;
- dwLength -= frame_samples*2;
- }
- return 0;
- }
- static int StreamCallback(const void *input,
- void *output,
- unsigned long frameCount,
- const PaStreamCallbackTimeInfo* timeInfo,
- PaStreamCallbackFlags statusFlags,
- void *userData)
- {
- audiomicspk3_t *micspk = (audiomicspk3_t*)userData;
- apr_status_t status;
- if (output) {
- unsigned nsamples_req = frameCount;
- if (micspk->ply_buf_cnt == 0 && nsamples_req == micspk->frame_samples) {
- delay_buf_get(micspk->ply_dbuf, (short*)output);
- } else {
- if (micspk->ply_buf_cnt > 0) {
- memcpy(output, micspk->ply_buf, micspk->ply_buf_cnt<<1);
- output = (short*)output + micspk->ply_buf_cnt;
- micspk->ply_buf_cnt = 0;
- nsamples_req -= micspk->ply_buf_cnt;
- }
- while (nsamples_req > 0) {
- if (nsamples_req >= micspk->frame_samples) {
- delay_buf_get(micspk->ply_dbuf, (short*)output);
- output = (short*)output + micspk->frame_samples;
- nsamples_req -= micspk->frame_samples;
- } else {
- delay_buf_get(micspk->ply_dbuf, micspk->ply_buf);
- micspk->ply_buf_cnt = micspk->frame_samples;
- memcpy(output, micspk->ply_buf, nsamples_req<<1);
- output = (short*)output + nsamples_req;
- memmove(micspk->ply_buf, micspk->ply_buf+nsamples_req, (micspk->frame_samples-nsamples_req)<<1);
- nsamples_req = 0;
- }
- }
- }
- }
- return paContinue;
- }
- static int initialize_spk(audiomicspk3_t *micspk)
- {
- UINT32 frame_samples = AUDIO_CLOCK * FRAME_TIME / 1000;
- const PaDeviceInfo *info;
- PaStreamParameters outParam;
- PaError paError;
- int ply_dev_id = micspk->ply_dev_id_portaudio;
- if (ply_dev_id == -1) {
- ply_dev_id = Pa_GetDefaultOutputDevice();
- if (ply_dev_id == paNoDevice) {
- AUDIO_LOG_ERROR("audiomicspk create error, cannot find output device");
- return APR_EGENERAL;
- }
- }
- info = Pa_GetDeviceInfo(ply_dev_id);
- outParam.device = ply_dev_id;
- outParam.channelCount = 1;
- outParam.sampleFormat = paInt16;
- outParam.suggestedLatency = info->defaultLowOutputLatency;
- outParam.hostApiSpecificStreamInfo = NULL;
- if (Pa_IsFormatSupported(NULL, &outParam, AUDIO_CLOCK) != paNoError) {
- AUDIO_LOG_ERROR("audiomicspk create error, cannot open audio output device");
- return APR_EGENERAL;
- }
- paError = Pa_OpenStream(&micspk->ply_stream, NULL, &outParam, AUDIO_CLOCK, frame_samples, paClipOff, &StreamCallback, micspk);
- if (paError != 0) {
- AUDIO_LOG_ERROR("audiomicspk create error, Pa_OpenStream function failed in dir! ");
- return APR_EGENERAL;
- }
- paError = Pa_StartStream(micspk->ply_stream);
- if (paError != 0) {
- AUDIO_LOG_ERROR("Pa_StartStream function failed in dir! ");
- Pa_CloseStream(micspk->ply_stream);
- micspk->ply_stream = NULL;
- return APR_EGENERAL;
- }
- return 0;
- }
- static int initialize_rec(audiomicspk3_t *micspk)
- {
- IMediaObject *pDMO = NULL;
- IPropertyStore *pPS = NULL;
- HRESULT hr;
- UINT32 frame_samples = AUDIO_CLOCK * FRAME_TIME / 1000;
- hr = CoCreateInstance(&CLSID_CWMAudioAEC, NULL, CLSCTX_INPROC_SERVER, &IID_IMediaObject, (void**)&pDMO);
- if (SUCCEEDED(hr)) {
- hr = pDMO->lpVtbl->QueryInterface(pDMO, &IID_IPropertyStore, (void**)&pPS);
- }
- if (FAILED(hr)) {
- if (pDMO) {
- pDMO->lpVtbl->Release(pDMO);
- }
- return -1;
- }
- // sys mode
- {
- PROPVARIANT pvSysMode;
- PropVariantInit(&pvSysMode);
- pvSysMode.vt = VT_I4;
- pvSysMode.lVal = micspk->opt & AMS2_OPT_AEC ? SINGLE_CHANNEL_AEC : SINGLE_CHANNEL_NSAGC;
- //pvSysMode.lVal = micspk->opt & AMS2_OPT_AEC ? OPTIBEAM_ARRAY_AND_AEC : SINGLE_CHANNEL_NSAGC;
- pPS->lpVtbl->SetValue(pPS, &MFPKEY_WMAAECMA_SYSTEM_MODE, &pvSysMode);
- PropVariantClear(&pvSysMode);
- }
- // feature mode
- {
- PROPVARIANT pvFeatMode;
- PropVariantInit(&pvFeatMode);
- pvFeatMode.vt = VT_BOOL;
- pvFeatMode.boolVal = VARIANT_TRUE;
- pPS->lpVtbl->SetValue(pPS, &MFPKEY_WMAAECMA_FEATURE_MODE, &pvFeatMode);
- PropVariantClear(&pvFeatMode);
- }
- // set device index
- {
- PROPVARIANT pvDeviceId;
- PropVariantInit(&pvDeviceId);
- pvDeviceId.vt = VT_I4;
- pvDeviceId.lVal = (unsigned long)(micspk->ply_dev_id<<16) + (unsigned long)(0x0000ffff & micspk->rec_dev_id);
- pPS->lpVtbl->SetValue(pPS, &MFPKEY_WMAAECMA_DEVICE_INDEXES, &pvDeviceId);
- PropVariantClear(&pvDeviceId);
- }
- // echo length
- #if 1
- if (micspk->opt & AMS2_OPT_AEC)
- {
- PROPVARIANT pvEchoLength;
- PropVariantInit(&pvEchoLength);
- pvEchoLength.vt = VT_I4;
- pvEchoLength.lVal = 128;
- pPS->lpVtbl->SetValue(pPS, &MFPKEY_WMAAECMA_FEATR_ECHO_LENGTH, &pvEchoLength);
- PropVariantClear(&pvEchoLength);
- }
- #endif
- // echo supress times
- #if 1
- if (micspk->opt & AMS2_OPT_AEC)
- {
- PROPVARIANT pvAESTimes;
- PropVariantInit(&pvAESTimes);
- pvAESTimes.vt = VT_I4;
- pvAESTimes.lVal = 1; // 0, 1, 2
- pPS->lpVtbl->SetValue(pPS, &MFPKEY_WMAAECMA_FEATR_AES, &pvAESTimes);
- PropVariantClear(&pvAESTimes);
- }
- #endif
- // retreive TS
- if (micspk->opt & AMS2_OPT_AEC)
- {
- PROPVARIANT pvTS;
- PropVariantInit(&pvTS);
- pvTS.vt = VT_BOOL;
- pvTS.boolVal = VARIANT_TRUE;
- pPS->lpVtbl->SetValue(pPS, &MFPKEY_WMAAECMA_RETRIEVE_TS_STATS, &pvTS);
- PropVariantClear(&pvTS);
- }
- // noise suppression
- {
- PROPVARIANT pvNoiseSup;
- PropVariantInit(&pvNoiseSup);
- pvNoiseSup.vt = VT_I4;
- pvNoiseSup.lVal = micspk->opt & AMS2_OPT_NS;
- pPS->lpVtbl->SetValue(pPS, &MFPKEY_WMAAECMA_FEATR_NS, &pvNoiseSup);
- PropVariantClear(&pvNoiseSup);
- }
- // Turn on/off AGC
- {
- PROPVARIANT pvAGC;
- PropVariantInit(&pvAGC);
- pvAGC.vt = VT_BOOL;
- pvAGC.boolVal = micspk->opt & AMS2_OPT_AGC ? VARIANT_TRUE : VARIANT_FALSE;
- pPS->lpVtbl->SetValue(pPS, &MFPKEY_WMAAECMA_FEATR_AGC, &pvAGC);
- PropVariantClear(&pvAGC);
- }
- // set output format
- {
- DMO_MEDIA_TYPE mt = {0};
- WAVEFORMATEX wfxOut = {WAVE_FORMAT_PCM, 1, 8000, 16000, 2, 16, 0};
- MoInitMediaType(&mt, sizeof(WAVEFORMATEX));
- mt.majortype = MEDIATYPE_Audio;
- mt.subtype = MEDIASUBTYPE_PCM;
- mt.lSampleSize = 0;
- //mt.lSampleSize = 2;
- mt.bFixedSizeSamples = TRUE;
- mt.bTemporalCompression = FALSE;
- mt.formattype = FORMAT_WaveFormatEx;
- memcpy(mt.pbFormat, &wfxOut, sizeof(WAVEFORMATEX));
- pDMO->lpVtbl->SetOutputType(pDMO, 0, &mt, 0);
- micspk->rec_buf_size = wfxOut.nSamplesPerSec * wfxOut.wBitsPerSample / 8;
- MoFreeMediaType(&mt);
- }
- delay_buf_create(AUDIO_CLOCK, frame_samples, 1, MAX_DELAY, 0, (delay_buf**)&micspk->rec_dbuf);
- pDMO->lpVtbl->AllocateStreamingResources(pDMO);
- pPS->lpVtbl->Release(pPS);
- micspk->rec_dmo = pDMO;
- return 0;
- }
- static void uninitialize_spk(audiomicspk3_t *micspk)
- {
- if (micspk->ply_stream) {
- Pa_AbortStream(micspk->ply_stream);
- Pa_CloseStream(micspk->ply_stream);
- }
- if (micspk->ply_dbuf) {
- delay_buf_destroy(micspk->ply_dbuf);
- micspk->ply_dbuf = NULL;
- }
- }
- static void uninitialize_rec(audiomicspk3_t *micspk)
- {
- IMediaObject *pDMO = (IMediaObject *)micspk->rec_dmo;
- if (pDMO) {
- pDMO->lpVtbl->Release(pDMO);
- }
-
- if (micspk->rec_dbuf) {
- delay_buf_destroy(micspk->rec_dbuf);
- micspk->rec_dbuf = NULL;
- }
-
- micspk->rec_dmo = NULL;
- }
- static void on_clock_rec(audiomicspk3_t *micspk)
- {
- IMediaObject *pDMO = (IMediaObject*)micspk->rec_dmo;
- DWORD dwStatus = 0;
- HRESULT hr;
- DWORD cOutputBufLen = micspk->rec_buf_size;
- DMO_OUTPUT_DATA_BUFFER bufferStruct = {0};
- do {
- bufferStruct.pBuffer = create_media_buffer(cOutputBufLen);
- bufferStruct.dwStatus = 0;
- hr = pDMO->lpVtbl->ProcessOutput(pDMO, 0, 1, &bufferStruct, &dwStatus);
- if (SUCCEEDED(hr)) {
- if (hr == S_FALSE) {
- //....
- } else {
- save_data(micspk, bufferStruct.pBuffer);
- }
- bufferStruct.pBuffer->lpVtbl->Release(bufferStruct.pBuffer);
- } else {
- bufferStruct.pBuffer->lpVtbl->Release(bufferStruct.pBuffer);
- break;
- }
- } while (bufferStruct.dwStatus & DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE);
-
- }
- static unsigned int __stdcall work_proc(void *arg)
- {
- audiomicspk3_t *micspk = (audiomicspk3_t *)arg;
- int rc;
- // set a higher priority because of audio is very sensitive about timing
- SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
- CoInitialize(NULL);
- //
- // record need play because of AEC, so
- // record <---> record and play
- // play <---> play
- // record and play <---> record and play
- //
- if (micspk->opt & AMS_OPT_RECORD) {
- rc = initialize_spk(micspk);
- if (rc != 0)
- goto on_error;
- rc = initialize_rec(micspk);
- if (rc != 0)
- goto on_error;
- } else if (micspk->opt & AMS_OPT_PLAY) {
- rc = initialize_spk(micspk);
- if (rc != 0)
- goto on_error;
- }
- micspk->evt_exit = CreateEventA(NULL, FALSE, FALSE, NULL);
- for (;;) {
- DWORD dwRet = WaitForSingleObject(micspk->evt_exit, CLOCK_PERIOD);
- if (dwRet == WAIT_OBJECT_0) { // exit
- break;
- } else { // timeout
- if (micspk->opt & AMS_OPT_RECORD) {
- on_clock_rec(micspk);
- } else if (micspk->opt & AMS_OPT_PLAY) {
- //on_clock_spk(micspk);
- }
- }
- }
- on_error:
- if (micspk->opt & AMS_OPT_RECORD) {
- uninitialize_spk(micspk);
- uninitialize_rec(micspk);
- } else if (micspk->opt & AMS_OPT_PLAY) {
- uninitialize_spk(micspk);
- }
- CoUninitialize();
- return 0;
- }
- static apr_status_t read_frame(void *self, audioframe_t *frame)
- {
- audiomicspk3_t *micspk = CONTAINING_RECORD(self, audiomicspk3_t, base);
- UINT32 frame_samples = AUDIO_CLOCK * FRAME_TIME / 1000;
- frame->size = 2*frame_samples;
- frame->dtmf = 0;
- delay_buf_get(micspk->rec_dbuf, (short*)frame->buffer);
- return APR_SUCCESS;
- }
- static apr_status_t write_frame(void *self, const audioframe_t *frame)
- {
- audiomicspk3_t *micspk = CONTAINING_RECORD(self, audiomicspk3_t, base);
- delay_buf_put(micspk->ply_dbuf, (short*)frame->buffer);
- return APR_SUCCESS;
- }
- static audiostream_vtbl_t g_stream_vtbl = {
- &read_frame,
- &write_frame,
- };
- apr_status_t audiomicspk3_create(apr_pool_t *pool,
- audioengine_t *engine,
- int opt,
- int clock,
- const char *rec_dev_key,
- const char *ply_dev_key,
- audiomicspk3_t **p_micspk)
- {
- int rec_dev_id = -1;
- int ply_dev_id = -1;
- int ply_dev_id_portaudio = -1;
- audiomicspk3_t *micspk;
- unsigned long frame_samples;
- ply_dev_id_portaudio = get_device_index_poartaudio(0, ply_dev_key);
- ply_dev_id = get_device_index(0, ply_dev_key);
- rec_dev_id = get_device_index(1, rec_dev_key);
- if (rec_dev_id < 0 || ply_dev_id < 0 || ply_dev_id_portaudio < 0)
- return APR_EGENERAL;
- //opt |= AMS2_OPT_AGC | AMS2_OPT_NS;
- micspk = apr_palloc(pool, sizeof(audiomicspk3_t));
- memset(micspk, 0, sizeof(audiomicspk3_t));
- frame_samples = FRAME_TIME * clock / 1000;
- micspk->rec_dev_id = rec_dev_id;
- micspk->ply_dev_id = ply_dev_id;
- micspk->ply_dev_id_portaudio = ply_dev_id_portaudio;
- micspk->opt = opt;
- micspk->frame_samples = frame_samples;
- audiostream_init(engine, &g_stream_vtbl, &micspk->base);
- micspk->base.direction = 0;
- if (opt & AMS_OPT_PLAY) {
- micspk->base.direction |= STREAM_DIR_WRITE;
- delay_buf_create(clock, frame_samples, 1, MAX_DELAY, 0, (delay_buf**)&micspk->ply_dbuf);
- micspk->ply_buf = (short*)apr_palloc(pool, frame_samples<<1);
- micspk->ply_buf_cnt = 0;
- }
- if (opt & AMS_OPT_RECORD) {
- micspk->base.direction |= STREAM_DIR_READ;
- delay_buf_create(clock, frame_samples, 1, MAX_DELAY, 0, (delay_buf**)&micspk->rec_dbuf);
- }
- micspk->worker_thread = (HANDLE)_beginthreadex(NULL, 0, &work_proc, micspk, 0, NULL);
- if (micspk->worker_thread) {
- BOOL bThreadExited = FALSE;
- do {
- DWORD dwRet = WaitForSingleObject(micspk->worker_thread, 10);
- if (dwRet == WAIT_TIMEOUT) {
- volatile HANDLE hExit = micspk->evt_exit;
- if (hExit)
- break;
- } else if (dwRet == WAIT_OBJECT_0) {
- bThreadExited = TRUE;
- }
- } while (!bThreadExited);
- if (bThreadExited) {
- audiomicspk3_destroy(micspk);
- return APR_EGENERAL;
- }
- } else {
- audiomicspk3_destroy(micspk);
- return APR_EGENERAL;
- }
- *p_micspk = micspk;
- return APR_SUCCESS;
- }
- void audiomicspk3_destroy(audiomicspk3_t *micspk)
- {
- if (micspk->evt_exit) {
- SetEvent(micspk->evt_exit);
- WaitForSingleObject(micspk->worker_thread, INFINITE);
- CloseHandle(micspk->worker_thread);
- CloseHandle(micspk->evt_exit);
- }
- }
-
|