Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2125 lines
56 KiB

  1. /*
  2. *) Functions to simplify recording & playback of wave file/data to a line/phone
  3. *) Put the code in TAPI32L.LIB? Then only apps that need it, get it
  4. +) tapiMakeNoise(
  5. DWORD Device Type: PHONE/LINE/WAVE, etc?
  6. HANDLE Device Handle,
  7. DWORD NoiseType: BUFFER/FILENAME/HFILE(readfile directly?)/MMIOHANDLE
  8. HANDLE hArray - array of type NoiseTypes that are to be played serially
  9. DWORD Flags:
  10. fSYNC
  11. fSTOP_EXISTING_PLAYING_IF_ANY
  12. );
  13. -) How to handle hardware assist? IE: Hey, hardware, play prompt #7 - how would an
  14. app know how/when to request that?
  15. -) What about proprietary wave formats? How to know what proprietary formats the hardware supports?
  16. Just try it?
  17. -) What about conversions? How to know what conversions the hardware can do
  18. -) How about a notification method? Such that an app can know when the wave is done.
  19. -)
  20. */
  21. #define STRICT
  22. #include "windows.h"
  23. #include "windowsx.h"
  24. #include "mmsystem.h"
  25. #include "tapi.h"
  26. #if DBG
  27. VOID
  28. DbgPrtWave(
  29. IN DWORD dwDbgLevel,
  30. IN PTCHAR lpszFormat,
  31. IN ...
  32. )
  33. /*++
  34. Routine Description:
  35. Formats the incoming debug message & calls DbgPrint
  36. Arguments:
  37. DbgLevel - level of message verboseness
  38. DbgMessage - printf-style format string, followed by appropriate
  39. list of arguments
  40. Return Value:
  41. --*/
  42. {
  43. // if (dwDbgLevel <= gdwDebugLevel)
  44. {
  45. TCHAR buf[1280];
  46. va_list ap;
  47. va_start(ap, lpszFormat);
  48. wsprintf(buf, TEXT("CallUpW (0x%08lx) - "), GetCurrentThreadId() );
  49. wvsprintf (&buf[23],
  50. lpszFormat,
  51. ap
  52. );
  53. lstrcat (buf, TEXT("\n"));
  54. OutputDebugString (buf);
  55. va_end(ap);
  56. }
  57. }
  58. #define WDBGOUT(_x_) DbgPrtWave _x_
  59. #else
  60. #define WDBGOUT(_x_)
  61. #endif
  62. //****************************************************************************
  63. //****************************************************************************
  64. //****************************************************************************
  65. unsigned long WINAPI WaveThread( LPVOID junk );
  66. void CALLBACK WaveOutCallback(
  67. HWAVE hWave, // handle of waveform device
  68. UINT uMsg, // sent message
  69. DWORD dwInstance, // instance data
  70. DWORD dwParam1, // application-defined parameter
  71. DWORD dwParam2 // application-defined parameter
  72. );
  73. enum
  74. {
  75. DEVICE_WAVEID,
  76. DEVICE_WAVEHANDLE,
  77. DEVICE_HLINE,
  78. DEVICE_HPHONE,
  79. DEVICE_HCALL
  80. };
  81. enum
  82. {
  83. SOURCE_WAVEFILE,
  84. SOURCE_MSDOSFILE,
  85. SOURCE_MEM
  86. };
  87. class WaveDevice;
  88. class WaveOperation;
  89. #define OPERATIONSTATUS_DONTPLAYTHIS 0x00000001
  90. #define MAX_NUM_BUFFERS (8)
  91. #define BUFFER_SIZE (8192)
  92. typedef struct {
  93. ULONG uBufferLength;
  94. WaveOperation * poWaveOperation;
  95. PBYTE pBuffer;
  96. } MISCINFO;
  97. //****************************************************************************
  98. //****************************************************************************
  99. LONG gfInited = 0;
  100. BOOLEAN gfShutdown = FALSE;
  101. WaveDevice *gpoWaveDeviceList = NULL;
  102. HANDLE ghFreeBufferEvent = 0;
  103. HANDLE ghWaveThread = NULL;
  104. MISCINFO *gDoneBuffersToBeProcessed[MAX_NUM_BUFFERS + 1];
  105. CRITICAL_SECTION gCriticalSection;
  106. //****************************************************************************
  107. //****************************************************************************
  108. //****************************************************************************
  109. class WaveOperation
  110. {
  111. public:
  112. DWORD dwSourceType;
  113. union
  114. {
  115. PTSTR psz;
  116. PBYTE pb;
  117. HANDLE h;
  118. LONG l;
  119. } SourceThing;
  120. class WaveOperation * pNextWaveOperationInList;
  121. class WaveDevice * poWaveDevice;
  122. HANDLE hSyncEvent;
  123. DWORD dwStatus;
  124. DWORD cFileSize;
  125. DWORD cDataRemaining;
  126. DWORD cDataDonePlaying;
  127. BOOLEAN fInited;
  128. LONG WaveOperation::InitOperation(
  129. class WaveDevice * poWaveDevice,
  130. DWORD dwSoundTypeIn,
  131. LONG lSourceThing
  132. );
  133. virtual LONG InitSpecific( void ) = 0;
  134. virtual ULONG GetData( PBYTE pBuffer, ULONG uBufferSize ) = 0;
  135. virtual void FreeSpecific( void ) = 0;
  136. inline WaveOperation * GetpNext();
  137. inline void SetpNext( WaveOperation * );
  138. inline HANDLE GetSyncEvent();
  139. inline void SetSyncEvent( HANDLE );
  140. inline void ProcessDoneBuffer( MISCINFO * pMiscInfo );
  141. inline ULONG BytesNotDonePlaying( void );
  142. };
  143. //****************************************************************************
  144. //****************************************************************************
  145. //****************************************************************************
  146. class WaveDevice
  147. {
  148. ULONG uDeviceId;
  149. DWORD dwDeviceType;
  150. HANDLE hDevice;
  151. HWAVEOUT hWaveOut;
  152. CRITICAL_SECTION CriticalSection;
  153. ULONG uUsageCount;
  154. class WaveDevice * pNextWaveDeviceInList;
  155. class WaveOperation * CurrentWaveOperation;
  156. class WaveOperation * LastWaveOperation;
  157. ULONG Head;
  158. ULONG Tail;
  159. ULONG NumFreeBuffers;
  160. ULONG cBufferSize;
  161. PBYTE FreeQueue[MAX_NUM_BUFFERS];
  162. WAVEHDR WaveHeader[MAX_NUM_BUFFERS];
  163. MISCINFO MiscInfo[MAX_NUM_BUFFERS];
  164. DWORD dwStatusBits;
  165. public:
  166. inline ULONG GetNumFreeBuffers( void );
  167. DWORD GetStatus( void );
  168. void TerminateAllOperations( void );
  169. LONG KillWaveDevice( BOOLEAN fWaitForThreadTermination );
  170. LONG CloseWaveDevice();
  171. LONG InitWaveDevice( ULONG uDeviceId );
  172. LONG OpenWaveDevice( WAVEFORMATEX * pWaveFormat );
  173. inline WaveDevice * GetpNext();
  174. inline void SetpNext( WaveDevice * );
  175. LONG QueueOperation( class WaveOperation * );
  176. class WaveOperation * NextOperation();
  177. ULONG PlaySomeData( BOOL fPrimeOnly );
  178. inline void ReturnToFreeBufferQueue( PBYTE pBuffer );
  179. inline void IncrementBytesPlayed( ULONG cCount );
  180. inline ULONG GetWaveDeviceId( void );
  181. inline CRITICAL_SECTION * GetCriticalSection( void );
  182. // static void CALLBACK WaveOutCallback(
  183. // HWAVE hWave, // handle of waveform device
  184. // UINT uMsg, // sent message
  185. // DWORD dwInstance, // instance data
  186. // DWORD dwParam1, // application-defined parameter
  187. // DWORD dwParam2 // application-defined parameter
  188. // );
  189. void IncUsageCount( void );
  190. void DecUsageCount( void );
  191. UINT GetUsageCount( void );
  192. };
  193. //****************************************************************************
  194. LONG WaveDevice::InitWaveDevice( ULONG uDevId )
  195. {
  196. LONG lResult = 0;
  197. ULONG n;
  198. WDBGOUT((4, "Entering InitWaveDevice"));
  199. //
  200. // Alloc some buffers
  201. //
  202. Head = 0;
  203. Tail = 0;
  204. NumFreeBuffers = 0;
  205. uUsageCount = 0;
  206. dwStatusBits = 0;
  207. cBufferSize = BUFFER_SIZE;
  208. uDeviceId = uDevId;
  209. for ( n = 0; n < MAX_NUM_BUFFERS; n++ )
  210. {
  211. FreeQueue[n] = (PBYTE)LocalAlloc(LPTR, cBufferSize);
  212. if ( NULL == FreeQueue[n] )
  213. {
  214. WDBGOUT((1, "Mem alloc failed. Size= 0x%08lx", cBufferSize));
  215. while ( n )
  216. {
  217. LocalFree( FreeQueue[n-1] );
  218. n--;
  219. }
  220. return( LINEERR_NOMEM );
  221. }
  222. NumFreeBuffers++;
  223. }
  224. InitializeCriticalSection( &CriticalSection );
  225. CurrentWaveOperation = NULL;
  226. LastWaveOperation = NULL;
  227. return( lResult );
  228. }
  229. //****************************************************************************
  230. inline ULONG WaveDevice::GetWaveDeviceId( void )
  231. {
  232. return uDeviceId;
  233. }
  234. //****************************************************************************
  235. inline ULONG WaveDevice::GetNumFreeBuffers( void )
  236. {
  237. return NumFreeBuffers;
  238. }
  239. //****************************************************************************
  240. LONG WaveDevice::OpenWaveDevice( WAVEFORMATEX * pWaveFormat )
  241. {
  242. ULONG u;
  243. LONG lResult;
  244. WDBGOUT((4, "Entering OpenWaveDevice"));
  245. lResult = (LONG)waveOutOpen(
  246. &hWaveOut,
  247. uDeviceId,
  248. pWaveFormat,
  249. (DWORD)WaveOutCallback,
  250. (DWORD)this,
  251. CALLBACK_FUNCTION | WAVE_MAPPED
  252. );
  253. //{
  254. // TCHAR buf[500];
  255. // wsprintf( buf, "woo on %lx ret=0x%lx", uDeviceId, lResult);
  256. // MessageBox(GetFocus(), buf, buf, MB_OK);
  257. //}
  258. if ( lResult )
  259. {
  260. WDBGOUT((1, "waveOutOpen returned 0x%08lx", lResult ));
  261. return( LINEERR_NOMEM); //TODO LATER: Diff ret codes?
  262. }
  263. for ( u = 0; u < NumFreeBuffers; u++ )
  264. {
  265. WaveHeader[u].lpData = (LPSTR)FreeQueue[u];
  266. WaveHeader[u].dwBufferLength = cBufferSize;
  267. WaveHeader[u].dwFlags = 0;
  268. lResult = waveOutPrepareHeader(
  269. hWaveOut,
  270. &(WaveHeader[u]),
  271. sizeof(WAVEHDR)
  272. );
  273. if ( lResult )
  274. {
  275. WDBGOUT((1, TEXT("waveOutPrepareHeader returned 0x%08lx"), lResult ));
  276. return( LINEERR_NOMEM); //TODO LATER: Diff ret codes?
  277. }
  278. }
  279. WDBGOUT((4, TEXT("Leaving OpenWaveDevice result = 0x0")));
  280. return( 0 );
  281. }
  282. ////****************************************************************************
  283. //LONG WaveDevice::RestartDevice( WAVEFORMATEX * pWaveFormat )
  284. //{
  285. // ULONG n;
  286. //
  287. //
  288. // WDBGOUT((4, "Entering RestartDevice"));
  289. //
  290. //
  291. // // Reset wave device
  292. // WDBGOUT((4, TEXT("Resetting the wave device...")));
  293. // waveOutReset( hWaveOut );
  294. //
  295. // //
  296. // // Wait until all of the outstanding buffers are back.
  297. // //
  298. // WDBGOUT((4, TEXT("Waiting for all buffers to be returned...")));
  299. // while ( NumFreeBuffers < MAX_NUM_BUFFERS )
  300. // {
  301. // Sleep(0);
  302. // }
  303. //
  304. // WDBGOUT((4, TEXT("Closing the wave device...")));
  305. // waveOutClose( hWaveOut );
  306. //
  307. //
  308. //
  309. // return( 0 );
  310. //}
  311. //
  312. //****************************************************************************
  313. LONG WaveDevice::CloseWaveDevice()
  314. {
  315. WDBGOUT((4, "Entering CloseWaveDevice"));
  316. // Reset wave device
  317. WDBGOUT((4, TEXT("Resetting the wave device...")));
  318. waveOutReset( hWaveOut );
  319. //
  320. // Wait until all of the outstanding buffers are back.
  321. //
  322. WDBGOUT((4, TEXT("Waiting for all buffers to be returned...")));
  323. while ( NumFreeBuffers < MAX_NUM_BUFFERS )
  324. {
  325. Sleep(0);
  326. }
  327. WDBGOUT((4, TEXT("Closing the wave device...")));
  328. waveOutClose( hWaveOut );
  329. return( 0 );
  330. }
  331. //****************************************************************************
  332. LONG WaveDevice::KillWaveDevice( BOOLEAN fWaitForThreadTermination )
  333. {
  334. ULONG n;
  335. WaveDevice * poTempDevice;
  336. WDBGOUT((4, "Entering KillWaveDevice"));
  337. // Reset wave device
  338. WDBGOUT((4, TEXT("Resetting the wave device...")));
  339. waveOutReset( hWaveOut );
  340. //
  341. // Wait until all of the outstanding buffers are back.
  342. //
  343. WDBGOUT((4, TEXT("Waiting for all buffers to be returned...")));
  344. while ( NumFreeBuffers < MAX_NUM_BUFFERS )
  345. {
  346. Sleep(0);
  347. }
  348. WDBGOUT((4, TEXT("Closing the wave device...")));
  349. waveOutClose( hWaveOut );
  350. //
  351. // Free the memory for all of the buffers
  352. //
  353. for ( n=0; n<MAX_NUM_BUFFERS; n++ )
  354. {
  355. LocalFree( FreeQueue[n] );
  356. FreeQueue[n] = NULL;
  357. }
  358. //
  359. // Remove the device from the global list
  360. //
  361. poTempDevice = gpoWaveDeviceList;
  362. if ( poTempDevice == this )
  363. {
  364. gpoWaveDeviceList = GetpNext();
  365. }
  366. else
  367. {
  368. while ( poTempDevice
  369. &&
  370. ( (*poTempDevice).GetpNext() != this )
  371. )
  372. {
  373. poTempDevice =(*poTempDevice).GetpNext();
  374. }
  375. //
  376. // The next one in the list is it. Remove the link.
  377. //
  378. if ( poTempDevice != NULL )
  379. {
  380. //
  381. // Adjust the list pointers
  382. //
  383. (*poTempDevice).SetpNext( GetpNext() );
  384. }
  385. }
  386. DeleteCriticalSection( &CriticalSection );
  387. delete this;
  388. //
  389. // Are all of the devices dead and buried?
  390. //
  391. if ( NULL == gpoWaveDeviceList )
  392. {
  393. gfShutdown = TRUE;
  394. //TODO NOW: fix this gfInited = 0;
  395. //
  396. // Signal the other thread to come down
  397. //
  398. SetEvent( ghFreeBufferEvent );
  399. //
  400. // Wait 'till the thread is dead?
  401. //
  402. if ( fWaitForThreadTermination )
  403. {
  404. WaitForSingleObject( ghWaveThread, INFINITE );
  405. }
  406. CloseHandle( ghWaveThread );
  407. //
  408. // Zero this so we start fresh next time.
  409. //
  410. // ghWaveThread = NULL;
  411. }
  412. return( 0 );
  413. }
  414. //****************************************************************************
  415. inline DWORD WaveDevice::GetStatus( void )
  416. {
  417. return dwStatusBits;
  418. }
  419. //****************************************************************************
  420. inline void WaveDevice::TerminateAllOperations( void )
  421. {
  422. WaveOperation *poWaveOperation;
  423. WDBGOUT((3, TEXT("Entering TerminateAllOps")));
  424. EnterCriticalSection( &CriticalSection );
  425. poWaveOperation = CurrentWaveOperation;
  426. while ( poWaveOperation )
  427. {
  428. WDBGOUT((4, TEXT("Tainting oper: 0x%08lx"), poWaveOperation ));
  429. (*poWaveOperation).dwStatus |= OPERATIONSTATUS_DONTPLAYTHIS;
  430. poWaveOperation = (*poWaveOperation).GetpNext();
  431. }
  432. //
  433. // Reset wave device to force all the buffers in
  434. //
  435. WDBGOUT((4, TEXT("Resetting the wave device...")));
  436. waveOutReset( hWaveOut );
  437. LeaveCriticalSection( &CriticalSection );
  438. WDBGOUT((3, TEXT("Leaving TerminateAllOps")));
  439. }
  440. //****************************************************************************
  441. inline CRITICAL_SECTION * WaveDevice::GetCriticalSection( void )
  442. {
  443. return &CriticalSection;
  444. }
  445. //****************************************************************************
  446. inline WaveDevice * WaveDevice::GetpNext()
  447. {
  448. return( pNextWaveDeviceInList );
  449. }
  450. //****************************************************************************
  451. inline void WaveDevice::SetpNext(WaveDevice * pWaveDevice)
  452. {
  453. pNextWaveDeviceInList = pWaveDevice;
  454. }
  455. //****************************************************************************
  456. inline void WaveDevice::IncUsageCount( void )
  457. {
  458. uUsageCount++;
  459. };
  460. //****************************************************************************
  461. inline void WaveDevice::DecUsageCount( void )
  462. {
  463. uUsageCount--;
  464. };
  465. //****************************************************************************
  466. inline UINT WaveDevice::GetUsageCount( void )
  467. {
  468. return uUsageCount;
  469. };
  470. //****************************************************************************
  471. LONG WaveDevice::QueueOperation( class WaveOperation *poNewWaveOperation )
  472. {
  473. WDBGOUT((3, TEXT("Entering QueueOperation")));
  474. EnterCriticalSection( &CriticalSection );
  475. (*poNewWaveOperation).SetpNext( NULL );
  476. //
  477. // Add operation to list
  478. //
  479. if ( LastWaveOperation )
  480. {
  481. (*LastWaveOperation).SetpNext( poNewWaveOperation );
  482. }
  483. LastWaveOperation = poNewWaveOperation;
  484. if ( NULL == CurrentWaveOperation )
  485. {
  486. CurrentWaveOperation = poNewWaveOperation;
  487. }
  488. LeaveCriticalSection( &CriticalSection );
  489. WDBGOUT((4, TEXT("Created new oper: 0x%08lx"), poNewWaveOperation));
  490. WDBGOUT((3, TEXT("Leaving QueueOperation")));
  491. return( 0 );
  492. }
  493. //****************************************************************************
  494. class WaveOperation * WaveDevice::NextOperation()
  495. {
  496. //
  497. // This function will get rid of the operation at the top of this wave
  498. // device's operation queue, and will update the queue to reflect the next
  499. // as now the first.
  500. //
  501. WDBGOUT((3, TEXT("Entering NextOperation")));
  502. EnterCriticalSection( &CriticalSection );
  503. if ( CurrentWaveOperation )
  504. {
  505. WaveOperation * poWaveOperation;
  506. WaveOperation * poTempOperation;
  507. poWaveOperation = (*CurrentWaveOperation).GetpNext();
  508. delete CurrentWaveOperation;
  509. while ( poWaveOperation )
  510. {
  511. //
  512. // If we can play this operation, break outta this loop
  513. //
  514. if ( !( (*poWaveOperation).dwStatus & OPERATIONSTATUS_DONTPLAYTHIS) )
  515. {
  516. WDBGOUT((55, TEXT("How much break?")));
  517. break;
  518. }
  519. //
  520. // We're not supposed to play this operation
  521. //
  522. if ( (*poWaveOperation).hSyncEvent )
  523. {
  524. WDBGOUT((5, TEXT("Caller was waiting. Signaling...")));
  525. SetEvent( (*poWaveOperation).hSyncEvent );
  526. }
  527. poTempOperation = (*poWaveOperation).GetpNext();
  528. delete poWaveOperation;
  529. poWaveOperation = poTempOperation;
  530. }
  531. WDBGOUT((55, TEXT("Not too much")));
  532. CurrentWaveOperation = poWaveOperation;
  533. }
  534. WDBGOUT((55, TEXT("was it Too much?")));
  535. //
  536. // The CurrentWaveOperation may have been "NULLED" out by the previous stuff
  537. //
  538. if ( NULL == CurrentWaveOperation )
  539. {
  540. LastWaveOperation = NULL;
  541. }
  542. LeaveCriticalSection( &CriticalSection );
  543. WDBGOUT((4, TEXT("Leaving NextOperation - returning 0x%08lx"), CurrentWaveOperation));
  544. return( CurrentWaveOperation );
  545. }
  546. //****************************************************************************
  547. inline void WaveDevice::ReturnToFreeBufferQueue( PBYTE pBuffer )
  548. {
  549. FreeQueue[Tail] = pBuffer;
  550. //
  551. // If we're at the end of the list, wrap.
  552. //
  553. Tail = ( Tail + 1 ) % MAX_NUM_BUFFERS;
  554. NumFreeBuffers++;
  555. }
  556. //****************************************************************************
  557. inline void WaveDevice::IncrementBytesPlayed( ULONG cCount )
  558. {
  559. // //
  560. // // If there is an operation on the dying queue, this must be from it
  561. // //
  562. // if ( DyingWaveOperation )
  563. // {
  564. // //
  565. // // Is it dead yet?
  566. // //
  567. // if ( 0 == DyingWaveOperation->BytesNotDonePlaying() )
  568. // {
  569. // WaveOperation * poNextOperation;
  570. //
  571. // EnterCriticalSection( &CriticalSection );
  572. //
  573. // //
  574. // // Yes, it's dead.
  575. // //
  576. // poNextOperation = DyingWaveOperation->GetpNext();
  577. //
  578. // //
  579. // // Was the caller waiting (ie: was it sync) ?
  580. // //
  581. // if ( (*DyingWaveOperation).GetSyncEvent() )
  582. // {
  583. // SetEvent( (*DyingWaveOperation).GetSyncEvent() );
  584. // }
  585. //
  586. // delete DyingWaveOperation;
  587. //
  588. // DyingWaveOperation = poNextOperation;
  589. //
  590. // LeaveCriticalSection( &CriticalSection );
  591. // }
  592. // }
  593. //
  594. //TODO LATER: Keep a total count of bytes played out this device?
  595. }
  596. //****************************************************************************
  597. //****************************************************************************
  598. //****************************************************************************
  599. //****************************************************************************
  600. LONG WaveOperation::InitOperation(
  601. class WaveDevice * poWaveDeviceIn,
  602. DWORD dwSourceTypeIn,
  603. LONG lSourceThing
  604. )
  605. {
  606. WDBGOUT((4, TEXT("Entering InitOperation")));
  607. dwSourceType = dwSourceTypeIn;
  608. SourceThing.l = lSourceThing;
  609. poWaveDevice = poWaveDeviceIn;
  610. pNextWaveOperationInList = NULL;
  611. (*poWaveDevice).IncUsageCount();
  612. dwStatus = 0;
  613. fInited = FALSE;
  614. return(0);
  615. }
  616. //****************************************************************************
  617. inline HANDLE WaveOperation::GetSyncEvent()
  618. {
  619. return( hSyncEvent );
  620. }
  621. //****************************************************************************
  622. inline void WaveOperation::SetSyncEvent( HANDLE hEvent )
  623. {
  624. hSyncEvent = hEvent;
  625. return;
  626. }
  627. //****************************************************************************
  628. inline WaveOperation * WaveOperation::GetpNext()
  629. {
  630. return( pNextWaveOperationInList );
  631. }
  632. //****************************************************************************
  633. inline void WaveOperation::SetpNext(WaveOperation * pWaveOperation)
  634. {
  635. pNextWaveOperationInList = pWaveOperation;
  636. }
  637. //****************************************************************************
  638. inline void WaveOperation::ProcessDoneBuffer( MISCINFO * pMiscInfo )
  639. {
  640. ULONG nBytesQueued;
  641. WDBGOUT((3, TEXT("Entering ProcessDoneBuffer")));
  642. cDataDonePlaying += pMiscInfo->uBufferLength;
  643. WDBGOUT((11, TEXT("Now - size=0x%08lx done=0x%08lx"),
  644. cFileSize,
  645. cDataDonePlaying));
  646. (*poWaveDevice).IncrementBytesPlayed( pMiscInfo->uBufferLength );
  647. (*poWaveDevice).ReturnToFreeBufferQueue( pMiscInfo->pBuffer );
  648. //
  649. // Has someone decided this wave should stop?
  650. //
  651. if ( dwStatus & OPERATIONSTATUS_DONTPLAYTHIS )
  652. {
  653. if ( (*poWaveDevice).GetNumFreeBuffers() != MAX_NUM_BUFFERS )
  654. {
  655. WDBGOUT((4, TEXT("Bailing from ProcessDoneBuffer - dontplay")));
  656. return;
  657. }
  658. cDataDonePlaying = cFileSize;
  659. }
  660. //
  661. // Is this thing already dead?
  662. //
  663. if ( cDataDonePlaying >= cFileSize )
  664. {
  665. WDBGOUT((4, TEXT("Done playing this:0x%08lx"), this ));
  666. //
  667. // Was the caller waiting (ie: was it sync) ?
  668. //
  669. if ( hSyncEvent )
  670. {
  671. WDBGOUT((5, TEXT("Caller was waiting. Signaling...")));
  672. SetEvent( hSyncEvent );
  673. }
  674. //TODO LATER: PERFORMANCE: If the next format is the same as this one, don't close the device
  675. (*poWaveDevice).CloseWaveDevice();
  676. (*poWaveDevice).DecUsageCount();
  677. EnterCriticalSection( &gCriticalSection );
  678. //
  679. // Was this the last oper?
  680. //
  681. if ( (*poWaveDevice).GetUsageCount() == 0 )
  682. {
  683. WDBGOUT((4, TEXT("Last oper out...")));
  684. (*poWaveDevice).KillWaveDevice(FALSE);
  685. }
  686. else
  687. {
  688. WaveOperation * pNewOperation;
  689. //
  690. // Move up the next operation
  691. //
  692. while ( TRUE )
  693. {
  694. pNewOperation = (*poWaveDevice).NextOperation();
  695. if ( NULL == pNewOperation )
  696. {
  697. if ( (*poWaveDevice).GetUsageCount() == 0 )
  698. {
  699. WDBGOUT((4, TEXT("No more ops to run...")));
  700. (*poWaveDevice).KillWaveDevice(FALSE);
  701. }
  702. //
  703. // All operations done. Go away.
  704. //
  705. WDBGOUT((3, TEXT("All operations seem to be done...")));
  706. break;
  707. }
  708. WDBGOUT((3, TEXT("Playing data from new op...")));
  709. nBytesQueued = (*poWaveDevice).PlaySomeData( FALSE );
  710. if ( nBytesQueued )
  711. {
  712. //
  713. // There were some bytes played. Break the loop...
  714. //
  715. break;
  716. }
  717. //
  718. // Was the caller waiting (ie: was it sync) ?
  719. //
  720. if ( pNewOperation->hSyncEvent )
  721. {
  722. WDBGOUT((3, TEXT("No data in new op and caller is waiting...")));
  723. SetEvent( pNewOperation->hSyncEvent );
  724. }
  725. //
  726. // Update the counter. This op is, for all intents and purposes, done.
  727. //
  728. (*poWaveDevice).DecUsageCount();
  729. WDBGOUT((3, TEXT("No data in new op. Looking for next...")));
  730. }
  731. }
  732. FreeSpecific();
  733. delete this;
  734. LeaveCriticalSection( &gCriticalSection );
  735. }
  736. else
  737. {
  738. WDBGOUT((3, TEXT("Playing data from same op...")));
  739. (*poWaveDevice).PlaySomeData( FALSE );
  740. }
  741. WDBGOUT((3, TEXT("Leaving ProcessDoneBuffer")));
  742. }
  743. //****************************************************************************
  744. //****************************************************************************
  745. inline ULONG WaveOperation::BytesNotDonePlaying( void )
  746. {
  747. return cFileSize - cDataDonePlaying;
  748. }
  749. //****************************************************************************
  750. //****************************************************************************
  751. class BufferWave: public WaveOperation
  752. {
  753. PBYTE pData; // Pointer to the data to play
  754. PBYTE pCurrentPointer;
  755. public:
  756. LONG BufferWave::InitSpecific( void );
  757. ULONG GetData( PBYTE pBuffer, ULONG uBufferSize );
  758. void BufferWave::FreeSpecific( void );
  759. };
  760. //****************************************************************************
  761. LONG BufferWave::InitSpecific( void )
  762. {
  763. pData = SourceThing.pb;
  764. pCurrentPointer = pData;
  765. return(0);
  766. }
  767. //****************************************************************************
  768. ULONG BufferWave::GetData( PBYTE pBuffer, ULONG uBufferSize )
  769. {
  770. ULONG uBytesToPlay;
  771. uBytesToPlay = (cDataRemaining > uBufferSize) ?
  772. uBufferSize :
  773. cDataRemaining;
  774. cDataRemaining -= uBytesToPlay;
  775. memcpy( pBuffer, pCurrentPointer, uBytesToPlay );
  776. pCurrentPointer += uBytesToPlay;
  777. return( uBytesToPlay );
  778. }
  779. //****************************************************************************
  780. void BufferWave::FreeSpecific( void )
  781. {
  782. return;
  783. }
  784. //****************************************************************************
  785. //****************************************************************************
  786. class WaveFile: public WaveOperation
  787. {
  788. HMMIO hmmio;
  789. public:
  790. LONG WaveFile::InitSpecific( void );
  791. ULONG GetData( PBYTE pBuffer, ULONG uBufferSize );
  792. void WaveFile::FreeSpecific( void );
  793. };
  794. //****************************************************************************
  795. LONG WaveFile::InitSpecific( void )
  796. {
  797. MMCKINFO mmckinfoParent; /* parent chunk information structure */
  798. MMCKINFO mmckinfoSubchunk; /* subchunk information structure */
  799. DWORD dwFmtSize; /* size of "fmt" chunk */
  800. WAVEFORMATEX Format; /* pointer to memory for "fmt" chunk */
  801. LONG lResult;
  802. WDBGOUT((4, TEXT("Entering WaveFile::InitSpecific")));
  803. hmmio = mmioOpen(
  804. SourceThing.psz,
  805. NULL,
  806. MMIO_READ
  807. );
  808. //
  809. // Did the open go ok?
  810. //
  811. if ( NULL == hmmio )
  812. {
  813. //
  814. // Nope.
  815. //
  816. WDBGOUT((1, TEXT("Error during mmioOpen of [%s] - err=0x%08lx"),
  817. (SourceThing.psz == NULL) ? "" : SourceThing.psz,
  818. GetLastError() ));
  819. return LINEERR_OPERATIONFAILED;
  820. }
  821. /*
  822. * Locate a "RIFF" chunk with a "WAVE" form type
  823. * to make sure the file is a WAVE file.
  824. */
  825. mmckinfoParent.fccType = mmioFOURCC('W', 'A', 'V', 'E');
  826. WDBGOUT((11, TEXT("Descend WAVE")));
  827. if ( mmioDescend(
  828. hmmio,
  829. (LPMMCKINFO) &mmckinfoParent,
  830. NULL,
  831. MMIO_FINDRIFF)
  832. )
  833. {
  834. WDBGOUT((1, TEXT("This is not a WAVE file - [%s]"),
  835. (SourceThing.psz == NULL) ? "" : SourceThing.psz));
  836. mmioClose( hmmio, 0);
  837. return LINEERR_INVALPARAM;
  838. }
  839. /*
  840. * Find the "fmt " chunk (form type "fmt "); it must be
  841. * a subchunk of the "RIFF" parent chunk.
  842. */
  843. mmckinfoSubchunk.ckid = mmioFOURCC('f', 'm', 't', ' ');
  844. WDBGOUT((11, TEXT("Descend FMT")));
  845. if ( mmioDescend(
  846. hmmio,
  847. &mmckinfoSubchunk,
  848. &mmckinfoParent,
  849. MMIO_FINDCHUNK)
  850. )
  851. {
  852. WDBGOUT((1, TEXT("WAVE file has no \"fmt\" chunk")));
  853. mmioClose(hmmio, 0);
  854. return LINEERR_INVALPARAM;
  855. }
  856. /*
  857. * Get the size of the "fmt " chunk--allocate and lock memory for it.
  858. */
  859. dwFmtSize = mmckinfoSubchunk.cksize;
  860. WDBGOUT((11, TEXT("read fmt")));
  861. /* Read the "fmt " chunk. */
  862. mmioRead(
  863. hmmio,
  864. (HPSTR)&Format,
  865. sizeof(Format) );
  866. // {
  867. // WDBGOUT((1, TEXT("Failed to read format chunk.")));
  868. // mmioClose(pMyWaveFile->hmmio, 0);
  869. // return 1;
  870. // }
  871. WDBGOUT((11, TEXT("Ascend fmt")));
  872. /* Ascend out of the "fmt " subchunk. */
  873. mmioAscend(hmmio, &mmckinfoSubchunk, 0);
  874. /*
  875. * Find the data subchunk. The current file position
  876. * should be at the beginning of the data chunk.
  877. */
  878. mmckinfoSubchunk.ckid = mmioFOURCC('d', 'a', 't', 'a');
  879. WDBGOUT((11, TEXT("Descend DATA")));
  880. if ( mmioDescend(
  881. hmmio,
  882. &mmckinfoSubchunk,
  883. &mmckinfoParent,
  884. MMIO_FINDCHUNK)
  885. )
  886. {
  887. WDBGOUT((1, TEXT("WAVE file has no data chunk.")));
  888. mmioClose(hmmio, 0);
  889. return LINEERR_INVALPARAM;
  890. }
  891. /* Get the size of the data subchunk. */
  892. cFileSize = mmckinfoSubchunk.cksize;
  893. cDataRemaining = mmckinfoSubchunk.cksize;
  894. cDataDonePlaying = 0;
  895. WDBGOUT((11, TEXT("OpenWaveDev")));
  896. lResult = poWaveDevice->OpenWaveDevice( &Format );
  897. // if ( cDataRemaining == 0L)
  898. // {
  899. // WDBGOUT((1, TEXT("The data chunk contains no data.")));
  900. // mmioClose(hmmio, 0);
  901. // return 0; //TODO LATER: Right? It's not an error...
  902. // It'll just get 0 bytes on the first read...
  903. // }
  904. return( lResult );
  905. }
  906. //****************************************************************************
  907. ULONG WaveFile::GetData( PBYTE pBuffer, ULONG uBufferSize )
  908. {
  909. ULONG uBytesToPlay;
  910. ULONG uBytesRead;
  911. WDBGOUT((11, TEXT("Entering WaveFile::GetData")));
  912. //
  913. // Have we done anything yet?
  914. //
  915. if ( !fInited )
  916. {
  917. if ( InitSpecific() )
  918. {
  919. return( 0 );
  920. }
  921. fInited = TRUE;
  922. }
  923. uBytesToPlay = (cDataRemaining > uBufferSize) ?
  924. uBufferSize :
  925. cDataRemaining;
  926. if ( 0 == uBytesToPlay )
  927. {
  928. return 0;
  929. }
  930. /* Read the waveform data subchunk. */
  931. uBytesRead = mmioRead(
  932. hmmio,
  933. (LPSTR)pBuffer,
  934. uBytesToPlay
  935. );
  936. if ( uBytesRead != uBytesToPlay )
  937. {
  938. WDBGOUT((1, TEXT("Failed to properly read data chunk.")));
  939. mmioClose(hmmio, 0);
  940. return 0;
  941. }
  942. cDataRemaining -= uBytesToPlay;
  943. return( uBytesToPlay );
  944. }
  945. //****************************************************************************
  946. void WaveFile::FreeSpecific( void )
  947. {
  948. mmioClose(hmmio, 0);
  949. return;
  950. }
  951. //****************************************************************************
  952. //****************************************************************************
  953. class DosFile: public WaveOperation
  954. {
  955. HANDLE hFile;
  956. public:
  957. LONG DosFile::InitSpecific( void );
  958. ULONG GetData( PBYTE pBuffer, ULONG uBufferSize );
  959. void DosFile::FreeSpecific( void );
  960. };
  961. //****************************************************************************
  962. LONG DosFile::InitSpecific( void )
  963. {
  964. BOOL fResult;
  965. // WIN32_FILE_ATTRIBUTE_DATA FileInfo;
  966. BY_HANDLE_FILE_INFORMATION FileInfo;
  967. hFile = CreateFile(
  968. SourceThing.psz,
  969. GENERIC_READ,
  970. FILE_SHARE_READ,
  971. NULL,
  972. OPEN_EXISTING,
  973. FILE_ATTRIBUTE_NORMAL,
  974. NULL
  975. );
  976. if ( 0 == hFile )
  977. {
  978. WDBGOUT((1, TEXT("Error doing OpenFile( lpszName ) GetLastError=0x%)8lx"),
  979. SourceThing.psz, GetLastError() ));
  980. return( LINEERR_OPERATIONFAILED );
  981. }
  982. // fResult = GetFileAttributesEx( SourceThing.psz,
  983. // GetFileExInfoStandard,
  984. // (PVOID) &FileInfo
  985. // );
  986. fResult = GetFileInformationByHandle( hFile, &FileInfo );
  987. if ( fResult )
  988. {
  989. //TODO LATER: Handle > 4 gig files
  990. //
  991. // Uh, we don't really handle gigabyte files...
  992. //
  993. if ( FileInfo.nFileSizeHigh )
  994. {
  995. cFileSize = (DWORD)-1;
  996. cDataRemaining = (DWORD)-1;
  997. }
  998. else
  999. {
  1000. cFileSize = FileInfo.nFileSizeLow;
  1001. cDataRemaining = FileInfo.nFileSizeLow;
  1002. }
  1003. }
  1004. else
  1005. {
  1006. cFileSize = 0;
  1007. cDataRemaining = 0;
  1008. }
  1009. cDataDonePlaying = 0;
  1010. return(0);
  1011. }
  1012. //****************************************************************************
  1013. ULONG DosFile::GetData( PBYTE pBuffer, ULONG uBufferSize )
  1014. {
  1015. BOOL fResult;
  1016. UINT uBytesRead = 0;
  1017. fResult = ReadFile( hFile,
  1018. pBuffer,
  1019. uBufferSize,
  1020. (LPDWORD)&uBytesRead,
  1021. NULL
  1022. );
  1023. if ( fResult )
  1024. {
  1025. if ( 0 == uBytesRead )
  1026. {
  1027. //
  1028. // We're at the end of the file
  1029. //
  1030. cDataRemaining = 0;
  1031. }
  1032. else
  1033. {
  1034. cDataRemaining -= uBytesRead;
  1035. }
  1036. }
  1037. return( uBytesRead );
  1038. }
  1039. //****************************************************************************
  1040. void DosFile::FreeSpecific( void )
  1041. {
  1042. CloseHandle( hFile );
  1043. return;
  1044. }
  1045. //****************************************************************************
  1046. //****************************************************************************
  1047. //****************************************************************************
  1048. ULONG WaveDevice::PlaySomeData( BOOL fPrimeOnly )
  1049. {
  1050. ULONG uBufferedBytes = 0;
  1051. ULONG uTotalQueuedSize = 0;
  1052. PBYTE pBuffer = NULL;
  1053. LONG lResult;
  1054. CRITICAL_SECTION *pCriticalSection;
  1055. WDBGOUT((3, TEXT("Entering PlaySomeData")));
  1056. pCriticalSection = &CriticalSection;
  1057. EnterCriticalSection( pCriticalSection );
  1058. if ( NULL != CurrentWaveOperation )
  1059. {
  1060. //
  1061. // Is it OK to play this thing?
  1062. //
  1063. if ( !((*CurrentWaveOperation).dwStatus & OPERATIONSTATUS_DONTPLAYTHIS) )
  1064. {
  1065. while ( NumFreeBuffers )
  1066. {
  1067. uBufferedBytes = (*CurrentWaveOperation).GetData( FreeQueue[Head], cBufferSize );
  1068. WDBGOUT((11, "GetData on 0x%08lx gave %ld bytes for buffer #%d",
  1069. CurrentWaveOperation,
  1070. uBufferedBytes,
  1071. Head));
  1072. if ( 0 == uBufferedBytes )
  1073. {
  1074. WDBGOUT((10, TEXT("breakin 'cause 0 bytes...")));
  1075. break;
  1076. }
  1077. WDBGOUT((10, TEXT("past if...")));
  1078. uTotalQueuedSize += uBufferedBytes;
  1079. MiscInfo[Head].uBufferLength = uBufferedBytes;
  1080. MiscInfo[Head].poWaveOperation = CurrentWaveOperation;
  1081. MiscInfo[Head].pBuffer = FreeQueue[Head];
  1082. WaveHeader[Head].dwUser = (DWORD) &MiscInfo[Head];
  1083. WaveHeader[Head].dwBufferLength = uBufferedBytes;
  1084. lResult = waveOutWrite( hWaveOut,
  1085. &WaveHeader[Head],
  1086. sizeof(WAVEHDR)
  1087. );
  1088. if ( lResult )
  1089. {
  1090. //
  1091. // Something's wrong. Quit this operation.
  1092. //
  1093. uTotalQueuedSize = 0;
  1094. uBufferedBytes = 0;
  1095. WDBGOUT((1, TEXT("waveOutWrite returned 0x%08lx"), lResult));
  1096. break;
  1097. }
  1098. Head = (Head + 1) % MAX_NUM_BUFFERS;
  1099. NumFreeBuffers--;
  1100. //
  1101. // Are we just "priming" the pump?
  1102. //
  1103. // if ( fPrimeOnly )
  1104. // {
  1105. // WDBGOUT((4, TEXT("Leaving PlaySomeData - primed (size=%08ld)"), uTotalQueuedSize ));
  1106. // LeaveCriticalSection( pCriticalSection );
  1107. // return uTotalQueuedSize;
  1108. // }
  1109. }
  1110. }
  1111. #if DBG
  1112. else
  1113. {
  1114. WDBGOUT((10, TEXT("I've been asked not to play this operation (0x%08lx)"), CurrentWaveOperation));
  1115. }
  1116. #endif
  1117. WDBGOUT((10, TEXT("past while numfreebuffers...")));
  1118. //
  1119. // We got here because we're out of buffers, or the operation is done
  1120. //
  1121. if ( 0 != uBufferedBytes )
  1122. {
  1123. //
  1124. // Must be here because we ran out of buffers...
  1125. //
  1126. LeaveCriticalSection( pCriticalSection );
  1127. return( uTotalQueuedSize );
  1128. }
  1129. //
  1130. // We get here when the current operation is all done
  1131. // (or, at least, all of its remaining data is queued in the
  1132. // wave driver)
  1133. //
  1134. }
  1135. //
  1136. // If we got here, it's because we're out of things to do
  1137. //
  1138. LeaveCriticalSection( pCriticalSection );
  1139. WDBGOUT((4, TEXT("Leaving PlaySomeData - no currop (size=%08ld)"), uTotalQueuedSize ));
  1140. return uTotalQueuedSize;
  1141. // return( 0 );
  1142. }
  1143. //****************************************************************************
  1144. //****************************************************************************
  1145. //****************************************************************************
  1146. void CALLBACK WaveOutCallback(
  1147. HWAVE hWave, // handle of waveform device
  1148. UINT uMsg, // sent message
  1149. DWORD dwInstance, // instance data
  1150. DWORD dwParam1, // application-defined parameter
  1151. DWORD dwParam2 // application-defined parameter
  1152. )
  1153. {
  1154. UINT n;
  1155. switch ( uMsg )
  1156. {
  1157. case WOM_DONE:
  1158. {
  1159. class WaveDevice * poWaveDevice =
  1160. (class WaveDevice *)dwInstance;
  1161. MISCINFO * pMiscInfo = (MISCINFO *)((LPWAVEHDR)dwParam1)->dwUser;
  1162. WDBGOUT((11, TEXT("Got DoneWithBuff msg for 0x%08lx in 0x%08lx"),
  1163. *(LPDWORD)dwParam1,
  1164. dwParam1));
  1165. // EnterCriticalSection( &gBufferCriticalSection );
  1166. n = 0;
  1167. //TODO NOW: If this buffer won't fit, it'll get lost. This can easily happen
  1168. // when there are >1 wave devices playing.
  1169. while (
  1170. ( n < MAX_NUM_BUFFERS )
  1171. &&
  1172. ( gDoneBuffersToBeProcessed[n] != NULL )
  1173. )
  1174. {
  1175. n++;
  1176. }
  1177. gDoneBuffersToBeProcessed[n] = pMiscInfo;
  1178. // LeaveCriticalSection( &gBufferCriticalSection );
  1179. SetEvent( ghFreeBufferEvent );
  1180. }
  1181. break;
  1182. case WOM_OPEN:
  1183. WDBGOUT((11, TEXT("Got Waveout Open")));
  1184. break;
  1185. case WOM_CLOSE:
  1186. WDBGOUT((11, TEXT("Got Waveout Close")));
  1187. break;
  1188. }
  1189. }
  1190. //****************************************************************************
  1191. //****************************************************************************
  1192. //****************************************************************************
  1193. //LONG tapiMakeNoise(
  1194. // DWORD Device Type: PHONE/LINE/WAVE, etc?
  1195. // HANDLE Device Handle,
  1196. // DWORD NoiseType: BUFFER/FILENAME/HFILE(readfile directly?)/MMIOHANDLE
  1197. // HANDLE hArray - array of type NoiseTypes that are to be played serially
  1198. // DWORD Flags:
  1199. // fSYNC
  1200. // fSTOP_EXISTING_PLAYING_IF_ANY
  1201. // );
  1202. // SOME FLAGS FOR THIS FUNC
  1203. #define PLAY_SYNC 0x00000001
  1204. #define KILL_ALL_NOISE 0x80000000
  1205. #ifdef __cplusplus
  1206. extern "C" { /* Assume C declarations for C++ */
  1207. #endif /* __cplusplus */
  1208. LONG WINAPI tapiPlaySound(
  1209. DWORD dwDeviceType,
  1210. HANDLE hDevice,
  1211. DWORD dwSoundType,
  1212. HANDLE hArray,
  1213. DWORD dwFlags
  1214. )
  1215. {
  1216. HANDLE hSyncEvent = NULL;
  1217. class WaveDevice * poWaveDevice;
  1218. class WaveOperation * poWaveOperation;
  1219. LONG fAreWeInited;
  1220. LONG lResult = 0;
  1221. ULONG uNormalizedWaveId = 0;
  1222. // BOOLEAN fNeedToPrimeDevice = FALSE;
  1223. WDBGOUT((3, "Entering tapiPlaySound"));
  1224. WDBGOUT((5, " dwDeviceType: %ld", dwDeviceType));
  1225. WDBGOUT((5, " hDevice: 0x%08lx", hDevice));
  1226. WDBGOUT((5, " dwSoundType: %ld", dwSoundType));
  1227. WDBGOUT((5, " hArray: 0x%08lx", hArray));
  1228. WDBGOUT((5, " dwFlags: 0x%08lx", dwFlags));
  1229. fAreWeInited = InterlockedExchange(
  1230. &gfInited,
  1231. TRUE
  1232. );
  1233. if ( 0 == fAreWeInited )
  1234. {
  1235. InitializeCriticalSection( &gCriticalSection );
  1236. }
  1237. if ( 0 == ghFreeBufferEvent )
  1238. {
  1239. ghFreeBufferEvent = CreateEvent(
  1240. NULL,
  1241. FALSE,
  1242. FALSE,
  1243. NULL
  1244. );
  1245. if ( NULL == ghFreeBufferEvent )
  1246. {
  1247. WDBGOUT((1, "CreateEvent2 failed: GetLastError = 0x%08lx", GetLastError()));
  1248. return LINEERR_NOMEM;
  1249. }
  1250. }
  1251. //
  1252. // Normalize to a wave device (and validate dwDeviceType at the same time)
  1253. //
  1254. switch ( dwDeviceType )
  1255. {
  1256. case DEVICE_WAVEID:
  1257. {
  1258. uNormalizedWaveId = (ULONG) hDevice;
  1259. }
  1260. break;
  1261. case DEVICE_WAVEHANDLE:
  1262. {
  1263. }
  1264. break;
  1265. case DEVICE_HLINE:
  1266. case DEVICE_HCALL:
  1267. {
  1268. DWORD VarString[ 8 ] =
  1269. {
  1270. sizeof(VarString),
  1271. 0,
  1272. 0,
  1273. STRINGFORMAT_BINARY,
  1274. 0,
  1275. 0,
  1276. 0
  1277. };
  1278. if ( 0 == (lResult = lineGetID(
  1279. (HLINE)hDevice,
  1280. 0,
  1281. (HCALL)hDevice,
  1282. (DEVICE_HCALL == dwDeviceType) ?
  1283. LINECALLSELECT_CALL :
  1284. LINECALLSELECT_LINE,
  1285. (LPVARSTRING)&VarString,
  1286. TEXT("wave/out")
  1287. ) ) )
  1288. {
  1289. uNormalizedWaveId = (DWORD) ((LPBYTE)VarString)[ ((LPVARSTRING)&VarString)->dwStringOffset ];
  1290. }
  1291. else
  1292. {
  1293. WDBGOUT((1, "lineGetID failed - 0x%08lx", lResult));
  1294. return LINEERR_INVALPARAM;
  1295. }
  1296. }
  1297. break;
  1298. case DEVICE_HPHONE:
  1299. {
  1300. }
  1301. break;
  1302. default:
  1303. WDBGOUT((1, "Invalid dwDeviceType (0x%08lx) passed in.", dwDeviceType));
  1304. return LINEERR_BADDEVICEID;
  1305. }
  1306. EnterCriticalSection( &gCriticalSection );
  1307. poWaveDevice = gpoWaveDeviceList;
  1308. while ( poWaveDevice )
  1309. {
  1310. if ( (*poWaveDevice).GetWaveDeviceId() == uNormalizedWaveId )
  1311. {
  1312. //
  1313. // We found it!
  1314. //
  1315. break;
  1316. }
  1317. //
  1318. // ...and I still haven't found what I'm lookin' for.
  1319. //
  1320. poWaveDevice = (*poWaveDevice).GetpNext();
  1321. }
  1322. //
  1323. // So, was it not in our list already?
  1324. //
  1325. if ( NULL == poWaveDevice )
  1326. {
  1327. //
  1328. // No, add a new device object to the list
  1329. //
  1330. poWaveDevice = new WaveDevice;
  1331. lResult = (*poWaveDevice).InitWaveDevice( uNormalizedWaveId );
  1332. if ( lResult )
  1333. {
  1334. WDBGOUT((1, TEXT("InitWaveDevice returned 0x%08lx"), lResult));
  1335. //TODO: Diff error codes for diff causes...
  1336. LeaveCriticalSection( &gCriticalSection );
  1337. return LINEERR_RESOURCEUNAVAIL;
  1338. }
  1339. (*poWaveDevice).SetpNext( gpoWaveDeviceList );
  1340. gpoWaveDeviceList = poWaveDevice;
  1341. }
  1342. //
  1343. // If the caller wants to cancel all currently queued and playing
  1344. // sound on this device, do it now
  1345. //
  1346. if ( KILL_ALL_NOISE & dwFlags )
  1347. {
  1348. (*poWaveDevice).TerminateAllOperations();
  1349. WDBGOUT((4, "Caller was asking to terminate the wave device. Done."));
  1350. // LeaveCriticalSection( &gCriticalSection );
  1351. //
  1352. // return( 0 );
  1353. }
  1354. // t-mperh 6/30 was all commented before - not sure why
  1355. //
  1356. //
  1357. // If the user passed in a NULL for hArray, we'll (for now?) assume
  1358. // he wants a no-op (or 'twas a TERMINATE request).
  1359. //
  1360. if ( NULL == hArray )
  1361. {
  1362. WDBGOUT((3, "Leaving tapiPlaySound - NULL thing"));
  1363. LeaveCriticalSection( &gCriticalSection );
  1364. return 0;
  1365. }
  1366. //**************************************************************
  1367. //NOTE: The above code fixed a problem of passing in NULL names.
  1368. // This caused an OPEN to fail and this stuff would get stuck.
  1369. // There must still be a bug that will show up when someone calls with
  1370. // a bad filename or a file that plays 0 bytes.
  1371. //**************************************************************
  1372. switch ( dwSoundType )
  1373. {
  1374. case SOURCE_WAVEFILE:
  1375. {
  1376. poWaveOperation = new WaveFile;
  1377. }
  1378. break;
  1379. case SOURCE_MSDOSFILE:
  1380. {
  1381. poWaveOperation = new DosFile;
  1382. }
  1383. break;
  1384. case SOURCE_MEM:
  1385. {
  1386. poWaveOperation = new BufferWave;
  1387. }
  1388. break;
  1389. default:
  1390. {
  1391. WDBGOUT((1, "Invalid dwSourceType - 0x%08lx", dwSoundType));
  1392. LeaveCriticalSection( &gCriticalSection );
  1393. return LINEERR_INVALPARAM;
  1394. }
  1395. }
  1396. if ( NULL == ghWaveThread )
  1397. {
  1398. DWORD dwThreadID;
  1399. ghWaveThread = CreateThread(
  1400. NULL,
  1401. 0,
  1402. WaveThread,
  1403. NULL,
  1404. 0,
  1405. &dwThreadID
  1406. );
  1407. if ( 0 != lResult )
  1408. {
  1409. WDBGOUT((1, "Create thread failed! GetLastError()=0x%lx", GetLastError() ));
  1410. LeaveCriticalSection( &gCriticalSection );
  1411. return LINEERR_NOMEM;
  1412. }
  1413. }
  1414. //
  1415. // Init global operation
  1416. //
  1417. (*poWaveOperation).InitOperation(
  1418. poWaveDevice,
  1419. dwSoundType,
  1420. (LONG)hArray
  1421. );
  1422. (*poWaveDevice).QueueOperation( poWaveOperation );
  1423. if ( dwFlags & PLAY_SYNC )
  1424. {
  1425. hSyncEvent = CreateEvent(
  1426. NULL,
  1427. TRUE,
  1428. FALSE,
  1429. NULL
  1430. );
  1431. if ( NULL == hSyncEvent )
  1432. {
  1433. WDBGOUT((1, TEXT("CreateEvent failed: GetLastError = 0x%08lx"), GetLastError()));
  1434. delete poWaveOperation;
  1435. LeaveCriticalSection( &gCriticalSection );
  1436. return( LINEERR_NOMEM );
  1437. }
  1438. (*poWaveOperation).SetSyncEvent( hSyncEvent );
  1439. }
  1440. //
  1441. // If all of the buffers are idle, we'll have to prime...
  1442. //
  1443. if ( MAX_NUM_BUFFERS == (*poWaveDevice).GetNumFreeBuffers() )
  1444. {
  1445. WDBGOUT((4, TEXT("Priming")));
  1446. if ( 0 == (*poWaveDevice).PlaySomeData( TRUE ) )
  1447. {
  1448. WaveOperation * poWaveOperation;
  1449. WDBGOUT((4, TEXT("No data played for this wave!")));
  1450. poWaveOperation = (*poWaveDevice).NextOperation();
  1451. while (poWaveOperation)
  1452. {
  1453. if ( (*poWaveDevice).PlaySomeData(TRUE) )
  1454. {
  1455. break;
  1456. }
  1457. poWaveOperation = (*poWaveDevice).NextOperation();
  1458. }
  1459. //
  1460. // If fNeedToPrimeDevice was true, this must be the first (and only,
  1461. // since we're still in the critical section) operation
  1462. // And, since there was no data (or we failed for any reason),
  1463. // we should shut down the wave device here.
  1464. // Now leave the critical section so we can wait for the WAVETHREAD
  1465. // to finish and so that thread can do work to clean up
  1466. LeaveCriticalSection( &gCriticalSection );
  1467. (*poWaveDevice).KillWaveDevice(TRUE);
  1468. EnterCriticalSection( &gCriticalSection );
  1469. //
  1470. // Fake out the event
  1471. //
  1472. if ( hSyncEvent )
  1473. {
  1474. WDBGOUT((5, TEXT("Faking hSyncEvent...")));
  1475. SetEvent( hSyncEvent );
  1476. }
  1477. }
  1478. }
  1479. #if DBG
  1480. else
  1481. {
  1482. WDBGOUT((4, TEXT("Not priming because %ln buffers are out"),
  1483. (*poWaveDevice).GetNumFreeBuffers() ));
  1484. }
  1485. #endif
  1486. LeaveCriticalSection( &gCriticalSection );
  1487. if ( hSyncEvent )
  1488. {
  1489. WDBGOUT((5, TEXT("Waiting for the wave to finish (event=0x%08lx)"),
  1490. hSyncEvent));
  1491. WaitForSingleObject( hSyncEvent, INFINITE );
  1492. //
  1493. // When it gets back, the thing is done playing
  1494. //
  1495. CloseHandle( hSyncEvent );
  1496. }
  1497. WDBGOUT((4, TEXT("Leaving tapiPlaySound - retcode = 0x0")));
  1498. return( 0 );
  1499. }
  1500. #ifdef __cplusplus
  1501. } /* End Assume C declarations for C++ */
  1502. #endif /* __cplusplus */
  1503. //****************************************************************************
  1504. //****************************************************************************
  1505. //****************************************************************************
  1506. unsigned long WINAPI WaveThread( LPVOID junk )
  1507. {
  1508. UINT n;
  1509. WDBGOUT((3, "WaveThread starting..."));
  1510. do
  1511. {
  1512. WDBGOUT((3, "WaveThread waiting..."));
  1513. WaitForSingleObject( ghFreeBufferEvent, INFINITE );
  1514. //
  1515. // First, deal with any finished buffers
  1516. //
  1517. n = 0;
  1518. // while ( gDoneBuffersToBeProcessed[n] != NULL )
  1519. EnterCriticalSection( &gCriticalSection );
  1520. while ( n < MAX_NUM_BUFFERS )
  1521. {
  1522. if ( gDoneBuffersToBeProcessed[n] != NULL )
  1523. {
  1524. MISCINFO *pMiscInfo = gDoneBuffersToBeProcessed[n];
  1525. pMiscInfo->poWaveOperation->ProcessDoneBuffer( pMiscInfo );
  1526. gDoneBuffersToBeProcessed[n] = NULL;
  1527. }
  1528. n++;
  1529. }
  1530. LeaveCriticalSection( &gCriticalSection );
  1531. // poWaveDevice = gpoWaveDeviceList;
  1532. //
  1533. // while ( poWaveDevice )
  1534. // {
  1535. // UINT nBytesQueued = 0;
  1536. //
  1537. // while ( nBytesQueued == 0 )
  1538. // {
  1539. // //
  1540. // // Now play some new data
  1541. // //
  1542. // nBytesQueued = (*poWaveDevice).PlaySomeData( FALSE );
  1543. //
  1544. // //
  1545. // // And is the entire wave done?
  1546. // //
  1547. // if ( 0 == nBytesQueued )
  1548. // {
  1549. // WaveOperation * poNewCurrent;
  1550. //
  1551. // poNewCurrent = (*poWaveDevice).NextOperation();
  1552. //
  1553. // if ( NULL == poNewCurrent )
  1554. // {
  1555. // if ( NULL == gpoWaveDeviceList )
  1556. // {
  1557. // gfShutdown = TRUE;
  1558. // gfInited = 0;
  1559. // }
  1560. // break;
  1561. // }
  1562. // }
  1563. // }
  1564. //
  1565. //
  1566. // poWaveDevice = (*poWaveDevice).GetpNext();
  1567. // }
  1568. } while ( !gfShutdown );
  1569. WDBGOUT((5, TEXT("Oh, I guess we're done now...")));
  1570. CloseHandle( ghFreeBufferEvent );
  1571. ghFreeBufferEvent = 0;
  1572. gfShutdown = FALSE;
  1573. WDBGOUT((3, TEXT("WaveThread ending...")));
  1574. ghWaveThread = NULL;
  1575. return 0;
  1576. }