Source code of Windows XP (NT5)
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.

1326 lines
31 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: cdapimci.c
  3. *
  4. * This module encapsulates the CD-ROM device into a set of callable apis.
  5. * The api's are implemented using the cdaudio mci interface.
  6. *
  7. * Created: 26-04-93
  8. * Author: Stephen Estrop [StephenE]
  9. *
  10. * Copyright (c) 1993 - 1995 Microsoft Corporation. All rights reserved.
  11. \**************************************************************************/
  12. #pragma warning( once : 4201 4214 )
  13. #define NOOLE
  14. #include <windows.h> /* required for all Windows applications */
  15. #include <windowsx.h>
  16. #include <string.h>
  17. #include "playres.h"
  18. #include "cdplayer.h"
  19. #include "cdapi.h"
  20. #include "scan.h"
  21. #include "trklst.h"
  22. #include "..\cdopt\cdopt.h"
  23. #ifdef __cplusplus
  24. extern "C" {
  25. #endif
  26. /* -------------------------------------------------------------------------
  27. **
  28. ** High level routines
  29. **
  30. ** -------------------------------------------------------------------------
  31. */
  32. BOOL g_fCDOpen = TRUE;
  33. /******************************Public*Routine******************************\
  34. * OpenCdRom
  35. *
  36. *
  37. *
  38. * History:
  39. * dd-mm-94 - StephenE - Created
  40. *
  41. \**************************************************************************/
  42. MCIDEVICEID
  43. OpenCdRom(
  44. TCHAR chDrive,
  45. LPDWORD lpdwErrCode
  46. )
  47. {
  48. MCI_OPEN_PARMS mciOpen;
  49. TCHAR szElementName[4];
  50. TCHAR szAliasName[32];
  51. DWORD dwFlags;
  52. DWORD dwAliasCount = GetCurrentTime();
  53. DWORD dwRet;
  54. ZeroMemory( &mciOpen, sizeof(mciOpen) );
  55. mciOpen.lpstrDeviceType = (LPTSTR)MCI_DEVTYPE_CD_AUDIO;
  56. wsprintf( szElementName, TEXT("%c:"), chDrive );
  57. wsprintf( szAliasName, TEXT("SJE%lu:"), dwAliasCount );
  58. mciOpen.lpstrElementName = szElementName;
  59. mciOpen.lpstrAlias = szAliasName;
  60. OSVERSIONINFO os;
  61. os.dwOSVersionInfoSize = sizeof(os);
  62. GetVersionEx(&os);
  63. if (os.dwPlatformId == VER_PLATFORM_WIN32_NT)
  64. {
  65. dwFlags = MCI_OPEN_ELEMENT | MCI_OPEN_SHAREABLE | MCI_OPEN_ALIAS |
  66. MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID | MCI_WAIT;
  67. }
  68. else
  69. {
  70. dwFlags = MCI_OPEN_ELEMENT | MCI_OPEN_ALIAS |
  71. MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID | MCI_WAIT;
  72. }
  73. dwRet = mciSendCommand(0, MCI_OPEN, dwFlags, (DWORD_PTR)(LPVOID)&mciOpen);
  74. if ( dwRet == MMSYSERR_NOERROR ) {
  75. MCI_SET_PARMS mciSet;
  76. ZeroMemory( &mciSet, sizeof(mciSet) );
  77. mciSet.dwTimeFormat = MCI_FORMAT_MSF;
  78. mciSendCommand( mciOpen.wDeviceID, MCI_SET,
  79. MCI_SET_TIME_FORMAT, (DWORD_PTR)(LPVOID)&mciSet );
  80. }
  81. else {
  82. /*
  83. ** Only return the error code if we have been given a valid pointer
  84. */
  85. if (lpdwErrCode != NULL) {
  86. *lpdwErrCode = dwRet;
  87. }
  88. mciOpen.wDeviceID = 0;
  89. }
  90. return mciOpen.wDeviceID;
  91. }
  92. /******************************Public*Routine******************************\
  93. * CloseCdRom
  94. *
  95. *
  96. *
  97. * History:
  98. * dd-mm-94 - StephenE - Created
  99. *
  100. \**************************************************************************/
  101. void
  102. CloseCdRom(
  103. MCIDEVICEID DevHandle
  104. )
  105. {
  106. mciSendCommand( DevHandle, MCI_CLOSE, 0L, 0L );
  107. }
  108. /******************************Public*Routine******************************\
  109. * CheckStatus
  110. *
  111. * Check return code for known bad codes and inform
  112. * user how to correct (if possible) the problem.
  113. *
  114. * History:
  115. * 18-11-93 - StephenE - Created
  116. *
  117. \**************************************************************************/
  118. void
  119. CheckStatus(
  120. LPSTR szCaller,
  121. DWORD status,
  122. int cdrom
  123. )
  124. {
  125. #if DBG
  126. TCHAR s[200];
  127. TCHAR err[100];
  128. #endif
  129. if (status==ERROR_SUCCESS)
  130. return;
  131. /*
  132. switch (status)
  133. {
  134. case MCIERR_HARDWARE:
  135. NoMediaUpdate( cdrom );
  136. break;
  137. }
  138. */
  139. #if DBG
  140. mciGetErrorString( status, err, sizeof(err) / sizeof(TCHAR) );
  141. wsprintf( s, IdStr( STR_ERR_GEN ), g_Devices[cdrom]->drive, err );
  142. OutputDebugString (s);
  143. OutputDebugString (TEXT("\r\n"));
  144. #endif
  145. }
  146. /******************************Public*Routine******************************\
  147. * CheckUnitCdrom
  148. *
  149. * Queries the device state, checking to see if a disc has been ejected or
  150. * inserted.
  151. *
  152. * History:
  153. * 18-11-93 - StephenE - Created
  154. *
  155. \**************************************************************************/
  156. void
  157. CheckUnitCdrom(
  158. int cdrom,
  159. BOOL fForceRescan
  160. )
  161. {
  162. DWORD status;
  163. if ((cdrom < 0) || (cdrom >= MAX_CD_DEVICES))
  164. {
  165. return;
  166. }
  167. if (fForceRescan)
  168. {
  169. // Close Device to force read of correct TOC
  170. if (g_Devices[cdrom]->hCd != 0L)
  171. {
  172. CloseCdRom (g_Devices[cdrom]->hCd);
  173. g_Devices[cdrom]->hCd = 0L;
  174. }
  175. }
  176. if ( g_Devices[cdrom]->hCd == 0L ) {
  177. g_Devices[cdrom]->hCd = OpenCdRom( g_Devices[cdrom]->drive, NULL );
  178. if ( g_Devices[cdrom]->hCd == 0 ) {
  179. return;
  180. }
  181. else {
  182. /*
  183. ** Force a rescan of this disc.
  184. */
  185. g_Devices[cdrom]->State = CD_NO_CD;
  186. }
  187. }
  188. status = TestUnitReadyCdrom( g_Devices[cdrom]->hCd );
  189. if (g_Devices[cdrom]->State & CD_NO_CD)
  190. {
  191. if (status == ERROR_SUCCESS) {
  192. /*
  193. ** A new disc has been inserted, scan it now.
  194. */
  195. RescanDevice( g_hwndApp, cdrom );
  196. }
  197. }
  198. else {
  199. if (status != ERROR_SUCCESS) {
  200. /*
  201. ** Disc has been ejected.
  202. */
  203. NoMediaUpdate( cdrom );
  204. }
  205. }
  206. }
  207. /******************************Public*Routine******************************\
  208. * NoMediaUpdate
  209. *
  210. * Update the user display when it is found that no media is in the device.
  211. *
  212. * History:
  213. * 18-11-93 - StephenE - Created
  214. *
  215. \**************************************************************************/
  216. void
  217. NoMediaUpdate(
  218. int cdrom
  219. )
  220. {
  221. BOOL fChangePlayButtons;
  222. if ( cdrom == g_CurrCdrom )
  223. {
  224. fChangePlayButtons = TRUE;
  225. }
  226. else {
  227. fChangePlayButtons = FALSE;
  228. }
  229. g_Devices[cdrom]->State = (CD_NO_CD | CD_STOPPED);
  230. if (fChangePlayButtons)
  231. {
  232. g_pSink->OnEvent(MMEVENT_ONMEDIAUNLOADED,NULL);
  233. //tell the UI to gray out the button
  234. HWND hwndTrackButton = GetDlgItem(GetParent(g_hwndApp),IDB_TRACK);
  235. if (hwndTrackButton)
  236. {
  237. EnableWindow(hwndTrackButton,FALSE);
  238. }
  239. SetPlayButtonsEnableState();
  240. }
  241. //tell the playlist
  242. // Drive has been ejected
  243. if (g_pSink)
  244. {
  245. LPCDOPT pOpt = (LPCDOPT)g_pSink->GetOptions();
  246. LPCDOPTIONS pCDOpts = NULL;
  247. LPCDUNIT pUnit = NULL;
  248. if (pOpt)
  249. {
  250. pCDOpts = pOpt->GetCDOpts();
  251. }
  252. if (pCDOpts)
  253. {
  254. pUnit = pCDOpts->pCDUnitList;
  255. }
  256. //scan the list to find the one we want
  257. for (int index = 0; index < cdrom; index++)
  258. {
  259. if (pUnit)
  260. {
  261. pUnit = pUnit->pNext;
  262. }
  263. }
  264. if (pUnit)
  265. {
  266. pUnit->dwTitleID = CDTITLE_NODISC;
  267. pUnit->dwNumTracks = 0;
  268. pUnit->szNetQuery[0] = '\0';
  269. pOpt->DiscChanged(pUnit);
  270. }
  271. } //end if sink
  272. TimeAdjustInitialize( cdrom );
  273. }
  274. /******************************Public*Routine******************************\
  275. * EjectTheCdromDisc
  276. *
  277. * Eject the disc from the specified cdrom device.
  278. *
  279. * History:
  280. * 18-11-93 - StephenE - Created
  281. *
  282. \**************************************************************************/
  283. BOOL
  284. EjectTheCdromDisc(
  285. int cdrom
  286. )
  287. {
  288. DWORD status;
  289. /*
  290. ** Stop the drive first
  291. */
  292. status = StopCdrom( g_Devices[cdrom]->hCd );
  293. /*
  294. ** Eject the disc
  295. */
  296. status = EjectCdrom( g_Devices[cdrom]->hCd );
  297. CheckStatus( "EjectCdrom", status, cdrom );
  298. return status == ERROR_SUCCESS;
  299. }
  300. /******************************Public*Routine******************************\
  301. * PlayCurrTrack
  302. *
  303. * Set cdrom device playing from start MSF to end MSF of current
  304. * track.
  305. *
  306. * History:
  307. * 18-11-93 - StephenE - Created
  308. *
  309. \**************************************************************************/
  310. BOOL
  311. PlayCurrTrack(
  312. int cdrom
  313. )
  314. {
  315. DWORD status;
  316. MCI_PLAY_PARMS pam;
  317. int min,sec,endindex;
  318. PTRACK_PLAY tr;
  319. tr = CURRTRACK( cdrom );
  320. if (tr==NULL) {
  321. return( FALSE );
  322. }
  323. sec = TRACK_S(cdrom,tr->TocIndex) + CDTIME(cdrom).TrackCurSec;
  324. min = TRACK_M(cdrom,tr->TocIndex) + CDTIME(cdrom).TrackCurMin;
  325. min+= (sec / 60);
  326. sec = (sec % 60);
  327. pam.dwFrom = MCI_MAKE_MSF( min, sec, TRACK_F(cdrom,tr->TocIndex) );
  328. endindex = FindContiguousEnd( cdrom, tr );
  329. pam.dwTo = MCI_MAKE_MSF( TRACK_M(cdrom,endindex),
  330. TRACK_S(cdrom,endindex),
  331. TRACK_F(cdrom,endindex) );
  332. #if DBG
  333. {
  334. long lAddress, lEndPos, lStartPos;
  335. dprintf( TEXT("Playing from : %2.2d:%2.2d:%2.2d"),
  336. MCI_MSF_MINUTE(pam.dwFrom),
  337. MCI_MSF_SECOND(pam.dwFrom),
  338. MCI_MSF_FRAME( pam.dwFrom) );
  339. dprintf( TEXT("Playing to : %2.2d:%2.2d:%2.2d"),
  340. MCI_MSF_MINUTE(pam.dwTo),
  341. MCI_MSF_SECOND(pam.dwTo),
  342. MCI_MSF_FRAME( pam.dwTo) );
  343. lAddress = pam.dwFrom;
  344. lStartPos = (MCI_MSF_MINUTE(lAddress) * FRAMES_PER_MINUTE) +
  345. (MCI_MSF_SECOND(lAddress) * FRAMES_PER_SECOND) +
  346. (MCI_MSF_FRAME(lAddress));
  347. lAddress = pam.dwTo;
  348. lEndPos = (MCI_MSF_MINUTE(lAddress) * FRAMES_PER_MINUTE) +
  349. (MCI_MSF_SECOND(lAddress) * FRAMES_PER_SECOND) +
  350. (MCI_MSF_FRAME(lAddress));
  351. lAddress = lEndPos - lStartPos;
  352. lStartPos =
  353. MCI_MAKE_MSF((lAddress / FRAMES_PER_MINUTE),
  354. (lAddress % FRAMES_PER_MINUTE) / FRAMES_PER_SECOND,
  355. (lAddress % FRAMES_PER_MINUTE) % FRAMES_PER_SECOND);
  356. lAddress = lStartPos;
  357. dprintf( TEXT("Play length : %2.2d:%2.2d:%2.2d"),
  358. MCI_MSF_MINUTE(lAddress),
  359. MCI_MSF_SECOND(lAddress),
  360. MCI_MSF_FRAME( lAddress) );
  361. }
  362. #endif
  363. status = PlayCdrom( g_Devices[cdrom]->hCd, &pam );
  364. CheckStatus( "PlayCurrTrack", status, cdrom );
  365. return status == ERROR_SUCCESS;
  366. }
  367. /******************************Public*Routine******************************\
  368. * StopTheCdromDrive
  369. *
  370. * Tell the cdrom device to stop playing
  371. *
  372. * History:
  373. * 18-11-93 - StephenE - Created
  374. *
  375. \**************************************************************************/
  376. BOOL
  377. StopTheCdromDrive(
  378. int cdrom
  379. )
  380. {
  381. DWORD status;
  382. status = StopCdrom( g_Devices[cdrom]->hCd );
  383. CheckStatus( "StopCdrom", status, cdrom );
  384. return status == ERROR_SUCCESS;
  385. }
  386. /******************************Public*Routine******************************\
  387. * PauseTheCdromDrive
  388. *
  389. * Tell the cdrom device to pause playing
  390. *
  391. * History:
  392. * 18-11-93 - StephenE - Created
  393. *
  394. \**************************************************************************/
  395. BOOL
  396. PauseTheCdromDrive(
  397. int cdrom
  398. )
  399. {
  400. DWORD status;
  401. status = PauseCdrom( g_Devices[cdrom]->hCd );
  402. CheckStatus( "PauseCdrom", status, cdrom );
  403. return status == ERROR_SUCCESS;
  404. }
  405. /******************************Public*Routine******************************\
  406. * ResumeTheCdromDrive
  407. *
  408. * Tell the cdrom device to resume playing
  409. *
  410. * History:
  411. * 18-11-93 - StephenE - Created
  412. *
  413. \**************************************************************************/
  414. BOOL
  415. ResumeTheCdromDrive(
  416. int cdrom
  417. )
  418. {
  419. DWORD status;
  420. status = ResumeCdrom( g_Devices[cdrom]->hCd, cdrom );
  421. CheckStatus( "ResumeCdrom", status, cdrom );
  422. if ( status == ERROR_NOT_READY ) {
  423. NoMediaUpdate( cdrom );
  424. }
  425. return status == ERROR_SUCCESS;
  426. }
  427. /******************************Public*Routine******************************\
  428. * SeekToCurrSecond
  429. *
  430. * Seek to the position on the disc represented by the
  431. * current time (position) information in gDevices, and
  432. * continue playing to the end of the current track.
  433. *
  434. * History:
  435. * 18-11-93 - StephenE - Created
  436. *
  437. \**************************************************************************/
  438. BOOL
  439. SeekToCurrSecond(
  440. int cdrom
  441. )
  442. {
  443. DWORD status;
  444. int endindex;
  445. PTRACK_PLAY tr;
  446. UCHAR StartingF, StartingS, StartingM;
  447. /*
  448. ** Build starting and ending positions for play
  449. */
  450. tr = CDTIME(cdrom).CurrTrack;
  451. if (tr == NULL) {
  452. return FALSE;
  453. }
  454. StartingM = (TRACK_M(cdrom,tr->TocIndex) + CDTIME(cdrom).TrackCurMin);
  455. StartingS = (TRACK_S(cdrom,tr->TocIndex) + CDTIME(cdrom).TrackCurSec);
  456. StartingF = (TRACK_F(cdrom,tr->TocIndex));
  457. if (StartingS > 59) {
  458. StartingM++;
  459. StartingS -= (UCHAR)60;
  460. }
  461. if (g_Devices[ cdrom ]->State & CD_PLAYING) {
  462. MCI_PLAY_PARMS mciPlay;
  463. endindex = FindContiguousEnd( cdrom, tr );
  464. mciPlay.dwFrom = MCI_MAKE_MSF( StartingM, StartingS, StartingF );
  465. mciPlay.dwTo = MCI_MAKE_MSF( TRACK_M(cdrom,endindex),
  466. TRACK_S(cdrom,endindex),
  467. TRACK_F(cdrom,endindex) );
  468. status = PlayCdrom( g_Devices[ cdrom ]->hCd, &mciPlay );
  469. }
  470. else {
  471. MCI_SEEK_PARMS mciSeek;
  472. mciSeek.dwTo = MCI_MAKE_MSF( StartingM, StartingS, StartingF );
  473. status = SeekCdrom( g_Devices[ cdrom ]->hCd, &mciSeek );
  474. }
  475. CheckStatus( "SeekToCurrSec", status, cdrom );
  476. return status == ERROR_SUCCESS;
  477. }
  478. /******************************Public*Routine******************************\
  479. * GetCurrPos
  480. *
  481. * Query cdrom device for its current position and status
  482. * and return information in callers buffer.
  483. *
  484. * History:
  485. * 18-11-93 - StephenE - Created
  486. *
  487. \**************************************************************************/
  488. BOOL
  489. GetCurrPos(
  490. int cdrom,
  491. PCURRPOS CpPtr
  492. )
  493. {
  494. DWORD status;
  495. DWORD dwStatus;
  496. DWORD dwTrack;
  497. DWORD dwAbsPos;
  498. BOOL fNT;
  499. OSVERSIONINFO os;
  500. os.dwOSVersionInfoSize = sizeof(os);
  501. GetVersionEx(&os);
  502. if (os.dwPlatformId == VER_PLATFORM_WIN32_NT)
  503. {
  504. fNT = TRUE;
  505. }
  506. else
  507. {
  508. fNT = FALSE;
  509. }
  510. /*
  511. ** Tell lower layer what we want it to do...in this case,
  512. ** we need to specify which SubQData format we want returned.
  513. ** This is exported from scsicdrom.sys to the user layer
  514. ** so that it could be implemented in one call, instead of
  515. ** four separate calls (there are four SubQData formats)
  516. */
  517. /*
  518. ** Set up for current position SubQData format.
  519. */
  520. if (CDTIME(cdrom).CurrTrack != NULL) {
  521. if (fNT)
  522. {
  523. status = StatusTrackPosCdrom ( g_Devices[ cdrom ]->hCd, &dwStatus, &dwTrack, &dwAbsPos);
  524. }
  525. else
  526. {
  527. status = GetCdromCurrentPosition( g_Devices[ cdrom ]->hCd, &dwAbsPos );
  528. }
  529. }
  530. else {
  531. status = MCIERR_INTERNAL;
  532. }
  533. if (status == ERROR_SUCCESS) {
  534. int iTrack;
  535. LONG lAbsPosF;
  536. LONG lStartPos;
  537. LONG lTrackPos;
  538. if (!fNT)
  539. {
  540. iTrack = (int)GetCdromCurrentTrack( g_Devices[ cdrom ]->hCd );
  541. }
  542. else
  543. {
  544. iTrack = (int)dwTrack;
  545. }
  546. if (!fNT)
  547. {
  548. CpPtr->AudioStatus = GetCdromMode( g_Devices[ cdrom ]->hCd );
  549. }
  550. else
  551. {
  552. CpPtr->AudioStatus = dwStatus;
  553. }
  554. CpPtr->Track = iTrack;
  555. CpPtr->Index = 1;
  556. iTrack--;
  557. lStartPos = (TRACK_M(cdrom, iTrack ) * FRAMES_PER_MINUTE) +
  558. (TRACK_S(cdrom, iTrack ) * FRAMES_PER_SECOND) +
  559. (TRACK_F(cdrom, iTrack ));
  560. lAbsPosF = (MCI_MSF_MINUTE(dwAbsPos) * FRAMES_PER_MINUTE) +
  561. (MCI_MSF_SECOND(dwAbsPos) * FRAMES_PER_SECOND) +
  562. (MCI_MSF_FRAME(dwAbsPos));
  563. lTrackPos = lAbsPosF - lStartPos;
  564. /*
  565. ** Are we in the track lead in zone ?
  566. */
  567. if ( lTrackPos < 0 ) {
  568. /*
  569. ** Have we just entered the lead in zone
  570. */
  571. if (!g_Devices[cdrom]->fProcessingLeadIn) {
  572. g_Devices[cdrom]->fProcessingLeadIn = TRUE;
  573. /*
  574. ** Is the track that we are currently in the next track
  575. ** that we actually want to play. If it is then everything is
  576. ** OK. If it isn't then we need to hack the current position
  577. ** information so that it looks like we sre still playing the
  578. ** previous track.
  579. */
  580. if ( CURRTRACK(cdrom)->nextplay
  581. && CURRTRACK(cdrom)->nextplay->TocIndex == iTrack) {
  582. g_Devices[cdrom]->fShowLeadIn = TRUE;
  583. }
  584. else {
  585. g_Devices[cdrom]->fShowLeadIn = FALSE;
  586. }
  587. }
  588. g_Devices[cdrom]->fShowLeadIn = FALSE;
  589. if (g_Devices[cdrom]->fShowLeadIn) {
  590. CpPtr->Index = 0;
  591. lTrackPos = -lTrackPos;
  592. }
  593. else {
  594. CpPtr->Track = iTrack;
  595. iTrack--;
  596. lTrackPos = lAbsPosF
  597. - g_Devices[cdrom]->toc.TrackData[iTrack].AddressF;
  598. }
  599. }
  600. else {
  601. g_Devices[cdrom]->fShowLeadIn = FALSE;
  602. g_Devices[cdrom]->fProcessingLeadIn = FALSE;
  603. }
  604. CpPtr->m = (int)(lTrackPos / FRAMES_PER_MINUTE);
  605. CpPtr->s = (int)(lTrackPos % FRAMES_PER_MINUTE) / FRAMES_PER_SECOND;
  606. CpPtr->f = (int)(lTrackPos % FRAMES_PER_MINUTE) % FRAMES_PER_SECOND;
  607. CpPtr->ab_m = (int)MCI_MSF_MINUTE(dwAbsPos);
  608. CpPtr->ab_s = (int)MCI_MSF_SECOND(dwAbsPos);
  609. CpPtr->ab_f = (int)MCI_MSF_FRAME(dwAbsPos);
  610. /*
  611. ** Round up to the nearest second.
  612. */
  613. if (CpPtr->f > (FRAMES_PER_SECOND / 2) ) {
  614. if ( ++CpPtr->s > 59 ) {
  615. CpPtr->s = 0;
  616. CpPtr->m++;
  617. }
  618. }
  619. else {
  620. CpPtr->f = 0;
  621. }
  622. if (CpPtr->ab_f > (FRAMES_PER_SECOND / 2) ) {
  623. if ( ++CpPtr->ab_s > 59 ) {
  624. CpPtr->ab_s = 0;
  625. CpPtr->ab_m++;
  626. }
  627. }
  628. else {
  629. CpPtr->ab_f = 0;
  630. }
  631. }
  632. else {
  633. ZeroMemory( CpPtr, sizeof(*CpPtr) );
  634. }
  635. CheckStatus( "GetCurrPos", status, cdrom );
  636. return status==ERROR_SUCCESS;
  637. }
  638. /******************************Public*Routine******************************\
  639. * SeekToTrackAndHold
  640. *
  641. * Seek to specified track and enter hold state.
  642. *
  643. * History:
  644. * 18-11-93 - StephenE - Created
  645. *
  646. \**************************************************************************/
  647. BOOL
  648. SeekToTrackAndHold(
  649. int cdrom,
  650. int tindex
  651. )
  652. {
  653. DWORD status;
  654. MCI_SEEK_PARMS sam;
  655. sam.dwTo = MCI_MAKE_MSF( TRACK_M(cdrom,tindex),
  656. TRACK_S(cdrom,tindex),
  657. TRACK_F(cdrom,tindex) );
  658. status = SeekCdrom( g_Devices[ cdrom ]->hCd, &sam );
  659. CheckStatus( "SeekToTrackAndHold", status, cdrom );
  660. return status == ERROR_SUCCESS;
  661. }
  662. /* -------------------------------------------------------------------------
  663. **
  664. ** Low level routines
  665. **
  666. ** -------------------------------------------------------------------------
  667. */
  668. /******************************Public*Routine******************************\
  669. * GetCdromTOC
  670. *
  671. * This routine will get the table of contents from
  672. * a CDRom device.
  673. *
  674. *
  675. * History:
  676. * 18-11-93 - StephenE - Created
  677. *
  678. \**************************************************************************/
  679. DWORD
  680. GetCdromTOC(
  681. MCIDEVICEID DevHandle,
  682. PCDROM_TOC TocPtr
  683. )
  684. {
  685. MCI_STATUS_PARMS mciStatus;
  686. long lAddress, lStartPos, lDiskLen;
  687. int i;
  688. DWORD dwRet;
  689. #if DBG
  690. dprintf( TEXT("Reading TOC for drive %d"), DevHandle );
  691. #endif
  692. ZeroMemory( &mciStatus, sizeof(mciStatus) );
  693. mciStatus.dwItem = MCI_STATUS_NUMBER_OF_TRACKS;
  694. //
  695. // NOTE: none of the mciSendCommand calls below bother to check the
  696. // return code. This is asking for trouble... but if the
  697. // commands fail we cannot do much about it.
  698. //
  699. dwRet = mciSendCommand( DevHandle, MCI_STATUS,
  700. MCI_STATUS_ITEM, (DWORD_PTR)(LPVOID)&mciStatus);
  701. TocPtr->FirstTrack = 1;
  702. TocPtr->LastTrack = (UCHAR)mciStatus.dwReturn;
  703. mciStatus.dwItem = MCI_STATUS_POSITION;
  704. for ( i = 0; i < TocPtr->LastTrack; i++ ) {
  705. mciStatus.dwTrack = i + 1;
  706. dwRet = mciSendCommand( DevHandle, MCI_STATUS,
  707. MCI_STATUS_ITEM | MCI_TRACK,
  708. (DWORD_PTR)(LPVOID)&mciStatus);
  709. TocPtr->TrackData[i].TrackNumber = (UCHAR)(i + 1);
  710. lAddress = TocPtr->TrackData[i].Address = (long)mciStatus.dwReturn;
  711. lStartPos = (MCI_MSF_MINUTE(lAddress) * FRAMES_PER_MINUTE) +
  712. (MCI_MSF_SECOND(lAddress) * FRAMES_PER_SECOND) +
  713. (MCI_MSF_FRAME( lAddress));
  714. TocPtr->TrackData[i].AddressF = lStartPos;
  715. }
  716. mciStatus.dwItem = MCI_STATUS_LENGTH;
  717. dwRet = mciSendCommand( DevHandle, MCI_STATUS,
  718. MCI_STATUS_ITEM, (DWORD_PTR)(LPVOID)&mciStatus);
  719. /*
  720. ** Convert the absolute start address of the first track
  721. ** into Frames
  722. */
  723. lAddress = TocPtr->TrackData[0].Address;
  724. lStartPos = TocPtr->TrackData[0].AddressF;
  725. /*
  726. ** Convert the total disk length into Frames
  727. */
  728. lAddress = (long)mciStatus.dwReturn;
  729. lDiskLen = (MCI_MSF_MINUTE(lAddress) * FRAMES_PER_MINUTE) +
  730. (MCI_MSF_SECOND(lAddress) * FRAMES_PER_SECOND) +
  731. (MCI_MSF_FRAME(lAddress));
  732. /*
  733. ** Now, determine the absolute start position of the sentinel
  734. ** track. That is, the special track that marks the end of the
  735. ** disk.
  736. */
  737. lAddress = lStartPos + lDiskLen;
  738. TocPtr->TrackData[i].TrackNumber = 0;
  739. TocPtr->TrackData[i].Address =
  740. MCI_MAKE_MSF((lAddress / FRAMES_PER_MINUTE),
  741. (lAddress % FRAMES_PER_MINUTE) / FRAMES_PER_SECOND,
  742. (lAddress % FRAMES_PER_MINUTE) % FRAMES_PER_SECOND);
  743. return (TocPtr->LastTrack != 0) ? ERROR_SUCCESS : MCIERR_INTERNAL;
  744. }
  745. /******************************Public*Routine******************************\
  746. * StopCdrom
  747. *
  748. * This routine will stop a CDRom device that is playing.
  749. *
  750. *
  751. * History:
  752. * 18-11-93 - StephenE - Created
  753. *
  754. \**************************************************************************/
  755. DWORD
  756. StopCdrom(
  757. MCIDEVICEID DevHandle
  758. )
  759. {
  760. MCI_GENERIC_PARMS mciGen;
  761. ZeroMemory( &mciGen, sizeof(mciGen) );
  762. return mciSendCommand( DevHandle, MCI_STOP, 0L, (DWORD_PTR)(LPVOID)&mciGen );
  763. }
  764. /******************************Public*Routine******************************\
  765. * PauseCdrom
  766. *
  767. * This routine will pause a CDRom device.
  768. *
  769. * History:
  770. * 18-11-93 - StephenE - Created
  771. *
  772. \**************************************************************************/
  773. DWORD
  774. PauseCdrom(
  775. MCIDEVICEID DevHandle
  776. )
  777. {
  778. MCI_GENERIC_PARMS mciGen;
  779. ZeroMemory( &mciGen, sizeof(mciGen) );
  780. return mciSendCommand( DevHandle, MCI_PAUSE, 0L, (DWORD_PTR)(LPVOID)&mciGen );
  781. }
  782. /******************************Public*Routine******************************\
  783. * ResumeCdrom
  784. *
  785. * This routine will resume a paused CDRom device.
  786. *
  787. * History:
  788. * 18-11-93 - StephenE - Created
  789. *
  790. \**************************************************************************/
  791. DWORD
  792. ResumeCdrom(
  793. MCIDEVICEID DevHandle,
  794. int cdrom
  795. )
  796. {
  797. MCI_GENERIC_PARMS mciGen;
  798. DWORD dwRet;
  799. static int fCanResume = -1;
  800. ZeroMemory( &mciGen, sizeof(mciGen) );
  801. switch (fCanResume) {
  802. case -1:
  803. dwRet = mciSendCommand( DevHandle, MCI_RESUME, MCI_TO, (DWORD_PTR)(LPVOID)&mciGen );
  804. fCanResume = (dwRet == MMSYSERR_NOERROR ? 1 : 0);
  805. if (0 == fCanResume) {
  806. dwRet = (PlayCurrTrack( cdrom ) ? MMSYSERR_NOERROR : MCIERR_HARDWARE);
  807. }
  808. break;
  809. case 0:
  810. dwRet = (PlayCurrTrack( cdrom ) ? MMSYSERR_NOERROR : MCIERR_HARDWARE);
  811. break;
  812. case 1:
  813. dwRet = mciSendCommand( DevHandle, MCI_RESUME, MCI_TO, (DWORD_PTR)(LPVOID)&mciGen );
  814. break;
  815. }
  816. return dwRet;
  817. }
  818. /******************************Public*Routine******************************\
  819. * PlayCdrom
  820. *
  821. * This routine plays a CDRom device starting and ending at the MSF
  822. * positions specified in the structure passed in.
  823. *
  824. * History:
  825. * 18-11-93 - StephenE - Created
  826. *
  827. \**************************************************************************/
  828. DWORD
  829. PlayCdrom(
  830. MCIDEVICEID DevHandle,
  831. MCI_PLAY_PARMS *mciPlay
  832. )
  833. {
  834. return mciSendCommand( DevHandle, MCI_PLAY,
  835. MCI_FROM | MCI_TO, (DWORD_PTR)(LPVOID)mciPlay );
  836. }
  837. /******************************Public*Routine******************************\
  838. * IsCdromTrackAudio
  839. *
  840. *
  841. *
  842. * History:
  843. * dd-mm-94 - StephenE - Created
  844. *
  845. \**************************************************************************/
  846. BOOL
  847. IsCdromTrackAudio(
  848. CDHANDLE DevHandle,
  849. int iTrackNumber
  850. )
  851. {
  852. MCI_STATUS_PARMS mciStatus;
  853. ZeroMemory( &mciStatus, sizeof(mciStatus) );
  854. mciStatus.dwItem = MCI_CDA_STATUS_TYPE_TRACK;
  855. mciStatus.dwTrack = iTrackNumber + 1;
  856. mciSendCommand( DevHandle, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK,
  857. (DWORD_PTR)(LPVOID)&mciStatus);
  858. return mciStatus.dwReturn == (DWORD)MCI_CDA_TRACK_AUDIO;
  859. }
  860. /******************************Public*Routine******************************\
  861. * GetCdromCurrentPosition
  862. *
  863. * Gets the current ABSOLUTE position of the specified cdrom device.
  864. *
  865. * History:
  866. * 18-11-93 - StephenE - Created
  867. *
  868. \**************************************************************************/
  869. DWORD
  870. GetCdromCurrentPosition(
  871. CDHANDLE DevHandle,
  872. DWORD *lpdwPosition
  873. )
  874. {
  875. MCI_STATUS_PARMS mciStatus;
  876. DWORD dwErr;
  877. ZeroMemory( &mciStatus, sizeof(mciStatus) );
  878. mciStatus.dwItem = MCI_STATUS_POSITION;
  879. dwErr = mciSendCommand( DevHandle, MCI_STATUS,
  880. MCI_STATUS_ITEM, (DWORD_PTR)(LPVOID)&mciStatus );
  881. *lpdwPosition = (long)mciStatus.dwReturn;
  882. return dwErr;
  883. }
  884. /******************************Public*Routine******************************\
  885. * GetCdromMode
  886. *
  887. * Gets the current mode of the cdrom.
  888. *
  889. * History:
  890. * 18-11-93 - StephenE - Created
  891. *
  892. \**************************************************************************/
  893. DWORD
  894. GetCdromMode(
  895. MCIDEVICEID DevHandle
  896. )
  897. {
  898. MCI_STATUS_PARMS mciStatus;
  899. ZeroMemory( &mciStatus, sizeof(mciStatus) );
  900. mciStatus.dwItem = MCI_STATUS_MODE;
  901. mciSendCommand( DevHandle, MCI_STATUS,
  902. MCI_STATUS_ITEM, (DWORD_PTR)(LPVOID)&mciStatus );
  903. return (DWORD)mciStatus.dwReturn;
  904. }
  905. /******************************Public*Routine******************************\
  906. * GetCdromCurrentTrack
  907. *
  908. * Gets the current track of the cdrom.
  909. *
  910. * History:
  911. * 18-11-93 - StephenE - Created
  912. *
  913. \**************************************************************************/
  914. DWORD
  915. GetCdromCurrentTrack(
  916. MCIDEVICEID DevHandle
  917. )
  918. {
  919. MCI_STATUS_PARMS mciStatus;
  920. ZeroMemory( &mciStatus, sizeof(mciStatus) );
  921. mciStatus.dwItem = MCI_STATUS_CURRENT_TRACK;
  922. mciSendCommand( DevHandle, MCI_STATUS,
  923. MCI_STATUS_ITEM, (DWORD_PTR)(LPVOID)&mciStatus );
  924. return (DWORD)mciStatus.dwReturn;
  925. }
  926. /******************************Public*Routine******************************\
  927. * SeekCdrom
  928. *
  929. * This routine seek to an MSF address on the audio CD and enters
  930. * a hold (paused) state.
  931. *
  932. *
  933. * History:
  934. * 18-11-93 - StephenE - Created
  935. *
  936. \**************************************************************************/
  937. DWORD
  938. SeekCdrom(
  939. MCIDEVICEID DevHandle,
  940. MCI_SEEK_PARMS *mciSeek
  941. )
  942. {
  943. return mciSendCommand( DevHandle, MCI_SEEK,
  944. MCI_TO, (DWORD_PTR)(LPVOID)mciSeek );
  945. }
  946. /******************************Public*Routine******************************\
  947. * EjectCdrom
  948. *
  949. * This routine will eject a disc from a CDRom device or close the tray if
  950. * it is open.
  951. *
  952. * History:
  953. * 18-11-93 - StephenE - Created
  954. *
  955. \**************************************************************************/
  956. DWORD
  957. EjectCdrom(
  958. MCIDEVICEID DevHandle
  959. )
  960. {
  961. MCI_SET_PARMS mciSet;
  962. DWORD mmr = ERROR_SUCCESS;
  963. ZeroMemory( &mciSet, sizeof(mciSet) );
  964. if ((GetCdromMode(DevHandle) == (DWORD)MCI_MODE_OPEN) && g_fCDOpen)
  965. {
  966. mmr = mciSendCommand( DevHandle, MCI_SET,
  967. MCI_SET_DOOR_CLOSED, (DWORD_PTR)(LPVOID)&mciSet );
  968. if (mmr == ERROR_SUCCESS)
  969. {
  970. g_fCDOpen = FALSE;
  971. }
  972. }
  973. else
  974. {
  975. mmr = mciSendCommand( DevHandle, MCI_SET,
  976. MCI_SET_DOOR_OPEN, (DWORD_PTR)(LPVOID)&mciSet );
  977. if (mmr == ERROR_SUCCESS)
  978. {
  979. g_fCDOpen = TRUE;
  980. }
  981. }
  982. return (mmr);
  983. }
  984. /******************************Public*Routine******************************\
  985. * TestUnitReadyCdrom
  986. *
  987. * This routine will retrieve the status of the CDRom device.
  988. *
  989. * History:
  990. * 18-11-93 - StephenE - Created
  991. *
  992. \**************************************************************************/
  993. DWORD
  994. TestUnitReadyCdrom(
  995. MCIDEVICEID DevHandle
  996. )
  997. {
  998. MCI_STATUS_PARMS mciStatus;
  999. ZeroMemory( &mciStatus, sizeof(mciStatus) );
  1000. mciStatus.dwItem = MCI_STATUS_MEDIA_PRESENT;
  1001. if ( mciSendCommand( DevHandle, MCI_STATUS, MCI_STATUS_ITEM,
  1002. (DWORD_PTR)(LPVOID)&mciStatus ) == MMSYSERR_NOERROR ) {
  1003. return mciStatus.dwReturn ? ERROR_SUCCESS : ERROR_NOT_READY;
  1004. }
  1005. return ERROR_NOT_READY;
  1006. }
  1007. /******************************Public*Routine******************************\
  1008. * StatusTrackPosCdrom
  1009. *
  1010. * This routine will retrieve the
  1011. * status, current track, and current position of the CDRom device.
  1012. *
  1013. * History:
  1014. * 18-11-93 - StephenE - Created
  1015. *
  1016. \**************************************************************************/
  1017. DWORD
  1018. StatusTrackPosCdrom(
  1019. MCIDEVICEID DevHandle,
  1020. DWORD * pStatus,
  1021. DWORD * pTrack,
  1022. DWORD * pPos
  1023. )
  1024. {
  1025. DWORD dwErr;
  1026. MCI_STATUS_PARMS mciStatus;
  1027. PSTATUSTRACKPOS pSTP = NULL;
  1028. STATUSTRACKPOS stp;
  1029. ZeroMemory( &mciStatus, sizeof(mciStatus) );
  1030. // Note: This is a non-standard MCI call (I.E. HACK!)
  1031. // the only reason for this behavior is it reduces
  1032. // the number of IOCTL's per 1/2 second on the HeartBeat
  1033. // thread for updating the timer display from ~15 to only
  1034. // ~1 on average. Resulting in a major reduction in
  1035. // system traffic on the SCSI or IDE bus.
  1036. // Note: we are passing down a structre to MCICDA containing
  1037. // the position, track, and status values which it will
  1038. // fill in for us and return.
  1039. mciStatus.dwItem = MCI_STATUS_TRACK_POS;
  1040. mciStatus.dwReturn = (DWORD_PTR)&stp;
  1041. dwErr = mciSendCommand( DevHandle, MCI_STATUS, MCI_STATUS_ITEM,
  1042. (DWORD_PTR)(LPVOID)&mciStatus );
  1043. if (dwErr == MMSYSERR_NOERROR)
  1044. {
  1045. pSTP = (PSTATUSTRACKPOS)mciStatus.dwReturn;
  1046. if (pSTP)
  1047. {
  1048. if (pStatus)
  1049. *pStatus = pSTP->dwStatus;
  1050. if (pTrack)
  1051. *pTrack = pSTP->dwTrack;
  1052. if (pPos)
  1053. *pPos = pSTP->dwDiscTime;
  1054. pSTP = NULL;
  1055. }
  1056. }
  1057. return dwErr;
  1058. } // End StatusTrackPosCdrom
  1059. #ifdef __cplusplus
  1060. };
  1061. #endif