msacm: Implement acmDriverPriority with driver priority/enabled saving. Foundation for notification broadcasts with support for deferred notification.
diff --git a/dlls/msacm/driver.c b/dlls/msacm/driver.c index eef7875..302cfee 100644 --- a/dlls/msacm/driver.c +++ b/dlls/msacm/driver.c
@@ -404,22 +404,9 @@ */ MMRESULT WINAPI acmDriverPriority(HACMDRIVERID hadid, DWORD dwPriority, DWORD fdwPriority) { - PWINE_ACMDRIVERID padid; - CHAR szSubKey[17]; - CHAR szBuffer[256]; - LONG lBufferLength = sizeof(szBuffer); - LONG lError; - HKEY hPriorityKey; - DWORD dwPriorityCounter; TRACE("(%p, %08lx, %08lx)\n", hadid, dwPriority, fdwPriority); - padid = MSACM_GetDriverID(hadid); - if (!padid) { - WARN("invalid handle\n"); - return MMSYSERR_INVALHANDLE; - } - /* Check for unknown flags */ if (fdwPriority & ~(ACM_DRIVERPRIORITYF_ENABLE|ACM_DRIVERPRIORITYF_DISABLE| @@ -441,33 +428,91 @@ WARN("invalid flag\n"); return MMSYSERR_INVALFLAG; } + + /* According to MSDN, ACM_DRIVERPRIORITYF_BEGIN and ACM_DRIVERPRIORITYF_END + may only appear by themselves, and in addition, hadid and dwPriority must + both be zero */ + if ((fdwPriority & ACM_DRIVERPRIORITYF_BEGIN) || + (fdwPriority & ACM_DRIVERPRIORITYF_END)) { + if (fdwPriority & ~(ACM_DRIVERPRIORITYF_BEGIN|ACM_DRIVERPRIORITYF_END)) { + WARN("ACM_DRIVERPRIORITYF_[BEGIN|END] cannot be used with any other flags\n"); + return MMSYSERR_INVALPARAM; + } + if (dwPriority) { + WARN("priority invalid with ACM_DRIVERPRIORITYF_[BEGIN|END]\n"); + return MMSYSERR_INVALPARAM; + } + if (hadid) { + WARN("non-null hadid invalid with ACM_DRIVERPRIORITYF_[BEGIN|END]\n"); + return MMSYSERR_INVALPARAM; + } + /* FIXME: MSDN wording suggests that deferred notification should be + implemented as a system-wide lock held by a calling task, and that + re-enabling notifications should broadcast them across all processes. + This implementation uses a simple DWORD counter. One consequence of the + current implementation is that applications will never see + MMSYSERR_ALLOCATED as a return error. + */ + if (fdwPriority & ACM_DRIVERPRIORITYF_BEGIN) { + MSACM_DisableNotifications(); + } else if (fdwPriority & ACM_DRIVERPRIORITYF_END) { + MSACM_EnableNotifications(); + } + return MMSYSERR_NOERROR; + } else { + PWINE_ACMDRIVERID padid; + BOOL bPerformBroadcast = FALSE; - lError = RegOpenKeyA(HKEY_CURRENT_USER, - "Software\\Microsoft\\Multimedia\\" - "Audio Compression Manager\\Priority v4.00", - &hPriorityKey - ); - /* FIXME: Create key */ - if (lError != ERROR_SUCCESS) { - WARN("RegOpenKeyA failed\n"); - return MMSYSERR_ERROR; + /* Fetch driver ID */ + padid = MSACM_GetDriverID(hadid); + if (!padid) { + WARN("invalid handle\n"); + return MMSYSERR_INVALHANDLE; + } + + /* Check whether driver ID is appropriate for requested op */ + if (dwPriority) { + if (padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_LOCAL) { + return MMSYSERR_NOTSUPPORTED; + } + if (dwPriority != 1 && dwPriority != -1) { + FIXME("unexpected priority %ld, using sign only\n", dwPriority); + if (dwPriority < 0) dwPriority = -1; + if (dwPriority > 0) dwPriority = 1; + } + + if (dwPriority == 1 && (padid->pPrevACMDriverID == NULL || + (padid->pPrevACMDriverID->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_LOCAL))) { + /* do nothing - driver is first of list, or first after last + local driver */ + } else if (dwPriority == -1 && padid->pNextACMDriverID == NULL) { + /* do nothing - driver is last of list */ + } else { + MSACM_RePositionDriver(padid, dwPriority); + bPerformBroadcast = TRUE; + } + } + + /* Check whether driver ID should be enabled or disabled */ + if (fdwPriority & ACM_DRIVERPRIORITYF_DISABLE) { + if (!(padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED)) { + padid->fdwSupport |= ACMDRIVERDETAILS_SUPPORTF_DISABLED; + bPerformBroadcast = TRUE; + } + } else if (fdwPriority & ACM_DRIVERPRIORITYF_ENABLE) { + if (padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) { + padid->fdwSupport &= ~ACMDRIVERDETAILS_SUPPORTF_DISABLED; + bPerformBroadcast = TRUE; + } + } + + /* Perform broadcast of changes */ + if (bPerformBroadcast) { + MSACM_WriteCurrentPriorities(); + MSACM_BroadcastNotification(); + } + return MMSYSERR_NOERROR; } - - for (dwPriorityCounter = 1; ; dwPriorityCounter++) { - snprintf(szSubKey, 17, "Priority%ld", dwPriorityCounter); - lError = RegQueryValueA(hPriorityKey, szSubKey, szBuffer, &lBufferLength); - if (lError != ERROR_SUCCESS) - break; - - FIXME("(%p, %ld, %ld): stub (partial)\n", - hadid, dwPriority, fdwPriority); - break; - } - - RegCloseKey(hPriorityKey); - - WARN("RegQueryValueA failed\n"); - return MMSYSERR_ERROR; } /*********************************************************************** @@ -491,6 +536,7 @@ } MSACM_UnregisterDriver(padid); + MSACM_BroadcastNotification(); return MMSYSERR_NOERROR; }
diff --git a/dlls/msacm/internal.c b/dlls/msacm/internal.c index 19b64cb..a5eb350 100644 --- a/dlls/msacm/internal.c +++ b/dlls/msacm/internal.c
@@ -46,6 +46,9 @@ PWINE_ACMDRIVERID MSACM_pFirstACMDriverID = NULL; PWINE_ACMDRIVERID MSACM_pLastACMDriverID = NULL; +static DWORD MSACM_suspendBroadcastCount = 0; +static BOOL MSACM_pendingBroadcast = FALSE; + static void MSACM_ReorderDriversByPriority(void); #if 0 @@ -334,6 +337,90 @@ } /*********************************************************************** + * MSACM_BroadcastNotification() + */ +void MSACM_BroadcastNotification(void) +{ + if (MSACM_suspendBroadcastCount <= 0) { + FIXME("notification broadcast not (yet) implemented\n"); + } else { + MSACM_pendingBroadcast = TRUE; + } +} + +/*********************************************************************** + * MSACM_DisableNotifications() + */ +void MSACM_DisableNotifications(void) +{ + MSACM_suspendBroadcastCount++; +} + +/*********************************************************************** + * MSACM_EnableNotifications() + */ +void MSACM_EnableNotifications(void) +{ + if (MSACM_suspendBroadcastCount > 0) { + MSACM_suspendBroadcastCount--; + if (MSACM_suspendBroadcastCount == 0 && MSACM_pendingBroadcast) { + MSACM_pendingBroadcast = FALSE; + MSACM_BroadcastNotification(); + } + } +} + +/*********************************************************************** + * MSACM_RePositionDriver() + */ +void MSACM_RePositionDriver(PWINE_ACMDRIVERID padid, DWORD dwPriority) +{ + PWINE_ACMDRIVERID pTargetPosition = NULL; + + /* Remove selected driver from linked list */ + if (MSACM_pFirstACMDriverID == padid) { + MSACM_pFirstACMDriverID = padid->pNextACMDriverID; + } + if (MSACM_pLastACMDriverID == padid) { + MSACM_pLastACMDriverID = padid->pPrevACMDriverID; + } + if (padid->pPrevACMDriverID != NULL) { + padid->pPrevACMDriverID->pNextACMDriverID = padid->pNextACMDriverID; + } + if (padid->pNextACMDriverID != NULL) { + padid->pNextACMDriverID->pPrevACMDriverID = padid->pPrevACMDriverID; + } + + /* Look up position where selected driver should be */ + if (dwPriority == 1) { + pTargetPosition = padid->pPrevACMDriverID; + while (pTargetPosition->pPrevACMDriverID != NULL && + !(pTargetPosition->pPrevACMDriverID->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_LOCAL)) { + pTargetPosition = pTargetPosition->pPrevACMDriverID; + } + } else if (dwPriority == -1) { + pTargetPosition = padid->pNextACMDriverID; + while (pTargetPosition->pNextACMDriverID != NULL) { + pTargetPosition = pTargetPosition->pNextACMDriverID; + } + } + + /* Place selected driver in selected position */ + padid->pPrevACMDriverID = pTargetPosition->pPrevACMDriverID; + padid->pNextACMDriverID = pTargetPosition; + if (padid->pPrevACMDriverID != NULL) { + padid->pPrevACMDriverID->pNextACMDriverID = padid; + } else { + MSACM_pFirstACMDriverID = padid; + } + if (padid->pNextACMDriverID != NULL) { + padid->pNextACMDriverID->pPrevACMDriverID = padid; + } else { + MSACM_pLastACMDriverID = padid; + } +} + +/*********************************************************************** * MSACM_ReorderDriversByPriority() * Reorders all drivers based on the priority list indicated by the registry key: * HKCU\\Software\\Microsoft\\Multimedia\\Audio Compression Manager\\Priority v4.00 @@ -446,6 +533,79 @@ } /*********************************************************************** + * MSACM_WriteCurrentPriorities() + * Writes out current order of driver priorities to registry key: + * HKCU\\Software\\Microsoft\\Multimedia\\Audio Compression Manager\\Priority v4.00 + */ +void MSACM_WriteCurrentPriorities(void) +{ + LONG lError; + HKEY hPriorityKey; + static const WCHAR basePriorityKey[] = { + 'S','o','f','t','w','a','r','e','\\', + 'M','i','c','r','o','s','o','f','t','\\', + 'M','u','l','t','i','m','e','d','i','a','\\', + 'A','u','d','i','o',' ','C','o','m','p','r','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\', + 'P','r','i','o','r','i','t','y',' ','v','4','.','0','0','\0' + }; + PWINE_ACMDRIVERID padid; + DWORD dwPriorityCounter; + static const WCHAR priorityTmpl[] = {'P','r','i','o','r','i','t','y','%','l','d','\0'}; + static const WCHAR valueTmpl[] = {'%','c',',',' ','%','s','\0'}; + static const WCHAR converterAlias[] = {'I','n','t','e','r','n','a','l',' ','P','C','M',' ','C','o','n','v','e','r','t','e','r','\0'}; + WCHAR szSubKey[17]; + WCHAR szBuffer[256]; + + /* Delete ACM priority key and create it anew */ + lError = RegDeleteKeyW(HKEY_CURRENT_USER, basePriorityKey); + if (lError != ERROR_SUCCESS && lError != ERROR_FILE_NOT_FOUND) { + ERR("unable to remove current key %s (0x%08lx) - priority changes won't persist past application end.\n", + debugstr_w(basePriorityKey), lError); + return; + } + lError = RegCreateKeyW(HKEY_CURRENT_USER, basePriorityKey, &hPriorityKey); + if (lError != ERROR_SUCCESS) { + ERR("unable to create key %s (0x%08lx) - priority changes won't persist past application end.\n", + debugstr_w(basePriorityKey), lError); + return; + } + + /* Write current list of priorities */ + for (dwPriorityCounter = 0, padid = MSACM_pFirstACMDriverID; padid; padid = padid->pNextACMDriverID) { + if (padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_LOCAL) continue; + if (padid->pszDriverAlias == NULL) continue; /* internal PCM converter is last */ + + /* Build required value name */ + dwPriorityCounter++; + snprintfW(szSubKey, 17, priorityTmpl, dwPriorityCounter); + + /* Value has a 1 in front for enabled drivers and 0 for disabled drivers */ + snprintfW(szBuffer, 256, valueTmpl, (padid->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) ? '0' : '1', padid->pszDriverAlias); + strlwrW(szBuffer); + + lError = RegSetValueExW(hPriorityKey, szSubKey, 0, REG_SZ, (BYTE *)szBuffer, (strlenW(szBuffer) + 1) * sizeof(WCHAR)); + if (lError != ERROR_SUCCESS) { + ERR("unable to write value for %s under key %s (0x%08lx)\n", + debugstr_w(padid->pszDriverAlias), debugstr_w(basePriorityKey), lError); + } + } + + /* Build required value name */ + dwPriorityCounter++; + snprintfW(szSubKey, 17, priorityTmpl, dwPriorityCounter); + + /* Value has a 1 in front for enabled drivers and 0 for disabled drivers */ + snprintfW(szBuffer, 256, valueTmpl, '1', converterAlias); + + lError = RegSetValueExW(hPriorityKey, szSubKey, 0, REG_SZ, (BYTE *)szBuffer, (strlenW(szBuffer) + 1) * sizeof(WCHAR)); + if (lError != ERROR_SUCCESS) { + ERR("unable to write value for %s under key %s (0x%08lx)\n", + debugstr_w(converterAlias), debugstr_w(basePriorityKey), lError); + } + RegCloseKey(hPriorityKey); +} + +/*********************************************************************** * MSACM_UnregisterDriver() */ PWINE_ACMDRIVERID MSACM_UnregisterDriver(PWINE_ACMDRIVERID p)
diff --git a/dlls/msacm/wineacm.h b/dlls/msacm/wineacm.h index c844ab5..0a3af41 100644 --- a/dlls/msacm/wineacm.h +++ b/dlls/msacm/wineacm.h
@@ -348,6 +348,12 @@ extern MMRESULT MSACM_Message(HACMDRIVER, UINT, LPARAM, LPARAM); extern BOOL MSACM_FindFormatTagInCache(WINE_ACMDRIVERID*, DWORD, LPDWORD); +extern void MSACM_RePositionDriver(PWINE_ACMDRIVERID, DWORD); +extern void MSACM_WriteCurrentPriorities(void); +extern void MSACM_BroadcastNotification(void); +extern void MSACM_DisableNotifications(void); +extern void MSACM_EnableNotifications(void); + /* From msacm32.c */ extern HINSTANCE MSACM_hInstance32;