Как настроить усиление микрофона в C # (нужно работать на XP & W7) - PullRequest
7 голосов
/ 11 июня 2010

Во-первых, обратите внимание, что я знаю, что уже есть несколько вопросов, подобных этому; Однако они кажется, не решить проблему адекватно. У меня есть приложение C # со всеми хуками pInvoke для связи с API WaveXXX, и я могу делать захват и воспроизведение из аудио с этим. Я также могу настроить громкость динамика (WaveOut) с помощью этого API.
Проблема в том, что по какой-то причине этот API не позволяет мне настраивать микрофон (WaveIn) громкость. Итак, мне удалось найти код микшера, который я также извлек и доступ через pInvoke и это позволяет мне регулировать громкость микрофона, но только на моем ПК W7. Код микшера, с которого я начал, взят отсюда: http://social.msdn.microsoft.com/Forums/en-US/isvvba/thread/05dc2d35-1d45-4837-8e16-562ee919da85 и это работает, но написано для регулировки громкости динамика. Я добавил метод SetMicVolume показано здесь ...

    public static void SetMicVolume(int mxid, int percentage)
    {
        bool rc;
        int mixer, vVolume;
        MIXERCONTROL volCtrl = new MIXERCONTROL();
        int currentVol;
        mixerOpen(out mixer, mxid, 0, 0, MIXER_OBJECTF_WAVEIN);
        int type = MIXERCONTROL_CONTROLTYPE_VOLUME;
        rc = GetVolumeControl(mixer, MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE, type, out volCtrl, out currentVol);
        if (rc == false)
        {
            mixerClose(mixer);
            mixerOpen(out mixer, 0, 0, 0, 0);
            rc = GetVolumeControl(mixer, MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE, type, out volCtrl, out currentVol);
            if (rc == false)    
                throw new Exception("SetMicVolume/GetVolumeControl() failed");
        }
        vVolume = ((int)((float)(volCtrl.lMaximum - volCtrl.lMinimum) / 100.0F) * percentage);
        rc = SetVolumeControl(mixer, volCtrl, vVolume);
        if (rc == false)
            throw new Exception("SetMicVolume/SetVolumeControl() failed");
        mixerClose(mixer);
    }

Обратите внимание на «вторую попытку» вызвать GetVolumeControl (). Это сделано потому, что в XP при первом вызове GetVolumeControl (см. Сайт выше для этого кода) происходит сбой вызова mixerGetLineControlsA (), а системы XP возвращают MIXERR_INVALCONTROL. Затем, со второй попыткой использования mixerOpen (out mixer, 0, 0, 0, 0), код не возвращает ошибку, но усиление микрофона не изменяется. Обратите внимание, как я уже говорил выше, это работает на W7 (вторая попытка никогда не выполняется, потому что она не завершается с помощью mixerOpen (out mixer, mxid, 0, 0, MIXER_OBJECTF_WAVEIN)).

Я признаю, что не очень хорошо разбираюсь в API микшера, так что сейчас я в этом разбираюсь; Однако, если кто-нибудь знает, почему это будет работать на W7, но не на XP, я бы хотел это услышать. Между тем, если я выясню это до того, как получу ответ, я опубликую свой собственный ответ ...

Ответы [ 2 ]

1 голос
/ 11 июня 2010

Мне кажется, что следующий код работает нормально ( обновлено 29.09.2010 ). Обратите внимание, что мои тестовые примеры - это два моих компьютера, один из которых W7, а другой - XP, так что это не окончательно. Я проверил, что это работает не для всех машин, но для тех, на которых они работают, похоже, все в порядке.

    public static bool setMicVolume(int mxid, int percentage)
    {
        if (mixerdisabled)
            return(false);

        bool rc;
        int mixer, vVolume, ctrltype, comptype;
        MIXERCONTROL volCtrl = new MIXERCONTROL();
        int currentVol;
        int mr = mixerOpen(out mixer, mxid, 0, 0, MIXER_OBJECTF_WAVEIN);
        if (mr != MMSYSERR_NOERROR)
        {
            Warning("mixerOpen() failed: " + mr.ToString());
            mixerdisabled = true;
            return(false);
        }
        ctrltype = MIXERCONTROL_CONTROLTYPE_VOLUME;
        comptype = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
        rc = GetVolumeControl(mixer, comptype, ctrltype, out volCtrl, out currentVol);
        if (rc == false)
        {
            Warning("SetMicVolume/GetVolumeControl() failed");
            mixerdisabled = true;
            mixerClose(mixer);
            return(false);
        }
        vVolume = ((int)((float)(volCtrl.lMaximum - volCtrl.lMinimum) / 100.0F) * percentage);
        rc = SetVolumeControl(mixer, volCtrl, vVolume);
        if (rc == false)
        {
            Warning("SetMicVolume/SetVolumeControl() failed");
            mixerdisabled = true;
            mixerClose(mixer);
            return (false);
        }
        mixerClose(mixer);
        return (true);
    }

Обратите внимание, что основное отличие состоит в том, что я использую тип компонента 'MIXERLINE_COMPONENTTYPE_DST_WAVEIN' вместо 'MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE'. На самом деле не понимаю этого, поэтому, если кто-то хочет присоединиться к объяснению (или сказать, что это не сработает в общем), я приветствую ответы!

1 голос
/ 11 июня 2010

Я пытался сделать именно это некоторое время назад, когда писал .NET Voice Recorder с помощью NAudio, и мне это было очень сложно. Возможно, вам придется написать две партии кода, одну для XP и одну для Vista / Win 7. Я использую NAudio для взаимодействия микшера.

Это то, чем я закончил (до сих пор не работает везде)

    private void TryGetVolumeControl()
    {
        int waveInDeviceNumber = waveIn.DeviceNumber;
        if (Environment.OSVersion.Version.Major >= 6) // Vista and over
        {
            var mixerLine = new MixerLine((IntPtr)waveInDeviceNumber, 0, MixerFlags.WaveIn);
            foreach (var control in mixerLine.Controls)
            {
                if (control.ControlType == MixerControlType.Volume)
                {
                    volumeControl = control as UnsignedMixerControl;
                    MicrophoneLevel = desiredVolume;
                    break;
                }
            }
        }
        else
        {
            var mixer = new Mixer(waveInDeviceNumber);
            foreach (var destination in mixer.Destinations)
            {
                if (destination.ComponentType == MixerLineComponentType.DestinationWaveIn)
                {
                    foreach (var source in destination.Sources)
                    {
                        if (source.ComponentType == MixerLineComponentType.SourceMicrophone)
                        {
                            foreach (var control in source.Controls)
                            {
                                if (control.ControlType == MixerControlType.Volume)
                                {
                                    volumeControl = control as UnsignedMixerControl;
                                    MicrophoneLevel = desiredVolume;
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }

    }
...