libaudiorender.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  1. // libaudiorender.cpp : Defines the exported functions for the DLL application.
  2. //
  3. #include "stdafx.h"
  4. #ifndef _CRT_SECURE_NO_WARNINGS
  5. #define _CRT_SECURE_NO_WARNINGS
  6. #endif
  7. #include "libaudiorender.h"
  8. #include "../../rvcmediacommon/rvc_media_common.h"
  9. #ifndef RVC_AUDIO_FRAME_SIZE
  10. #define RVC_AUDIO_FRAME_SIZE 320
  11. #endif
  12. #ifndef RVC_AUDIO_FREQUENCY
  13. #define RVC_AUDIO_FREQUENCY 8000
  14. #endif
  15. #ifndef RVC_AUDIO_BUFFER_LEN
  16. #define RVC_AUDIO_BUFFER_LEN 512
  17. #endif
  18. #ifndef RVC_DEFAULT_BITPERSAMPLE
  19. #define RVC_DEFAULT_BITPERSAMPLE 16
  20. #endif
  21. AudioRenderImpl::AudioRenderImpl(audiorender_callback_t* pCallback)
  22. {
  23. memcpy(&m_audiorender_cb, pCallback, sizeof(audiorender_callback_t));
  24. m_pAudioCaptureClient = NULL;
  25. m_pAudioClient = NULL;
  26. m_pMMDevice = NULL;
  27. m_hEventStop = NULL;
  28. m_hTimerWakeUp = NULL;
  29. m_hTask = NULL;
  30. m_pwfx = NULL;
  31. m_iQueueNumber = 0;
  32. m_audio_cap = NULL;
  33. m_frame_format = NULL;
  34. memset(m_strFilePathName, 0, MAX_PATH);
  35. m_bRecordPCM = false;
  36. }
  37. bool AudioRenderImpl::InitAudioFrame(audio_frame* pframe)
  38. {
  39. bool bret = false;
  40. if (NULL != pframe){
  41. pframe->bitspersample = RVC_DEFAULT_BITPERSAMPLE;
  42. pframe->format = 1;
  43. pframe->nchannels = 1;
  44. pframe->samplespersec = RVC_AUDIO_FREQUENCY;
  45. pframe->framesize = RVC_AUDIO_FRAME_SIZE;
  46. pframe->data = NULL;
  47. bret = true;
  48. }
  49. return bret;
  50. }
  51. DWORD AudioRenderImpl::pfThreadFunc(LPVOID lpThreadParameter)
  52. {
  53. AudioRenderImpl* pCapture = (AudioRenderImpl*)lpThreadParameter;
  54. pCapture->RenderFunc();
  55. return 0;
  56. }
  57. void AudioRenderImpl::LogRenderInfo()
  58. {
  59. uint32_t uConvertRatio = 1;
  60. if (NULL != m_frame_format){
  61. if (m_frame_format->samplespersec&&m_frame_format->nchannels&&m_frame_format->bitspersample){
  62. uConvertRatio = (m_pwfx->nSamplesPerSec*m_pwfx->nChannels*m_pwfx->wBitsPerSample)/(m_frame_format->samplespersec*m_frame_format->nchannels*m_frame_format->bitspersample);
  63. }
  64. }
  65. RenderLog(AUDIORENDER_LOG_DEBUG, "current speaker render audio convert ratio is %d.", uConvertRatio);
  66. eSpeakerSamplingDepthRate eSampleType = GetSpeakerSampleRate(m_pwfx->wBitsPerSample, m_pwfx->nSamplesPerSec);
  67. RenderLog(AUDIORENDER_LOG_DEBUG, "Speaker Sample Type is %d.", eSampleType);
  68. }
  69. void AudioRenderImpl::RenderLog(audiorender_loglevel elevel, const char *fmt, ... )
  70. {
  71. if (m_audiorender_cb.debug){
  72. va_list arg;
  73. va_start(arg, fmt);
  74. if (*m_audiorender_cb.debug){
  75. (*m_audiorender_cb.debug)(elevel, m_audiorender_cb.user_data, fmt, arg);
  76. }
  77. va_end(arg);
  78. }
  79. }
  80. void AudioRenderImpl::OnRenderFailed()
  81. {
  82. }
  83. void AudioRenderImpl::OnAudioRenderExcption()
  84. {
  85. }
  86. int AudioRenderImpl::StartRender(int iQueue, void* pFrameformat, const char* pSwitchName)
  87. {
  88. m_iQueueNumber = iQueue;
  89. if (NULL != m_frame_format){
  90. delete m_frame_format;
  91. m_frame_format = NULL;
  92. }
  93. m_frame_format = new audio_frame();
  94. if (NULL != m_frame_format){
  95. if (NULL != pFrameformat){
  96. m_frame_format->bitspersample = ((audio_frame*)pFrameformat)->bitspersample;
  97. m_frame_format->nchannels = ((audio_frame*)pFrameformat)->nchannels;
  98. m_frame_format->format = ((audio_frame*)pFrameformat)->format;
  99. m_frame_format->samplespersec = ((audio_frame*)pFrameformat)->samplespersec;
  100. m_frame_format->framesize = ((audio_frame*)pFrameformat)->framesize;
  101. }
  102. else{
  103. InitAudioFrame(m_frame_format);
  104. }
  105. }
  106. if (NULL != pSwitchName){
  107. size_t ulen = strlen(pSwitchName);
  108. if (ulen >= MAX_PATH){
  109. ulen = MAX_PATH - 1;
  110. }
  111. memcpy(m_strFilePathName, pSwitchName, ulen);
  112. if (strlen(m_strFilePathName) > 0){
  113. m_bRecordPCM = true;
  114. }
  115. }
  116. if (InitQueueInfo(iQueue)){
  117. return -1;
  118. }
  119. CoInitialize(NULL);
  120. IMMDeviceEnumerator *pMMDeviceEnumerator = NULL;
  121. HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL,
  122. __uuidof(IMMDeviceEnumerator), (void**)&pMMDeviceEnumerator);
  123. if (FAILED(hr)){
  124. CoUninitialize();
  125. return -1;
  126. }
  127. // get the default render endpoint
  128. hr = pMMDeviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &m_pMMDevice);
  129. if (FAILED(hr)){
  130. CoUninitialize();
  131. return -1;
  132. }
  133. pMMDeviceEnumerator->Release();
  134. m_hEventStop = CreateEvent(NULL, TRUE, FALSE, NULL);
  135. if (m_hEventStop == NULL){
  136. CoUninitialize();
  137. return -1;
  138. }
  139. hr = m_pMMDevice->Activate(__uuidof(IAudioClient), CLSCTX_ALL, NULL, (void**)&m_pAudioClient);
  140. if (FAILED(hr)){
  141. goto error;
  142. }
  143. REFERENCE_TIME hnsDefaultDevicePeriod(0);
  144. if (NULL != m_pAudioClient){
  145. hr = m_pAudioClient->GetDevicePeriod(&hnsDefaultDevicePeriod, NULL);
  146. if (FAILED(hr)){
  147. goto error;
  148. }
  149. }
  150. else{
  151. goto error;
  152. }
  153. hr = m_pAudioClient->GetMixFormat(&m_pwfx);
  154. if (FAILED(hr)){
  155. goto error;
  156. }
  157. else{
  158. RenderLog(AUDIORENDER_LOG_DEBUG, "speaker render format is %0x, channels is %d, samples rate is %d, buffer size is %d, block size of data is %d.",m_pwfx->wFormatTag, m_pwfx->nChannels, m_pwfx->nSamplesPerSec, m_pwfx->nAvgBytesPerSec, m_pwfx->nBlockAlign);
  159. RenderLog(AUDIORENDER_LOG_DEBUG, "destination audio frame format is %d, samples rate is %d, bits per sample is %d, channels number is %d.", m_frame_format->format, m_frame_format->samplespersec, m_frame_format->bitspersample, m_frame_format->nchannels);
  160. }
  161. if (!AdjustFormatTo16Bits(m_pwfx)){
  162. goto error;
  163. }
  164. m_hTimerWakeUp = CreateWaitableTimer(NULL, FALSE, NULL);
  165. if (m_hTimerWakeUp == NULL){
  166. goto error;
  167. }
  168. if (NULL != m_pAudioClient){
  169. hr = m_pAudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_LOOPBACK, 0, 0, m_pwfx, 0);
  170. if (FAILED(hr)){
  171. goto error;
  172. }
  173. }
  174. else{
  175. goto error;
  176. }
  177. if (NULL != m_pAudioClient){
  178. hr = m_pAudioClient->GetService(__uuidof(IAudioCaptureClient), (void**)&m_pAudioCaptureClient);
  179. if (FAILED(hr)){
  180. goto error;
  181. }
  182. }
  183. else{
  184. goto error;
  185. }
  186. DWORD nTaskIndex = 0;
  187. m_hTask = AvSetMmThreadCharacteristics("Capture", &nTaskIndex);
  188. if (NULL == m_hTask){
  189. goto error;
  190. }
  191. LARGE_INTEGER liFirstFire;
  192. liFirstFire.QuadPart = -hnsDefaultDevicePeriod / 2; // negative means relative time
  193. LONG lTimeBetweenFires = (LONG)hnsDefaultDevicePeriod / 2 / (10 * 1000); // convert to milliseconds
  194. BOOL bOK = SetWaitableTimer(m_hTimerWakeUp, &liFirstFire, lTimeBetweenFires, NULL, NULL, FALSE);
  195. if (!bOK){
  196. goto error;
  197. }
  198. if (NULL != m_pAudioClient){
  199. hr = m_pAudioClient->Start();
  200. if (FAILED(hr)){
  201. goto error;
  202. }
  203. }
  204. else{
  205. goto error;
  206. }
  207. m_hThread = CreateThread(NULL, 0, pfThreadFunc, this, 0, 0);
  208. if (m_hThread == NULL){
  209. goto error;
  210. }
  211. CoUninitialize();
  212. return 0;
  213. error:
  214. Close();
  215. CoUninitialize();
  216. return -1;
  217. }
  218. uint32_t AudioRenderImpl::ConvertDouble2SingleChannel(char* pDstBuf, const uint32_t uDstLen, const unsigned char* pSrcBuf, uint32_t uSrcLen, uint32_t uBitDeepth)
  219. {
  220. uint32_t uRet = 0;
  221. uint32_t uOneChannelLen = uSrcLen/2;
  222. uint32_t i = 0;
  223. for (; i < uOneChannelLen/2 && i < uDstLen/uBitDeepth; i++){
  224. memcpy((uint16_t*)pDstBuf + i, ((uint32_t*)(pSrcBuf))+i, uBitDeepth);
  225. }
  226. if (i == uOneChannelLen/2){
  227. uRet = uOneChannelLen;
  228. }
  229. return uRet;
  230. }
  231. eSpeakerSamplingDepthRate AudioRenderImpl::GetSpeakerSampleRate(uint32_t udepth, uint32_t usamplerate)
  232. {
  233. eSpeakerSamplingDepthRate eType = eSixteenBitsDVD;
  234. if (16 == udepth){
  235. switch(usamplerate)
  236. {
  237. case 44100:
  238. eType = eSixteenBitsCD;
  239. break;
  240. case 48000:
  241. eType = eSixteenBitsDVD;
  242. break;
  243. case 96000:
  244. eType = eSixteenBitsStatdioLow;
  245. break;
  246. case 192000:
  247. eType = eSixteenBitsStatdioHigh;
  248. break;
  249. }
  250. }
  251. else if (24 == udepth){
  252. switch(usamplerate)
  253. {
  254. case 44100:
  255. eType = eTwentyfourStatdioA;
  256. break;
  257. case 48000:
  258. eType = eTwentyfourStatdioB;
  259. break;
  260. case 96000:
  261. eType = eTwentyfourStatdioC;
  262. break;
  263. case 192000:
  264. eType = eTwentyfourStatdioD;
  265. break;
  266. }
  267. }
  268. return eType;
  269. }
  270. int AudioRenderImpl::InitQueueInfo(int iQueue)
  271. {
  272. int iRet = -1;
  273. char* pQueueName = NULL;
  274. if (0 == iQueue){
  275. pQueueName = REC_COMMON_REMOTEAUDIO_SHM_QUEUE;
  276. }
  277. else {
  278. pQueueName = REC_COMMON_AUDIO_SALES_SHM_QUEUE;
  279. }
  280. if (NULL != pQueueName){
  281. m_audio_cap = new Clibaudioqueue(pQueueName);
  282. if (NULL != m_audio_cap){
  283. iRet = 0;
  284. RenderLog(AUDIORENDER_LOG_DEBUG, "audio render insert queue name is %s.", pQueueName);
  285. }
  286. }
  287. return iRet;
  288. }
  289. uint32_t AudioRenderImpl::TranslateBuffer2DestFrameFormat(spx_int16_t* pOutAudio, spx_uint32_t* pAudioLen, spx_uint32_t uAudioBufferLen, unsigned char* pCbBuffer, const uint32_t uBufferLen, SpeexResamplerState *st, const audio_frame* pDestFrameFormat)
  290. {
  291. uint32_t uRet = 0;
  292. uint32_t uSingleChannelDataLen = uBufferLen;
  293. uint32_t uSingleChannelBufferLen = 0;
  294. char* pSingleChannelBuf = (char*)malloc(uBufferLen*sizeof(char));
  295. if (NULL != pSingleChannelBuf){
  296. memset(pSingleChannelBuf, 0, uBufferLen*sizeof(char));
  297. uSingleChannelBufferLen = uBufferLen*sizeof(char);
  298. }
  299. if (eDoubleChannel == m_pwfx->nChannels){
  300. if (eSingleChannel == pDestFrameFormat->nchannels){
  301. uSingleChannelDataLen = ConvertDouble2SingleChannel(pSingleChannelBuf, uSingleChannelBufferLen, pCbBuffer, uBufferLen, m_pwfx->wBitsPerSample/8);
  302. }
  303. else{
  304. memcpy(pSingleChannelBuf, pCbBuffer, uBufferLen);
  305. }
  306. }
  307. else{
  308. if (eSingleChannel == pDestFrameFormat->nchannels){
  309. memcpy(pSingleChannelBuf, pCbBuffer, uBufferLen);
  310. }
  311. else{
  312. RenderLog(AUDIORENDER_LOG_INFO, "not support single channel convert to double channels.");
  313. }
  314. }
  315. spx_uint32_t uInLen = uSingleChannelDataLen;
  316. int iRet = speex_resampler_process_int(st, 0, (spx_int16_t*)pSingleChannelBuf, &uInLen, pOutAudio, &uAudioBufferLen);
  317. if (RESAMPLER_ERR_SUCCESS == iRet){
  318. *pAudioLen = uAudioBufferLen;
  319. uRet = uAudioBufferLen;
  320. }
  321. if (NULL != pSingleChannelBuf){
  322. free(pSingleChannelBuf);
  323. pSingleChannelBuf = NULL;
  324. }
  325. return uRet;
  326. }
  327. void AudioRenderImpl::RenderFunc()
  328. {
  329. HANDLE waitArray[2] = { m_hEventStop, m_hTimerWakeUp };
  330. DWORD dwWaitResult;
  331. UINT32 nNextPacketSize(0);
  332. BYTE *pData = NULL;
  333. UINT32 nNumFramesToRead;
  334. DWORD dwFlags;
  335. CoInitialize(NULL);
  336. SpeexResamplerState *st = NULL;
  337. int err = 0;
  338. spx_int16_t OutAudioBuffer[RVC_AUDIO_BUFFER_LEN] = {0};
  339. spx_uint32_t uIndex = 0;
  340. spx_uint32_t uValidAudioLen = 0;
  341. spx_uint32_t uLeftBufferLen = RVC_AUDIO_BUFFER_LEN;
  342. int iseriesnumber = 0;
  343. FILE* pRecord = NULL;
  344. if (m_bRecordPCM){
  345. pRecord = fopen(m_strFilePathName, "wb+");
  346. }
  347. LogRenderInfo();
  348. st = speex_resampler_init_frac(1, m_pwfx->nSamplesPerSec, m_frame_format->samplespersec, m_pwfx->nSamplesPerSec, m_frame_format->samplespersec, 0, &err);
  349. while (true){
  350. dwWaitResult = WaitForMultipleObjects(sizeof(waitArray) / sizeof(waitArray[0]), waitArray, false, INFINITE);
  351. if (WAIT_OBJECT_0 == dwWaitResult) {
  352. RenderLog(AUDIORENDER_LOG_DEBUG, "exit circle for set event stop.");
  353. break;
  354. }
  355. if (WAIT_OBJECT_0 + 1 != dwWaitResult){
  356. RenderLog(AUDIORENDER_LOG_DEBUG, "exit circle for time wake up.");
  357. break;
  358. }
  359. HRESULT hr = S_OK;
  360. if (NULL != m_pAudioCaptureClient){
  361. m_pAudioCaptureClient->GetNextPacketSize(&nNextPacketSize);
  362. if (FAILED(hr)){
  363. break;
  364. }
  365. }else{
  366. break;
  367. }
  368. if (nNextPacketSize == 0) {
  369. continue;
  370. }
  371. if (NULL != m_pAudioCaptureClient){
  372. hr = m_pAudioCaptureClient->GetBuffer(&pData, &nNumFramesToRead, &dwFlags, NULL, NULL);
  373. if (FAILED(hr)){
  374. break;
  375. }
  376. }
  377. else{
  378. break;
  379. }
  380. if (0 != nNumFramesToRead){
  381. uIndex = TranslateBuffer2DestFrameFormat((spx_int16_t*)((char*)OutAudioBuffer+uIndex), &uValidAudioLen, uLeftBufferLen, pData, nNumFramesToRead*m_pwfx->nBlockAlign, st, m_frame_format);
  382. uLeftBufferLen -= uValidAudioLen;
  383. //RenderLog(AUDIORENDER_LOG_DEBUG, "translate valid audio len is %d,left buffer len is %d.", uValidAudioLen, uLeftBufferLen);
  384. if (uLeftBufferLen <= RVC_AUDIO_BUFFER_LEN - m_frame_format->framesize){
  385. //RenderLog(AUDIORENDER_LOG_DEBUG, "audio len = %d.", RVC_AUDIO_BUFFER_LEN - uLeftBufferLen);
  386. if (m_audio_cap){
  387. audio_frame framedata;
  388. framedata.bitspersample = m_frame_format->bitspersample;
  389. framedata.format = m_frame_format->format;
  390. framedata.nchannels = m_frame_format->nchannels;
  391. framedata.samplespersec = m_frame_format->samplespersec;
  392. framedata.framesize = m_frame_format->framesize;
  393. framedata.data = (char*)OutAudioBuffer;
  394. framedata.iseriesnumber = iseriesnumber++;
  395. bool bRet = m_audio_cap->InsertAudio(&framedata);
  396. if (bRet){
  397. if (0 == framedata.iseriesnumber % 1000){
  398. RenderLog(AUDIORENDER_LOG_DEBUG, "speaker audio[%d] InsertAudio success.", framedata.iseriesnumber);
  399. }
  400. }
  401. else{
  402. RenderLog(AUDIORENDER_LOG_INFO, "speaker audio InsertAudio failed.");
  403. }
  404. if (m_bRecordPCM){
  405. if (NULL != pRecord){
  406. fwrite(framedata.data, framedata.framesize, 1, pRecord);
  407. }
  408. }
  409. }
  410. uLeftBufferLen = RVC_AUDIO_BUFFER_LEN;
  411. memset(OutAudioBuffer, 0 , RVC_AUDIO_BUFFER_LEN);
  412. uIndex = 0;
  413. }
  414. else{
  415. uValidAudioLen = 0;
  416. }
  417. }
  418. if (NULL != m_pAudioCaptureClient){
  419. m_pAudioCaptureClient->ReleaseBuffer(nNumFramesToRead);
  420. }
  421. }
  422. if (NULL != pRecord){
  423. fclose(pRecord);
  424. pRecord = NULL;
  425. }
  426. speex_resampler_destroy(st);
  427. CoUninitialize();
  428. }
  429. bool AudioRenderImpl::AdjustFormatTo16Bits(WAVEFORMATEX *pwfx)
  430. {
  431. bool bRet = false;
  432. if (NULL != pwfx){
  433. if (pwfx->wFormatTag == WAVE_FORMAT_IEEE_FLOAT){
  434. pwfx->wFormatTag = WAVE_FORMAT_PCM;
  435. pwfx->wBitsPerSample = 16;
  436. pwfx->nBlockAlign = pwfx->nChannels * pwfx->wBitsPerSample / 8;
  437. pwfx->nAvgBytesPerSec = pwfx->nBlockAlign * pwfx->nSamplesPerSec;
  438. bRet = true;
  439. }
  440. else if (pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
  441. PWAVEFORMATEXTENSIBLE pEx = reinterpret_cast<PWAVEFORMATEXTENSIBLE>(pwfx);
  442. if (IsEqualGUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, pEx->SubFormat)){
  443. pEx->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
  444. pEx->Samples.wValidBitsPerSample = 16;
  445. pwfx->wBitsPerSample = 16;
  446. pwfx->nBlockAlign = pwfx->nChannels * pwfx->wBitsPerSample / 8;
  447. pwfx->nAvgBytesPerSec = pwfx->nBlockAlign * pwfx->nSamplesPerSec;
  448. bRet = true;
  449. }
  450. }
  451. }
  452. return bRet;
  453. }
  454. int AudioRenderImpl::StopRender()
  455. {
  456. RenderLog(AUDIORENDER_LOG_DEBUG, "stop audio render.");
  457. m_bRecordPCM = false;
  458. memset(m_strFilePathName, 0, MAX_PATH);
  459. if (m_pAudioClient){
  460. m_pAudioClient->Stop();
  461. }
  462. SetEvent(m_hEventStop);
  463. RenderLog(AUDIORENDER_LOG_DEBUG, "m_hEventStop SetEvent.");
  464. WaitForSingleObject(m_hThread, -1);
  465. if (m_audio_cap){
  466. Sleep(10);
  467. m_audio_cap->ClearAudioQueue();
  468. }
  469. if (m_frame_format){
  470. delete m_frame_format;
  471. m_frame_format = NULL;
  472. }
  473. Close();
  474. return 0;
  475. }
  476. int AudioRenderImpl::ReStartRender()
  477. {
  478. if (0 == StopRender()){
  479. StartRender(m_iQueueNumber, m_frame_format, m_strFilePathName);
  480. }
  481. return 0;
  482. }
  483. void AudioRenderImpl::Close()
  484. {
  485. if (m_hEventStop != NULL)
  486. {
  487. CloseHandle(m_hEventStop);
  488. m_hEventStop = NULL;
  489. }
  490. if (m_pAudioClient)
  491. {
  492. m_pAudioClient->Release();
  493. m_pAudioClient = NULL;
  494. }
  495. if (m_pwfx != NULL)
  496. {
  497. CoTaskMemFree(m_pwfx);
  498. m_pwfx = NULL;
  499. }
  500. if (m_hTimerWakeUp != NULL)
  501. {
  502. CancelWaitableTimer(m_hTimerWakeUp);
  503. CloseHandle(m_hTimerWakeUp);
  504. m_hTimerWakeUp = NULL;
  505. }
  506. if (m_hTask != NULL)
  507. {
  508. AvRevertMmThreadCharacteristics(m_hTask);
  509. m_hTask = NULL;
  510. }
  511. if (m_pAudioCaptureClient != NULL)
  512. {
  513. m_pAudioCaptureClient->Release();
  514. m_pAudioCaptureClient = NULL;
  515. }
  516. }
  517. void AudioRenderImpl::Release()
  518. {
  519. delete this;
  520. }
  521. AudioRenderImpl::~AudioRenderImpl()
  522. {
  523. }