UINT wDevID;
int nUseCount; /* Incremented for each shared open */
BOOL fShareable; /* TRUE if first open was shareable */
- WORD wNotifyDeviceID; /* MCI device ID with a pending notification */
+ MCIDEVICEID wNotifyDeviceID; /* MCI device ID with a pending notification */
HANDLE hCallback; /* Callback handle for pending notification */
DWORD dwTimeFormat;
HANDLE handle;
IDirectSoundBuffer_Stop(wmcda->dsBuf);
SetEvent(wmcda->stopEvent);
- EnterCriticalSection(&wmcda->cs);
- if (wmcda->hCallback) {
- mciDriverNotify(wmcda->hCallback, wmcda->wNotifyDeviceID,
- FAILED(hr) ? MCI_NOTIFY_FAILURE :
- ((endPos!=lastPos) ? MCI_NOTIFY_ABORTED :
- MCI_NOTIFY_SUCCESSFUL));
- wmcda->hCallback = NULL;
- }
- LeaveCriticalSection(&wmcda->cs);
+ /* A design bug in native: the independent CD player called by the
+ * MCI has no means to signal end of playing, therefore the MCI
+ * notification is left hanging. MCI_NOTIFY_SUPERSEDED will be
+ * signaled by the next command that has MCI_NOTIFY set (or
+ * MCI_NOTIFY_ABORTED for MCI_PLAY). */
ExitThread(0);
return 0;
return wmcda;
}
+/**************************************************************************
+ * MCICDA_mciNotify [internal]
+ *
+ * Notifications in MCI work like a 1-element queue.
+ * Each new notification request supersedes the previous one.
+ */
+static void MCICDA_Notify(DWORD_PTR hWndCallBack, WINE_MCICDAUDIO* wmcda, UINT wStatus)
+{
+ MCIDEVICEID wDevID = wmcda->wNotifyDeviceID;
+ HANDLE old = InterlockedExchangePointer(&wmcda->hCallback, NULL);
+ if (old) mciDriverNotify(old, wDevID, MCI_NOTIFY_SUPERSEDED);
+ mciDriverNotify(HWND_32(LOWORD(hWndCallBack)), wDevID, wStatus);
+}
+
/**************************************************************************
* MCICDA_GetStatus [internal]
*/
goto the_error;
if (dwFlags & MCI_NOTIFY) {
- TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpOpenParms->dwCallback);
mciDriverNotify(HWND_32(LOWORD(lpOpenParms->dwCallback)),
- wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
+ dwDeviceID, MCI_NOTIFY_SUCCESSFUL);
}
return 0;
if (--wmcda->nUseCount == 0) {
CloseHandle(wmcda->handle);
}
+ if ((dwParam & MCI_NOTIFY) && lpParms)
+ MCICDA_Notify(lpParms->dwCallback, wmcda, MCI_NOTIFY_SUCCESSFUL);
return 0;
}
static DWORD MCICDA_GetDevCaps(UINT wDevID, DWORD dwFlags,
LPMCI_GETDEVCAPS_PARMS lpParms)
{
+ WINE_MCICDAUDIO* wmcda = (WINE_MCICDAUDIO*)mciGetDriverData(wDevID);
DWORD ret = 0;
TRACE("(%04X, %08X, %p);\n", wDevID, dwFlags, lpParms);
if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
+ if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
if (dwFlags & MCI_GETDEVCAPS_ITEM) {
TRACE("MCI_GETDEVCAPS_ITEM dwItem=%08X;\n", lpParms->dwItem);
return MCIERR_UNRECOGNIZED_COMMAND;
}
TRACE("lpParms->dwReturn=%08X;\n", lpParms->dwReturn);
+ if (dwFlags & MCI_NOTIFY) {
+ MCICDA_Notify(lpParms->dwCallback, wmcda, MCI_NOTIFY_SUCCESSFUL);
+ }
return ret;
}
*lpParms->lpstrReturn = 0;
}
TRACE("=> %s (%d)\n", debugstr_w(lpParms->lpstrReturn), ret);
+
+ if (MMSYSERR_NOERROR==ret && (dwFlags & MCI_NOTIFY))
+ MCICDA_Notify(lpParms->dwCallback, wmcda, MCI_NOTIFY_SUCCESSFUL);
return ret;
}
if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
- if (dwFlags & MCI_NOTIFY) {
- TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
- mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
- wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
- }
if (dwFlags & MCI_STATUS_ITEM) {
TRACE("dwItem = %x\n", lpParms->dwItem);
switch (lpParms->dwItem) {
} else {
WARN("not MCI_STATUS_ITEM !\n");
}
+ if ((dwFlags & MCI_NOTIFY) && HRESULT_CODE(ret)==0)
+ MCICDA_Notify(lpParms->dwCallback, wmcda, MCI_NOTIFY_SUCCESSFUL);
return ret;
}
{
WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
DWORD ret = 0, start, end;
+ HANDLE oldcb;
DWORD br;
CDROM_PLAY_AUDIO_MSF play;
CDROM_SUB_Q_DATA_FORMAT fmt;
}
TRACE("Playing from %u to %u\n", start, end);
+ oldcb = InterlockedExchangePointer(&wmcda->hCallback,
+ (dwFlags & MCI_NOTIFY) ? HWND_32(LOWORD(lpParms->dwCallback)) : NULL);
+ if (oldcb) mciDriverNotify(oldcb, wmcda->wNotifyDeviceID, MCI_NOTIFY_ABORTED);
+
if (wmcda->hThread != 0) {
SetEvent(wmcda->stopEvent);
WaitForSingleObject(wmcda->hThread, INFINITE);
IDirectSound_Release(wmcda->dsObj);
wmcda->dsObj = NULL;
}
- else if(wmcda->hCallback) {
- mciDriverNotify(wmcda->hCallback, wmcda->wNotifyDeviceID,
- MCI_NOTIFY_ABORTED);
- wmcda->hCallback = NULL;
- }
-
- if ((dwFlags&MCI_NOTIFY))
- wmcda->hCallback = HWND_32(LOWORD(lpParms->dwCallback));
if (pDirectSoundCreate) {
WAVEFORMATEX format;
wmcda->hThread = CreateThread(NULL, 0, MCICDA_playLoop, wmcda, 0, &br);
if (wmcda->hThread != 0) {
hr = IDirectSoundBuffer_Play(wmcda->dsBuf, 0, 0, DSBPLAY_LOOPING);
- if (SUCCEEDED(hr))
+ if (SUCCEEDED(hr)) {
+ /* FIXME: implement MCI_WAIT and send notification only in that case */
+ if (0) {
+ oldcb = InterlockedExchangePointer(&wmcda->hCallback, NULL);
+ if (oldcb) mciDriverNotify(oldcb, wmcda->wNotifyDeviceID,
+ FAILED(hr) ? MCI_NOTIFY_FAILURE : MCI_NOTIFY_SUCCESSFUL);
+ }
return ret;
+ }
SetEvent(wmcda->stopEvent);
WaitForSingleObject(wmcda->hThread, INFINITE);
NULL, 0, &br, NULL)) {
wmcda->hCallback = NULL;
ret = MCIERR_HARDWARE;
- } else if (dwFlags & MCI_NOTIFY) {
- TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
- /*
- mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
- wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
- */
}
+ /* The independent CD player has no means to signal MCI_NOTIFY when it's done.
+ * Native sends a notification with MCI_WAIT only. */
return ret;
}
static DWORD MCICDA_Stop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
{
WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
+ HANDLE oldcb;
DWORD br;
TRACE("(%04X, %08X, %p);\n", wDevID, dwFlags, lpParms);
if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
+ oldcb = InterlockedExchangePointer(&wmcda->hCallback, NULL);
+ if (oldcb) mciDriverNotify(oldcb, wmcda->wNotifyDeviceID, MCI_NOTIFY_ABORTED);
+
if (wmcda->hThread != 0) {
SetEvent(wmcda->stopEvent);
WaitForSingleObject(wmcda->hThread, INFINITE);
else if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_STOP_AUDIO, NULL, 0, NULL, 0, &br, NULL))
return MCIERR_HARDWARE;
- if (wmcda->hCallback) {
- mciDriverNotify(wmcda->hCallback, wmcda->wNotifyDeviceID, MCI_NOTIFY_ABORTED);
- wmcda->hCallback = NULL;
- }
-
- if (lpParms && (dwFlags & MCI_NOTIFY)) {
- TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
- mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
- wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
- }
+ if ((dwFlags & MCI_NOTIFY) && lpParms)
+ MCICDA_Notify(lpParms->dwCallback, wmcda, MCI_NOTIFY_SUCCESSFUL);
return 0;
}
static DWORD MCICDA_Pause(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
{
WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
+ HANDLE oldcb;
DWORD br;
TRACE("(%04X, %08X, %p);\n", wDevID, dwFlags, lpParms);
if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
+ oldcb = InterlockedExchangePointer(&wmcda->hCallback, NULL);
+ if (oldcb) mciDriverNotify(oldcb, wmcda->wNotifyDeviceID, MCI_NOTIFY_ABORTED);
+
if (wmcda->hThread != 0) {
/* Don't bother calling stop if the playLoop thread has already stopped */
if(WaitForSingleObject(wmcda->stopEvent, 0) != WAIT_OBJECT_0 &&
else if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_PAUSE_AUDIO, NULL, 0, NULL, 0, &br, NULL))
return MCIERR_HARDWARE;
- EnterCriticalSection(&wmcda->cs);
- if (wmcda->hCallback) {
- mciDriverNotify(wmcda->hCallback, wmcda->wNotifyDeviceID, MCI_NOTIFY_SUPERSEDED);
- wmcda->hCallback = NULL;
- }
- LeaveCriticalSection(&wmcda->cs);
-
- if (lpParms && (dwFlags & MCI_NOTIFY)) {
- TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
- mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
- wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
- }
+ if ((dwFlags & MCI_NOTIFY) && lpParms)
+ MCICDA_Notify(lpParms->dwCallback, wmcda, MCI_NOTIFY_SUCCESSFUL);
return 0;
}
else if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_RESUME_AUDIO, NULL, 0, NULL, 0, &br, NULL))
return MCIERR_HARDWARE;
- if (lpParms && (dwFlags & MCI_NOTIFY)) {
- TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
- mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
- wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
- }
+ if ((dwFlags & MCI_NOTIFY) && lpParms)
+ MCICDA_Notify(lpParms->dwCallback, wmcda, MCI_NOTIFY_SUCCESSFUL);
return 0;
}
return MCIERR_HARDWARE;
}
- if (dwFlags & MCI_NOTIFY) {
- TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
- mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
- wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
- }
+ if (dwFlags & MCI_NOTIFY)
+ MCICDA_Notify(lpParms->dwCallback, wmcda, MCI_NOTIFY_SUCCESSFUL);
return 0;
}
if (dwFlags & MCI_SET_VIDEO) return MCIERR_UNSUPPORTED_FUNCTION;
if (dwFlags & MCI_SET_ON) return MCIERR_UNSUPPORTED_FUNCTION;
if (dwFlags & MCI_SET_OFF) return MCIERR_UNSUPPORTED_FUNCTION;
- if (dwFlags & MCI_NOTIFY) {
- TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n",
- lpParms->dwCallback);
- mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
- wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
- }
+
+ if (dwFlags & MCI_NOTIFY)
+ MCICDA_Notify(lpParms->dwCallback, wmcda, MCI_NOTIFY_SUCCESSFUL);
return 0;
}