Некоторые сталкиваются с тем что необходимо распознать речь перевести её в текст и обработать. Проблема описывалась много раз как впрочем и пути её решения так что Google в помощь, но вот я столкнулся на собственном опыте с проблемой которая потребовала нетривиального решения, а именно как заставить распознавать речь с микрофона которые не установлен «по умолчанию». Если вы тоже столкнулись с подобной проблемой то эта статья именно для вас.
Итак что мы имеем — есть два различных движка для распознавания речи в Microsoft Windows (стандартный и Microsoft Speech SDK 11) причём сразу скажу что русский язык поддерживает пока только один из них, а именно Microsoft Speech SDK 11 с установленным русским языком. Если внимательно прочитать документацию по обоим движкам, то видно что в качестве устройства можно выбрать только DefaultInputDevice, но копнув глубже, а именно открыв сборку декомпилятором Telerik JustDecompile я убедился что все классы являются лишь обёрткой над СОМ объектами, а как раз в этих СОМ объектах нужная функция есть. Естественно что как и все программисты я ленивый и работать с СОМ не хотел, поэтому совмести два решения. Итак первое что нам необходима это найти Token нужного нам микрофона для этого существует следующая функция:
После того как мы получим Token необходимо вызвать приватные методы у класса «движка» распознавания для этого используется следующая функция:
В конце я приведу полный текст вспомогательного класса, который используется в моей разработке, Вы можете использовать его полностью или частично или просто вставить необходимые фрагмента кода себе. Всё это проверенно на Windows 7,8,8.1 ,NET 4.0, 4.5, но думаю что и с другими версиями будет работать также.
Итак что мы имеем — есть два различных движка для распознавания речи в 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.Reflection;
namespace RMI.SmartHouse.Service
{
/// <summary>
/// Позволяет осуществить выбор микрофонов.
/// </summary>
public class MicSelector : IDisposable
{
#region Приватные поля
private SpeechLib.SpInProcRecoContext _siprc;
private SpeechLib.ISpeechObjectTokens _isot;
private SpeechLib.SpObjectToken _sot;
private bool _isDisposed;
#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 _isot;
}
}
#endregion
#region Публичные методы
/// <summary>
/// Устанавливает выбранный микрофон.
/// </summary>
/// <param name="name">Имя микрофона.</param>
/// <param name="sre">Движок для распознавания.</param>
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);
if (fi != null)
{
object sapiRecognizer = fi.GetValue(sre);
MethodInfo mi = sapiRecognizer.GetType().GetMethod("SetInput", BindingFlags.Instance | BindingFlags.NonPublic);
object[] parms = { _sot, true };
mi.Invoke(sapiRecognizer, parms);
}
}
}
}
/// <summary>
/// Устанавливает выбранный микрофон.
/// </summary>
/// <param name="name">Имя микрофона.</param>
/// <param name="sre">Движок для распознавания.</param>
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);
if (fi != null)
{
object sapiRecognizer = fi.GetValue(sre);
MethodInfo mi = sapiRecognizer.GetType().GetMethod("SetInput", BindingFlags.Instance | BindingFlags.NonPublic);
object[] parms = { _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;
}
return null;
}
/// <summary>
/// Освобождение ресурсов.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
#region Приватные функции
/// <summary>
/// Освобождение ресурсов.
/// </summary>
protected virtual void Dispose(bool disposing)
{
if (!_isDisposed)
{
if (disposing)
{
_sot = null;
_isot = null;
_siprc = null;
}
_isDisposed = true;
}
}
/// <summary>
/// Поиск микрофона по имени.
/// </summary>
/// <param name="name">Имя для поиска.</param>
/// <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);
if (desc.Contains(name))
{
break;
}
}
return _sot;
}
return null;
}
#endregion
}
}