msacm: Implement acmDriverPriority with driver priority/enabled saving.

Foundation for notification broadcasts with support for deferred
notification.
This commit is contained in:
Alex Villacís Lasso 2006-01-18 12:06:56 +01:00 committed by Alexandre Julliard
parent 8d52016114
commit cb37c43d78
3 changed files with 250 additions and 38 deletions

View File

@ -404,22 +404,9 @@ MMRESULT WINAPI acmDriverOpen(PHACMDRIVER phad, HACMDRIVERID hadid, DWORD fdwOpe
*/
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|
@ -442,32 +429,90 @@ MMRESULT WINAPI acmDriverPriority(HACMDRIVERID hadid, DWORD dwPriority, DWORD fd
return MMSYSERR_INVALFLAG;
}
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;
/* 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;
/* Fetch driver ID */
padid = MSACM_GetDriverID(hadid);
if (!padid) {
WARN("invalid handle\n");
return MMSYSERR_INVALHANDLE;
}
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;
/* 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;
}
RegCloseKey(hPriorityKey);
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;
}
}
WARN("RegQueryValueA failed\n");
return MMSYSERR_ERROR;
/* 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;
}
}
/***********************************************************************
@ -491,6 +536,7 @@ MMRESULT WINAPI acmDriverRemove(HACMDRIVERID hadid, DWORD fdwRemove)
}
MSACM_UnregisterDriver(padid);
MSACM_BroadcastNotification();
return MMSYSERR_NOERROR;
}

View File

@ -46,6 +46,9 @@ HANDLE MSACM_hHeap = NULL;
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
@ -333,6 +336,90 @@ void MSACM_RegisterAllDrivers(void)
MSACM_RegisterDriver(msacm32, msacm32, 0);
}
/***********************************************************************
* 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:
@ -445,6 +532,79 @@ errCleanUp:
if (driverList != NULL) HeapFree(MSACM_hHeap, 0, driverList);
}
/***********************************************************************
* 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()
*/

View File

@ -348,6 +348,12 @@ extern PWINE_ACMOBJ MSACM_GetObj(HACMOBJ hObj, DWORD type);
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;