Некоторые сталкиваются с тем что необходимо распознать речь перевести её в текст и обработать. Проблема описывалась много раз как впрочем и пути её решения так что Google в помощь, но вот я столкнулся на собственном опыте с проблемой которая потребовала нетривиального решения, а именно как заставить распознавать речь с микрофона которые не установлен «по умолчанию». Если вы тоже столкнулись с подобной проблемой то эта статья именно для вас.
Итак что мы имеем — есть два различных движка для распознавания речи в Microsoft Windows (стандартный и Microsoft Speech SDK 11) причём сразу скажу что русский язык поддерживает пока только один из них, а именно Microsoft Speech SDK 11 с установленным русским языком. Если внимательно прочитать документацию по обоим движкам, то видно что в качестве устройства можно выбрать только DefaultInputDevice, но копнув глубже, а именно открыв сборку декомпилятором Telerik JustDecompile я убедился что все классы являются лишь обёрткой над СОМ объектами, а как раз в этих СОМ объектах нужная функция есть. Естественно что как и все программисты я ленивый и работать с СОМ не хотел, поэтому совмести два решения. Итак первое что нам необходима это найти Token нужного нам микрофона для этого существует следующая функция:
private SpeechLib.SpObjectToken FindMicByName(string name)
{
if (isot != null)
{
for (int i = 0; i < isot.Count; i++)
{
sot = isot.Item(i);
string desc = sot.GetDescription(1033);
string id = sot.Id;
if (desc.Contains(name) != false)
{
break;
}
}
return sot;
}
else
return null;
}
После того как мы получим Token необходимо вызвать приватные методы у класса «движка» распознавания для этого используется следующая функция:
public void SetMicByName(string name, ref System.Speech.Recognition.SpeechRecognitionEngine sre)
{
if (isot != null)
{
sre.SetInputToDefaultAudioDevice();
sot = FindMicByName(name);
if (sot != null)
{
FieldInfo fi = sre.GetType().GetField("_sapiRecognizer", BindingFlags.Instance | BindingFlags.NonPublic);
object _sapiRecognizer = fi.GetValue(sre);
MethodInfo mi = _sapiRecognizer.GetType().GetMethod("SetInput", BindingFlags.Instance | BindingFlags.NonPublic);
object[] parms = new object[] { sot, true };
mi.Invoke(_sapiRecognizer, parms);
}
}
}
В конце я приведу полный текст вспомогательного класса, который используется в моей разработке, Вы можете использовать его полностью или частично или просто вставить необходимые фрагмента кода себе. Всё это проверенно на Windows 7,8,8.1 ,NET 4.0, 4.5, но думаю что и с другими версиями будет работать также.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
namespace RMI.SmartHouse.Service
{
/// <summary>
/// Позволяет осуществить выбор микрофонов.
/// </summary>
public class MicSelector : IDisposable
{
#region Приватные поля
SpeechLib.SpInProcRecoContext siprc;
SpeechLib.ISpeechObjectTokens isot;
SpeechLib.SpObjectToken sot;
#endregion
#region Конструкторы
/// <summary>
/// Конструктор по умолчанию.
/// </summary>
public MicSelector()
{
siprc = new SpeechLib.SpInProcRecoContext();
isot = siprc.Recognizer.GetAudioInputs(null, null);
sot = null;
}
#endregion
#region Публичные свойства
/// <summary>
/// Список доступных устройств.
/// </summary>
public SpeechLib.ISpeechObjectTokens Isot
{
get
{
return this.isot;
}
private set
{
this.isot = value;
}
}
#endregion
#region Публичные методы
/// <summary>
/// Устанавливает выбранный микрофон.
/// </summary>
/// <param name="name">Имя микрофона.
/// <param name="sre">Движок для распознавания.
public void SetMicByName(string name, ref System.Speech.Recognition.SpeechRecognitionEngine sre)
{
if (isot != null)
{
sre.SetInputToDefaultAudioDevice();
sot = FindMicByName(name);
if (sot != null)
{
FieldInfo fi = sre.GetType().GetField("_sapiRecognizer", BindingFlags.Instance | BindingFlags.NonPublic);
object _sapiRecognizer = fi.GetValue(sre);
MethodInfo mi = _sapiRecognizer.GetType().GetMethod("SetInput", BindingFlags.Instance | BindingFlags.NonPublic);
object[] parms = new object[] { sot, true };
mi.Invoke(_sapiRecognizer, parms);
}
}
}
/// <summary>
/// Устанавливает выбранный микрофон.
/// </summary>
/// <param name="name">Имя микрофона.
/// <param name="sre">Движок для распознавания.
public void SetMicByName(string name, ref Microsoft.Speech.Recognition.SpeechRecognitionEngine sre)
{
if (isot != null)
{
sre.SetInputToDefaultAudioDevice();
sot = FindMicByName(name);
if (sot != null)
{
FieldInfo fi = sre.GetType().GetField("_sapiRecognizer", BindingFlags.Instance | BindingFlags.NonPublic);
object _sapiRecognizer = fi.GetValue(sre);
MethodInfo mi = _sapiRecognizer.GetType().GetMethod("SetInput", BindingFlags.Instance | BindingFlags.NonPublic);
object[] parms = new object[] { sot, true };
mi.Invoke(_sapiRecognizer, parms);
}
}
}
/// <summary>
/// Обновляет список доступных устройств.
/// </summary>
/// <returns>Список доступных устройств.</returns>
public SpeechLib.ISpeechObjectTokens UpdateDeviceList()
{
if (siprc != null)
{
isot = siprc.Recognizer.GetAudioInputs(null, null);
return isot;
}
else
{
return null;
}
}
/// <summary>
/// Освобождение ресурсов.
/// </summary>
public void Dispose()
{
if (sot != null)
{
sot = null;
}
if (isot != null)
{
isot = null;
}
if (siprc != null)
{
siprc = null;
}
GC.Collect();
}
#endregion
#region Приватные функции
/// <summary>
/// Поиск микрофона по имени.
/// </summary>
/// <param name="name">Имя для поиска.
/// <returns>Токен микрофона.</returns>
private SpeechLib.SpObjectToken FindMicByName(string name)
{
if (isot != null)
{
for (int i = 0; i < isot.Count; i++)
{
sot = isot.Item(i);
string desc = sot.GetDescription(1033);
string id = sot.Id;
if (desc.Contains(name) != false)
{
break;
}
}
return sot;
}
else
return null;
}
#endregion
}
}
Автор: maxim_rubchenko