Не удается получить доступ к микрофону во время запуска демонстрации Dialog в sphinx4 5prealpha
Я пытаюсь запустить диалоговое демо sphinx 4 pre aplha, но оно выдает ошибки.
Я создаю приложение для живой речи.
Я импортировал проект с помощью maven и следовал этому руководству по переполнению стека: /questions/43161008/cmu-sphinx-4-5-pre-alpha-rukovodstvo-po-ustanovke/43161012#43161012
Ошибка говорит о проблемах, касающихся 16 кГц и канала, являющегося моно. Так ясно, что о материале отбора проб. И это тоже говорит о микрофоне.
Я смотрел, как изменить настройки микрофона на 16 кГц и 16 бит, но в Windows 7 такой опции нет
:
Дело в том, что HelloWorld и демонстрация диалога работали нормально в бета-версии sphinx4 1.06, но после того, как я попробовал последний выпуск, он выдает следующие ошибки:
Exception in thread "main" java.lang.IllegalStateException: javax.sound.sampled.LineUnavailableException: line with format PCM_SIGNED 16000.0 Hz, 16 bit, mono, 2 bytes/frame, little-endian not supported.
at edu.cmu.sphinx.api.Microphone.<init>(Microphone.java:38)
at edu.cmu.sphinx.api.SpeechSourceProvider.getMicrophone(SpeechSourceProvider.java:18)
at edu.cmu.sphinx.api.LiveSpeechRecognizer.<init>(LiveSpeechRecognizer.java:34)
at edu.cmu.sphinx.demo.dialog.Dialog.main(Dialog.java:145)
Caused by: javax.sound.sampled.LineUnavailableException: line with format PCM_SIGNED 16000.0 Hz, 16 bit, mono, 2 bytes/frame, little-endian not supported.
at com.sun.media.sound.DirectAudioDevice$DirectDL.implOpen(DirectAudioDevice.java:513)
at com.sun.media.sound.AbstractDataLine.open(AbstractDataLine.java:121)
at com.sun.media.sound.AbstractDataLine.open(AbstractDataLine.java:413)
at edu.cmu.sphinx.api.Microphone.<init>(Microphone.java:36)
... 3 more
Не могу понять, что делать, чтобы решить проблему.
3 ответа
Если вы измените SpeechSourceProvider
чтобы вернуть постоянную ссылку на микрофон, он не будет пытаться создать несколько ссылок на микрофон, что является источником проблемы.
public class SpeechSourceProvider {
private static final Microphone mic = new Microphone(16000, 16, true, false);
Microphone getMicrophone() {
return mic;
}
}
Проблема здесь в том, что вы не хотите, чтобы несколько потоков пытались получить доступ к одному ресурсу, но для демонстрации распознаватели останавливаются и запускаются по мере необходимости, так что они не все конкурируют за микрофон.
Как объясняет Николай на форуме кузницы источников ( здесь), ресурс микрофона должен быть освобожден распознавателем, использующим его в настоящее время, чтобы другой распознаватель мог использовать микрофон. Пока API был исправлен, я сделал следующие изменения в некоторых классах в sphinx API как временное решение. Это, вероятно, не лучшее решение, думаю, пока не будет предложено лучшее решение, это будет работать.
Я создал класс с именем MicrophoneExtention
с тем же исходным кодом, что и Microphone
класс, и добавил следующие методы:
public void closeLine () { line.close (); }
Точно так же LiveSpeechRecognizerExtention
класс с исходным кодом LiveSpeechRecognizer
класс, и внесли следующие изменения:
- используйте определенный класс MicrohphoneExtention:
private final MicroPhoneExtention microphone;
- внутри конструктора,
microphone =new MicrophoneExtention(16000, 16, true, false);
- И добавьте следующие методы:
public void closeRecognitionLine () { microphone.closeLine (); }
Наконец я отредактировал основной метод DialogDemo
,
Конфигурация конфигурации = новая конфигурация ();
configuration.setAcousticModelPath(ACOUSTIC_MODEL);
configuration.setDictionaryPath(DICTIONARY_PATH);
configuration.setGrammarPath(GRAMMAR_PATH);
configuration.setUseGrammar(истина); configuration.setGrammarName("dialog");
LiveSpeechRecognizerExtention recognizer =
new LiveSpeechRecognizerExtention(configuration);
Recognizer.startRecognition(true);
while (true) {
System.out.println("Choose menu item:");
System.out.println("Example: go to the bank account");
System.out.println("Example: exit the program");
System.out.println("Example: weather forecast");
System.out.println("Example: digits\n");
String utterance = recognizer.getResult().getHypothesis();
if (utterance.startsWith("exit"))
break;
if (utterance.equals("digits")) {
recognizer.stopRecognition();
recognizer.closeRecognitionLine();
configuration.setGrammarName("digits.grxml");
recognizer=new LiveSpeechRecognizerExtention(configuration);
recognizeDigits(recognizer);
recognizer.closeRecognitionLine();
configuration.setGrammarName("dialog");
recognizer=new LiveSpeechRecognizerExtention(configuration);
recognizer.startRecognition(true);
}
if (utterance.equals("bank account")) {
recognizer.stopRecognition();
recognizerBankAccount(Recognizer);
recognizer.startRecognition(true);
}
if (utterance.endsWith("weather forecast")) {
recognizer.stopRecognition();
recognizer.closeRecognitionLine();
configuration.setUseGrammar(false);
configuration.setLanguageModelPath(LANGUAGE_MODEL);
recognizer=new LiveSpeechRecognizerExtention(configuration);
recognizeWeather(recognizer);
recognizer.closeRecognitionLine();
configuration.setUseGrammar(true);
configuration.setGrammarName("dialog");
recognizer=new LiveSpeechRecognizerExtention(configuration);
recognizer.startRecognition(true);
}
}
Recognizer.stopRecognition();
и, очевидно, подписи метода в DialogDemo
нужно изменить... надеюсь, это поможет... и в заключение, я не уверен, что то, что я сделал, является абсолютно законным для начала. Если я делаю что-то не так, пожалуйста, будьте любезны указать мои ошибки:D
Ответ aetherwalker работал для меня - более подробно я переписал следующие файлы с моими собственными реализациями, где я только изменил используемый SpeechSourceProvider:
Первый - это AbstractSpeechRecognizer:
public class MaxAbstractSpeechRecognizer {
protected final Context context;
protected final Recognizer recognizer;
protected ClusteredDensityFileData clusters;
protected final MaxSpeechSourceProvider speechSourceProvider;
/**
* Constructs recognizer object using provided configuration.
* @param configuration initial configuration
* @throws IOException if IO went wrong
*/
public MaxAbstractSpeechRecognizer(Configuration configuration)
throws IOException
{
this(new Context(configuration));
}
protected MaxAbstractSpeechRecognizer(Context context) throws IOException {
this.context = context;
recognizer = context.getInstance(Recognizer.class);
speechSourceProvider = new MaxSpeechSourceProvider();
} .......................
Затем LiveSpeechRecognizer:
public class MaxLiveSpeechRecognizer extends MaxAbstractSpeechRecognizer {
private final Microphone microphone;
/**
* Constructs new live recognition object.
*
* @param configuration common configuration
* @throws IOException if model IO went wrong
*/
public MaxLiveSpeechRecognizer(Configuration configuration) throws IOException
{
super(configuration);
microphone = speechSourceProvider.getMicrophone();
context.getInstance(StreamDataSource.class)
.setInputStream(microphone.getStream());
}......................
И последнее, но не менее важное: SpeechSourceProvider:
import edu.cmu.sphinx.api.Microphone;
public class MaxSpeechSourceProvider {
private static final Microphone mic = new Microphone(16000, 16, true, false);
Microphone getMicrophone() {
return mic;
}
}
Для меня с этим изменением проблема заключалась в том, что пока я оставался в контексте cmusphinx, было хорошо, что линию можно использовать повторно много раз. Но если я начну повторно использовать микрофон для другой работы (например, для записи), он будет недоступен!
Я вижу, что поток был открыт в классе Microphone, но никогда не закрывался!
Итак, сначала я перехожу в класс Microphone
следующие атрибуты от статических до динамических:
private TargetDataLine line;
private InputStream inputStream;
После изменения метода stopRecording для закрытия потока перед строкой:
/**
* close the stream and line
*/
public void stopRecording() {
if (inputStream != null )
try {
inputStream.close();
} catch (IOException e) {
throw new IllegalStateException(e);
}
line.stop();
}
И теперь, без каких-либо изменений (класс SpeechSourceProvider оригинальный), я могу повторно использовать микрофон для cmupsphinx и другой задачи записи.