2014-09-29 3 views
1

Я пытаюсь получить аудиоинформацию с помощью powershell 4.0, в частности, пиковый звук в качестве звука. Таким образом, я нашел .Net-обертку для основного аудио api (можно найти here, а DLL-файл находится в CoreAudio \ bin) и пытался это использовать. Однако, для жизни меня, я не могу понять, как это сделать. Основная проблема заключается в том, что я не смог выяснить синтаксис доступа и использования методов классов, содержащихся в сборке. В частности, я пытаюсь работать с CoreAudio.AudioPeakMeter и CoreAudio.AudioMute.Проблемы с конструктором/методом с объектом framework .net в powershell

CoreAudio.AudioPeakMeter, например, должен иметь два члена, GetChannelCount и GetLevel.

Я попытался с помощью

[CoreAudio.AudioPeakMeter] | Get-Member -Static 

но что только возвращает Равно и ReferenceEquals что подтверждается, когда я использую

[CoreAudio.AudioPeakMeter]:: 

Я даже нашел функцию кто-то разместил в Интернете для получения конструкторов. Опять же, ничего не получилось. Как в буквальном смысле ничего. Выход не возвращается. Я подтвердил, что это работает для других, таких как System.Windows.Thickness, который использовался в качестве примера в сообщении.

Вот функция Get-Contructor, которую я нашел, если вам интересно.

function get-Constructor ([type]$type, [Switch]$FullName) 
{ 
    foreach ($c in $type.GetConstructors()) 
    { 
     $type.Name + "(" 
     foreach ($p in $c.GetParameters()) 
     { 
      if ($fullName) 
      { 
        "`t{0} {1}," -f $p.ParameterType.FullName, $p.Name 
      }else 
      { 
        "`t{0} {1}," -f $p.ParameterType.Name, $p.Name 
      } 
     } 
     ")" 
    } 
} 

ОДНАКО, я знаю GetChannelCount и GetLevel существуют и могут быть найдены в ISE через

(New-Object CoreAudio.AudioPeakMeter).GetChannelCount 

, а также с помощью команды

[CoreAudio.AudioPeakMeter].GetMethods() 

Для ISE, после ввода даты и GetChannelCount и GetLevel заполняются в списке ISE. Но, конечно, поскольку исходной проблемой является ошибка New-Object re на CoreAudio.AudioPeakMeter, powershell даже не пытается получить доступ к двум членам.

Последняя команда возвращает this, которую я отправил в pastebin.

Свойство метода IsSecurityCritical заставило меня подумать, что мне нужно запустить powershell с повышенными привилегиями. Однако, похоже, это не так, поскольку это не имело никакого значения.

Я подтвердил, что эти результаты одинаковы для всех классов в сборке. Однако я могу получить доступ к счетчикам. Вот пример:

[enum]::GetNames([CoreAudio.DEVICE_STATE]) 

Это верно вернет все возможные значения CoreAudio.DEVICE_STATE.

Есть ли что-то, что мне не хватает? Насколько я могу сказать, сборка правильно загружена (я использовал Add-Type), но powershell говорит, что методы класса не существуют, даже если они это делают.

+0

Класс 'AudioPeakMeter' не имеет открытого конструктора. Похоже, что один из немногих классов с открытым конструктором - 'MMDeviceEnumerator'. Я бы начал там. Вероятно, вы могли бы получить больше информации от чтения включенных образцов. –

+0

Мои знания о C# (или любой версии C на самом деле) довольно ограничены, поэтому я стараюсь понять исходный код и примеры как можно лучше, но я все еще недостаточно. Из того, что я могу сказать, и из моих исследований, похоже, что у AudioPeakMeter есть публичные конструкторы, но Powershell, похоже, не может их увидеть. Я также заметил, что '[CoreAudio.AudioPeakMeter] :: GetChannelCount' работает без ошибок, однако значения не возвращаются. Из исходного кода он должен возвращать int. – Mechajesus

ответ

0

Нашли решение! Это не совсем то решение, которое я искал, но оно работает. Я сделал еще несколько исследований и нашел this post. Кажется. .net-обертки для основного аудио-апи просто не играют хорошо с powershell. Я в конечном итоге взглянул на один из ответов на этот вопрос, выяснил, как это работает, и изменив его, чтобы делать то, что мне нужно. Я все-таки подумал, что я пытаюсь использовать неправильный интерфейс.Мне нужно было использовать IAudioMeterInformation вместо IAudioPeakMeter.

Вот что я придумал, что работает:

Add-Type -TypeDefinition @' 
using System.Runtime.InteropServices; 

[Guid("C02216F6-8C67-4B5B-9D00-D008E73E0064"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
interface IAudioMeterInformation { 
    int GetPeakValue(out float pfPeak); 
} 
[Guid("D666063F-1587-4E43-81F1-B948E807363F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
interface IMMDevice { 
    int Activate(ref System.Guid id, int clsCtx, int activationParams, out IAudioMeterInformation aev); 
} 
[Guid("A95664D2-9614-4F35-A746-DE8DB63617E6"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
interface IMMDeviceEnumerator { 
    int f(); // Unused 
    int GetDefaultAudioEndpoint(int dataFlow, int role, out IMMDevice endpoint); 
} 
[ComImport, Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")] class MMDeviceEnumeratorComObject { } 

public class AudioMeter { 
    static IAudioMeterInformation Meter() { 
    var enumerator = new MMDeviceEnumeratorComObject() as IMMDeviceEnumerator; 
    IMMDevice dev = null; 
    Marshal.ThrowExceptionForHR(enumerator.GetDefaultAudioEndpoint(/*eRender*/ 0, /*eMultimedia*/ 1, out dev)); 
    IAudioMeterInformation epv = null; 
    var epvid = typeof(IAudioMeterInformation).GUID; 
    Marshal.ThrowExceptionForHR(dev.Activate(ref epvid, /*CLSCTX_ALL*/ 23, 0, out epv)); 
    return epv; 
    } 
    public static float PeakValue { 
    get {float mv = -1; Marshal.ThrowExceptionForHR(Meter().GetPeakValue(out mv)); return mv;} 
    } 
}  
'@ 

Теперь я могу получить максимальное значение для звукового устройства и поток значения с помощью цикла. Пиковое значение - это плавающая переменная в диапазоне от 0 до 1, поэтому я умножил значение на 100 и преобразовал его в целое число, чтобы округлить значение до ближайшего целого числа. Цикл заканчивается при обнаружении нажатия клавиши.

do 
{ 
    Start-Sleep -Milliseconds 100 
    $var = [AudioMeter]::PeakValue * 100 
    $var 
} 
until($Host.UI.RawUI.KeyAvailable) 
$Host.UI.RawUI.FlushInputBuffer() 

я до сих пор не понял, как быть в состоянии использовать IMMDevice::Activate() метод на нескольких интерфейсах одновременно, так что я могу использовать IAudioEndpointVolume, а также для доступа к методу Mute, но это, наверное, другая тема для другого дня.

Смежные вопросы