Module: wine Branch: master Commit: 573fc10daed84840cd79d1ec2c7815b5be73f60a URL: http://source.winehq.org/git/wine.git/?a=commit;h=573fc10daed84840cd79d1ec2c...
Author: Jörg Höhle hoehle@users.sourceforge.net Date: Sat Jul 31 23:00:38 2010 +0200
mcicda: Fix seeking.
---
dlls/mcicda/mcicda.c | 43 +++++++++++++++++++++++++------------------ 1 files changed, 25 insertions(+), 18 deletions(-)
diff --git a/dlls/mcicda/mcicda.c b/dlls/mcicda/mcicda.c index 6c7d8fb..51727ee 100644 --- a/dlls/mcicda/mcicda.c +++ b/dlls/mcicda/mcicda.c @@ -393,7 +393,6 @@ static DWORD MCICDA_CalcTime(WINE_MCICDAUDIO* wmcda, DWORD tf, DWORD dwFrame, LP return dwTime; }
-static DWORD MCICDA_Seek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms); static DWORD MCICDA_Stop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms);
/************************************************************************** @@ -848,24 +847,23 @@ static DWORD MCICDA_SkipDataTracks(WINE_MCICDAUDIO* wmcda,DWORD *frame) WARN("error reading TOC !\n"); return MCICDA_GetError(wmcda); } - /* Locate first track whose starting frame is bigger than frame */ - for(i=toc.FirstTrack;i<=toc.LastTrack+1;i++) - if ( FRAME_OF_TOC(toc, i) > *frame ) break; - if (i <= toc.FirstTrack && i>toc.LastTrack+1) { - i = 0; /* requested address is out of range: go back to start */ - *frame = FRAME_OF_TOC(toc,toc.FirstTrack); - } - else - i--; + if (*frame < FRAME_OF_TOC(toc,toc.FirstTrack) || + *frame >= FRAME_OF_TOC(toc,toc.LastTrack+1)) /* lead-out */ + return MCIERR_OUTOFRANGE; + for(i=toc.LastTrack+1;i>toc.FirstTrack;i--) + if ( FRAME_OF_TOC(toc, i) <= *frame ) break; /* i points to last track whose start address is not greater than frame. * Now skip non-audio tracks */ - for(;i<=toc.LastTrack+1;i++) + for(;i<=toc.LastTrack;i++) if ( ! (toc.TrackData[i-toc.FirstTrack].Control & 4) ) break; /* The frame will be an address in the next audio track or * address of lead-out. */ if ( FRAME_OF_TOC(toc, i) > *frame ) *frame = FRAME_OF_TOC(toc, i); + /* Lead-out is an invalid seek position (on Linux as well). */ + if (*frame == FRAME_OF_TOC(toc,toc.LastTrack+1)) + (*frame)--; return 0; }
@@ -927,6 +925,14 @@ static DWORD MCICDA_Play(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms) (dwFlags & MCI_NOTIFY) ? HWND_32(LOWORD(lpParms->dwCallback)) : NULL); if (oldcb) mciDriverNotify(oldcb, wmcda->wNotifyDeviceID, MCI_NOTIFY_ABORTED);
+ if (start == end || start == FRAME_OF_TOC(toc,toc.LastTrack+1)-1) { + if (dwFlags & MCI_NOTIFY) { + oldcb = InterlockedExchangePointer(&wmcda->hCallback, NULL); + if (oldcb) mciDriverNotify(oldcb, wDevID, MCI_NOTIFY_SUCCESSFUL); + } + return MMSYSERR_NOERROR; + } + if (wmcda->hThread != 0) { SetEvent(wmcda->stopEvent); WaitForSingleObject(wmcda->hThread, INFINITE); @@ -1162,6 +1168,11 @@ static DWORD MCICDA_Seek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms) if (!position) return MCIERR_MISSING_PARAMETER; if (position&(position-1)) return MCIERR_FLAGS_NOT_COMPATIBLE;
+ /* Stop sends MCI_NOTIFY_ABORTED when needed. + * Tests show that native first sends ABORTED and reads the TOC, + * then only checks the position flags, then stops and seeks. */ + MCICDA_Stop(wDevID, MCI_WAIT, 0); + if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_READ_TOC, NULL, 0, &toc, sizeof(toc), &br, NULL)) { WARN("error reading TOC !\n"); @@ -1176,6 +1187,8 @@ static DWORD MCICDA_Seek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms) break; case MCI_SEEK_TO_END: TRACE("Seeking to end\n"); + /* End is prior to lead-out + * yet Win9X seeks to even one frame less than that. */ at = FRAME_OF_TOC(toc, toc.LastTrack + 1) - 1; if ( (ret=MCICDA_SkipDataTracks(wmcda, &at)) ) return ret; @@ -1190,13 +1203,7 @@ static DWORD MCICDA_Seek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms) return MCIERR_FLAGS_NOT_COMPATIBLE; }
- if (wmcda->hThread != 0) { - EnterCriticalSection(&wmcda->cs); - wmcda->start = at - FRAME_OF_TOC(toc, toc.FirstTrack); - /* Flush remaining data, or just let it play into the new data? */ - LeaveCriticalSection(&wmcda->cs); - } - else { + { seek.M = at / CDFRAMES_PERMIN; seek.S = (at / CDFRAMES_PERSEC) % 60; seek.F = at % CDFRAMES_PERSEC;