AudioRenderer.cpp
上传用户:lusi_8715
上传日期:2007-01-08
资源大小:199k
文件大小:8k
源码类别:

流媒体/Mpeg4/MP4

开发平台:

Visual C++

  1. /**************************************************************************************
  2.  *                                                                                    *
  3.  * This application contains code from OpenDivX and is released as a "Larger Work"    *
  4.  * under that license. Consistant with that license, this application is released     *
  5.  * under the GNU General Public License.                                              *
  6.  *                                                                                    *
  7.  * The OpenDivX license can be found at: http://www.projectmayo.com/opendivx/docs.php *
  8.  * The GPL can be found at: http://www.gnu.org/copyleft/gpl.html                      *
  9.  *                                                                                    *
  10.  * Copyright (c) 2001 - Project Mayo                                                  *
  11.  *                                                                                    *
  12.  * Authors: Damien Chavarria <adrc at projectmayo.com>                                *
  13.  *                                                                                    *
  14.  **************************************************************************************/
  15. #include "AudioRenderer.h"
  16. /*
  17.  * Class Functions
  18.  *
  19.  */
  20. /*
  21.  * Constructor: Tries to init an IDirectDound object
  22.  *              and a secondary buffer for playback
  23.  *
  24.  */
  25. AudioRenderer::AudioRenderer(WAVEFORMATEX *inFormat, HWND hwnd)
  26. {
  27. this->lpDirectSound = NULL;
  28. this->lpBuffer      = NULL;
  29. if(inFormat) {
  30. HRESULT hr;
  31. if(DirectSoundCreate(NULL, &this->lpDirectSound, NULL) == DS_OK) {
  32. /*
  33.  * Set cooperative mode
  34.  */
  35. hr = lpDirectSound->SetCooperativeLevel(hwnd, DSSCL_NORMAL);
  36. if(hr != DS_OK) {
  37. MessageBox(NULL, "Couldn't set sound mode!", "", MB_OK);
  38. return;
  39. }
  40. /*
  41.  * Create the buffer
  42.  */
  43. DSBUFFERDESC  dsbdesc;
  44. WAVEFORMATEX  wf;
  45. memset(&dsbdesc, 0, sizeof(DSBUFFERDESC));
  46. dsbdesc.dwSize = sizeof(DSBUFFERDESC);
  47.     
  48. ZeroMemory(&wf, sizeof(WAVEFORMATEX));
  49. memcpy(&wf, inFormat, sizeof(WAVEFORMATEX));
  50. dsbdesc.lpwfxFormat = (LPWAVEFORMATEX) &wf;
  51.     
  52. dsbdesc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_GLOBALFOCUS;
  53. dsbdesc.dwBufferBytes = 3 * inFormat->nAvgBytesPerSec;
  54. hr = lpDirectSound->CreateSoundBuffer(&dsbdesc, &lpBuffer, NULL);
  55. if(hr == DSERR_INVALIDPARAM) {
  56. char msg[70];
  57. sprintf(msg, "Cannot create sound buffer for %d, %d, %d!", inFormat->nChannels, 
  58. inFormat->nSamplesPerSec, inFormat->wBitsPerSample);
  59. MessageBox(NULL, msg, "", MB_OK);
  60. return;
  61. }
  62. /*
  63.  * here we're ok!
  64.  */
  65. this->ourFormat    = inFormat;
  66. this->dwBufferSize = 3 * inFormat->nAvgBytesPerSec;
  67. this->lInTimer = FALSE;
  68. }
  69. }
  70. }
  71. /*
  72.  * Destructor : Cleanup.
  73.  *
  74.  */
  75. AudioRenderer::~AudioRenderer()
  76. {
  77. }
  78. /*
  79.  * Sets the user-defined callback
  80.  * fo filling the audio buffer
  81.  *
  82.  */
  83. int AudioRenderer::SetCallback(void *lpData, AudioCallback callback)
  84. {
  85. this->lpData   = lpData;
  86. this->callback = callback;
  87. return 1;
  88. }
  89. /*
  90.  * TODO : sets the volume
  91.  *
  92.  */
  93. int AudioRenderer::SetVolume(int volume)
  94. {
  95. if(this->lpBuffer) {
  96. double vol;
  97. vol = - ( 70*pow(10, (100.0 - (double) volume)*2.0/100.0) );
  98. if(this->lpBuffer != NULL)
  99. this->lpBuffer->SetVolume((int) vol);
  100. }
  101. return 1;
  102. }
  103. /*
  104.  * Internal timer func for calling the
  105.  * user-defined callback and fill the buffer
  106.  *
  107.  */
  108. void CALLBACK TimeFunc(UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
  109. {
  110. AudioRenderer *audioRenderer = (AudioRenderer *) dwUser;
  111. if (InterlockedExchange(&audioRenderer->lInTimer, TRUE)) return;
  112. if(audioRenderer->callback) {
  113. void *buffer1, *buffer2;
  114. DWORD bytes1, bytes2;
  115. DWORD dwPlay, dwWrite;
  116. int   dwPlayedLength;
  117. audioRenderer->lpBuffer->GetCurrentPosition(&dwPlay, &dwWrite);
  118. if( dwPlay == audioRenderer->dwNextWriteOffset ) {
  119.     InterlockedExchange(&audioRenderer->lInTimer, FALSE);
  120. return;
  121. }
  122. if( dwPlay < audioRenderer->dwNextWriteOffset ) {
  123.         
  124. dwPlayedLength = (dwPlay + audioRenderer->dwBufferSize - audioRenderer->dwNextWriteOffset);
  125. }
  126. else {
  127.         
  128. dwPlayedLength = (dwPlay - audioRenderer->dwNextWriteOffset);
  129. }
  130. audioRenderer->dwProgress += dwPlayedLength;
  131. audioRenderer->lpBuffer->Lock(audioRenderer->dwNextWriteOffset, dwPlayedLength,
  132.   &buffer1, &bytes1, &buffer2, &bytes2, 0);
  133. if(bytes1) {
  134. audioRenderer->callback(audioRenderer->lpData, buffer1, bytes1);
  135. }
  136. if(bytes2) {
  137. audioRenderer->callback(audioRenderer->lpData, buffer2, bytes2);
  138. }
  139. audioRenderer->lpBuffer->Unlock(buffer1, bytes1, buffer2, bytes2);
  140. audioRenderer->dwNextWriteOffset += (bytes1 + bytes2); 
  141. if( audioRenderer->dwNextWriteOffset >= audioRenderer->dwBufferSize ) {
  142. audioRenderer->dwNextWriteOffset -= audioRenderer->dwBufferSize;
  143. }
  144. InterlockedExchange(&audioRenderer->lInTimer, FALSE);
  145. return;
  146. }
  147. }
  148. /*
  149.  * Gives the exact number of milliseconds
  150.  * of audio played since the call to Play()
  151.  *
  152.  */
  153. unsigned long AudioRenderer::AudioTime()
  154. {
  155. DWORD dwPlay, dwWrite;
  156. if(this->lpBuffer != NULL)
  157. this->lpBuffer->GetCurrentPosition(&dwPlay, &dwWrite);
  158. else 
  159. return 0;
  160. if(dwPlay < this->dwLastPlayPos) {
  161. this->dwPlayed += ( (this->dwBufferSize - this->dwLastPlayPos) + dwPlay);
  162. }
  163. else {
  164. this->dwPlayed += (dwPlay - this->dwLastPlayPos);
  165. }
  166. this->dwLastPlayPos = dwPlay;
  167. return (unsigned long) (( ((double) this->dwPlayed * (1000/(this->ourFormat->wBitsPerSample*this->ourFormat->nChannels/8)))) / (this->ourFormat->nSamplesPerSec));
  168. }
  169. /*
  170.  * Bufferize an entire buffer of data
  171.  * this is used after seeking...
  172.  */
  173. int AudioRenderer::Bufferize()
  174. {
  175. if(this->lpBuffer) {
  176. void *buffer1, *buffer2;
  177. DWORD bytes1, bytes2;
  178. /*
  179.  * First bufferise some data
  180.  */
  181. this->lpBuffer->SetCurrentPosition(0);
  182. this->lpBuffer->Lock(0, this->dwBufferSize,
  183.     &buffer1, &bytes1, &buffer2, &bytes2, 0);
  184. this->callback(this->lpData, buffer1, bytes1);
  185. this->lpBuffer->Unlock(buffer1, bytes1, buffer2, bytes2);
  186. this->dwNextWriteOffset = this->dwProgress = this->dwPlayed = this->dwLastPlayPos = 0;
  187. }
  188. return 1;
  189. }
  190. /*
  191.  * Starts the playback : Bufferize and 
  192.  * launch the thread.
  193.  *
  194.  */
  195. int AudioRenderer::Start()
  196. {
  197. if(this->lpBuffer) {
  198. void *buffer1, *buffer2;
  199. DWORD bytes1, bytes2;
  200. /*
  201.  * First bufferise some data
  202.  */
  203. this->lpBuffer->SetCurrentPosition(0);
  204. this->lpBuffer->Lock(0, this->dwBufferSize,
  205.     &buffer1, &bytes1, &buffer2, &bytes2, 0);
  206. this->callback(this->lpData, buffer1, bytes1);
  207. this->lpBuffer->Unlock(buffer1, bytes1, buffer2, bytes2);
  208. this->dwNextWriteOffset = this->dwProgress = this->dwPlayed = this->dwLastPlayPos = 0;
  209. /*
  210.  * Then start playing!
  211.  */
  212. this->paused = 0;
  213. this->lpBuffer->Play(0, 0, DSBPLAY_LOOPING);
  214. if( timeBeginPeriod( 10 ) != 0 ) {
  215. return 0;
  216. }
  217.         else {
  218. this->uTimerID = timeSetEvent( 10, 1, TimeFunc, (DWORD)(LPVOID)this, TIME_PERIODIC );
  219. }
  220. }
  221. return 1;
  222. }
  223. /*
  224.  * Toggle Pause
  225.  *
  226.  */
  227. int AudioRenderer::Pause()
  228. {
  229. if(this->paused) {
  230. this->paused = 0;
  231. this->lpBuffer->Play(0, 0, DSBPLAY_LOOPING);
  232. this->uTimerID = timeSetEvent( 10, 1, TimeFunc, (DWORD)(LPVOID)this, TIME_PERIODIC );
  233. }
  234. else {
  235. if(this->uTimerID) {
  236. timeKillEvent(this->uTimerID); 
  237.   }
  238. this->paused = 1;
  239. this->lpBuffer->Stop();
  240. }
  241. return 1;
  242. }
  243. /*
  244.  * Stops the playback 
  245.  * and timer
  246.  *
  247.  */
  248. int AudioRenderer::Stop()
  249. {
  250. if(this->uTimerID) {
  251. timeKillEvent(this->uTimerID); 
  252.   }
  253. if(this->lpBuffer) {
  254. this->lpBuffer->Stop();
  255. timeEndPeriod(10); 
  256. }
  257. return 1;
  258. }
  259. /*
  260.  * Closes propermy DSound.
  261.  */
  262. int AudioRenderer::Close()
  263. {
  264. this->Stop();
  265. if(this->lpDirectSound) {
  266. if(this->lpBuffer)
  267. this->lpBuffer->Release();
  268. this->lpDirectSound->Release();
  269. }
  270. return 1;
  271. }