2012-09-05 15 views
7

Antecedentes: En Windows Vista y superior, utilizando un ampliado Core Audio API (por Ray Molenkamp y Xavier Flix) para hacer cumplir los niveles de volumen mediante la suscripción de OnVolumeNotification del DefaultAudioEndpoint y ajuste de la volumen cuando cambiasuscripción de eventos CoreAudio OnVolumeNotification hace uso intensivo de la CPU en explorer.exe

Problema: Funcionalmente exitoso, pero tan pronto como se registra una suscripción a OnVolumeNotification, la CPU tiende a vincularse al 30-50% dependiendo de la potencia de su CPU. Después de excavar mucho con Process Explorer & Process Monitor, se reveló que explorer.exe y, en ocasiones, svchost.exe, serían consumidos por las llamadas de lectura de registros. No estoy seguro de qué clave de registro. No creo que me suscriba a este evento de forma perjudicial, ya que administro la suscripción con cuidado: solo se activa una vez.

proceso lógico de la aplicación de volumen

  1. Darse de baja de punto final OnVolumeNotification
  2. conjunto de propiedades de volumen variable escalar (efecto inmediato)
  3. Suscribirse al punto extremo OnVolumeNotification

Los métodos Win32 subyacentes involucrados en la API Core Audio son RegisterControlChangeNotify y UnregisterControlChangeNotify. ¿Es posible que el problema sea causado por estos o por la implementación de la suscripción al evento?

+1

¿Por qué no está claro qué clave de registro se está leyendo? Process Monitor debería darle esa información. Podría ser útil. Además, ¿intentó depurar explorer.exe? – Simon

+0

@Simon Me disculpo por no haber notado su comentario. No pude encontrar ninguna clave específica, no estoy 100% familiarizado con ProcMon. Estoy a punto de publicar una solución alternativa para quienes puedan tener el mismo problema. – erodewald

Respuesta

0

En lugar de:

  1. Cancelación de la suscripción
  2. Cambiar el volumen/set mute
  3. volver a suscribirse

he modificado mi lógica para usar esencialmente lógica en las propiedades con los campos de respaldo de manejar cuando actualizar. No es perfecto, pero está bastante cerca y no consume ninguna CPU y permite la entrada externa desde un control deslizante con soporte completo para INPC.

public EndpointVolumeEnforcer() { 
    try { 
    mmDeviceEnumerator = new MMDeviceEnumerator(); 
    mmDevice = mmDeviceEnumerator.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eMultimedia); 
    audioEndpointVolume = mmDevice.AudioEndpointVolume; 
    audioEndpointVolume.OnVolumeNotification += data => { 
     VolumePercent = Convert.ToInt16(data.MasterVolume*100); 
     DeviceIsMuted = data.Muted; 
    }; 
    DesiredVolume = 65; 
    } 
    catch (Exception ex) { 
    // Logging logic here 
    } 
} 

public int DesiredVolume { 
    get { return _desiredVolume; } 
    private set { 
    if (_desiredVolume == value) return; 
    _desiredVolume = value; 
    NotifyOfPropertyChange(); 
    Enforce(_desiredVolume); 
    } 
} 

public int VolumePercent { 
    get { return volumePercent; } 
    private set { 
    if (volumePercent == value) return; 
    volumePercent = value; 
    if (volumePercent != _desiredVolume) { 
     volumePercent = _desiredVolume; 
     Enforce(volumePercent); 
    } 
    } 
} 

public void Enforce(int pct, bool mute = false) { 
    var adjusted = Convert.ToInt16(audioEndpointVolume.MasterVolumeLevelScalar*100); 
    if (adjusted != DesiredVolume) { 
    audioEndpointVolume.MasterVolumeLevelScalar = pct/100f; 
    } 
} 
Cuestiones relacionadas