17

У меня есть приложение ASP.NET asp.net, которое имеет действие контроллера, которое берет строку в качестве входных данных и отправляет ответ wav-файла синтезированной речи. Вот упрощенный пример:System.Speech.Synthesis зависает с высоким процессором в 2012 R2

public async Task<ActionResult> Speak(string text) 
    { 
     Task<FileContentResult> task = Task.Run(() => 
     { 
      using (var synth = new System.Speech.Synthesis.SpeechSynthesizer()) 
      using (var stream = new MemoryStream()) 
      { 
       synth.SetOutputToWaveStream(stream); 
       synth.Speak(text); 
       var bytes = stream.GetBuffer(); 
       return File(bytes, "audio/x-wav"); 
      } 
     }); 
     return await task; 
    } 

Применение (и этот метод действий, в частности) работает нормально в среде сервера на 2008 серверов R2, 2012 серверов (не R2), и мой 8,1 Dev ПК. Он также отлично работает на стандартной виртуальной машине Azure 2012 R2. Однако, когда я развертываю его на трех серверах R2 R2 R2 (его возможном постоянном доме), метод действий никогда не вызывает ответа HTTP - процесс IIS Worker неограниченно увеличивает один из ядер процессора. В телезрителе событий ничего нет, и при просмотре сервера с Procmon ничего не выпрыгивает. Я подключил процесс с удаленной отладкой, и synth.Speak(text) никогда не возвращается. Когда выполняется вызов synth.Speak(text), я сразу вижу процесс runaway w3wp.exe в диспетчере задач сервера.

Моей первой была склонности верить какой-то процесс вмешивается в синтезе речи в целом на серверах, но для Windows Рассказчик работает правильно, и простое консольное приложение, как это работает правильно:

static void Main(string[] args) 
{ 
    var synth = new System.Speech.Synthesis.SpeechSynthesizer(); 
    synth.Speak("hello"); 
} 

Так, очевидно, Я не могу винить синтез речи сервера в целом. Так может быть, в моем коде есть проблема или что-то странное в конфигурации IIS? Как я могу заставить это действие контроллера работать на этих серверах?

Это простой способ проверить метод действия (просто должно получить право url значения для маршрутизации):

<div> 
    <input type="text" id="txt" autofocus /> 
    <button type="button" id="btn">Speak</button> 
</div> 

<script> 
    document.getElementById('btn').addEventListener('click', function() { 
     var text = document.getElementById('txt').value; 
     var url = window.location.href + '/speak?text=' + encodeURIComponent(text); 
     var audio = document.createElement('audio'); 
     var canPlayWavFileInAudioElement = audio.canPlayType('audio/wav'); 
     var bgSound = document.createElement('bgsound'); 
     bgSound.src = url; 
     var canPlayBgSoundElement = bgSound.getAttribute('src'); 

     if (canPlayWavFileInAudioElement) { 
      // probably Firefox and Chrome 
      audio.setAttribute('src', url); 
      audio.setAttribute('autoplay', ''); 
      document.getElementsByTagName('body')[0].appendChild(audio); 
     } else if (canPlayBgSoundElement) { 
      // internet explorer 
      document.getElementsByTagName('body')[0].appendChild(bgSound); 
     } else { 
      alert('This browser probably can\'t play a wav file'); 
     } 
    }); 
</script> 
+0

Вы пытались сделать это синхронным методом действий, не обернув его задачей? В этом коде могут возникнуть проблемы с пулом потоков, о котором ASP.NET не знает. –

+0

@DmitryS. Я не уверен, что могу сделать такой тест, как эта работа ... Если 'synth.Speak' не завернут, я получаю исключение во время выполнения:' InvalidOperationException' (асинхронная операция не может быть запущена в это время). Мне нравится линия мышления, но если это проблема пула потоков с ASP.NET, почему она будет работать на многих других серверах? – hmqcnoesy

+0

Последняя версия синтезатора имеет метод 'SpeakAsync()'. Вместо того, чтобы обертывать код в 'Task.Run()', вы можете просто «ждать SpeakAsync (text)». https://msdn.microsoft.com/en-us/library/system.speech.synthesis.speechsynthesizer.speakasync%28v=vs.110%29.aspx –

ответ

1

Я обнаружил, что могу воспроизвести проблему на других серверах, включая Azure VM, поэтому я исключил возможность проблемы с нашей конкретной средой.

Кроме того, я обнаружил, что я могу заставить код работать нормально на 2012 R2, если я запустил пул приложений под идентификатором, который был администратором на сервере и ранее был зарегистрирован на сервере. После очень длительного процесса устранения проблем с разрешениями я решил, что это должно быть что-то в процессе ведения журнала, который позволяет, что вызовы API TTS работают правильно. (Как бы то ни было, я не мог найти его, копая следы преследования). К счастью, ApplicationPoolIdentity может использовать аналогичную манеру входа, открыв «Расширенные настройки» для пула приложений в IIS и установив Load User Profile в True.

Идентичность, которая запускает приложение пул также необходимо разрешение на чтение HKU\.Default\Software\Microsoft\Speech, которое может быть предоставлено ApplicationPoolIdentity с помощью локального сервера для размещения и IIS APPPOOL\.Net v4.5 для пользователя (где .Net v4.5 это имя пула приложений).

После того, как разрешение на доступ к ключу reg предоставлено, а пул приложений настроен на загрузку профиля пользователя, приведенный выше код работает нормально. Протестировано на Azure VM и ванили 2012 R2 из MSDN ISO.

1

Я думаю, что вопрос является типом возвращаемого значения. IIS Экспресс позволяет вам уйти с ним, но IIS не является:

Task<FileContentResult> 

Так что, если вы пытаетесь:

public async Task<FileContentResult> Speak(string text) 
{ 
    Task<FileContentResult> task = Task.Run(() => 
    { 
     using (var synth = new System.Speech.Synthesis.SpeechSynthesizer()) 
     using (var stream = new MemoryStream()) 
     { 
      synth.SetOutputToWaveStream(stream); 
      synth.Speak(text); 
      var bytes = stream.GetBuffer(); 
      return File(bytes, "audio/x-wav"); 
     } 
    }); 
    return await task; 
} 

я уверен, вы также должны добавить аудио/WAV Тип MIME в IIS.

+0

К сожалению, нет, это не меняет поведение 2012 R2. – hmqcnoesy

+0

Тип MIME тоже не работает? –

+0

Нет, типы WAV MIME уже были настроены в IIS. Но все равно для статических файлов. – hmqcnoesy

-1

Это недалеко от верхней части моей головы, и он не был проверен, но вы можете быть в состоянии сделать что-то вроде этого:

public ActionResult Speak(string text) 
{ 
var speech = new SpeechSynthesizer(); 
speech.Speak(text); 

byte[] bytes; 
using (var stream = new MemoryStream()) 
{ 
    speech.SetOutputToWaveStream(stream); 
    bytes = stream.ToArray(); 
} 
return File(bytes, "audio/x-wav"); 
} 
1

Я имел этот опыт с сервером 2012R2 раньше (не synth api, но такая же проблема). Я исправил его, используя «ожидание task.ConfigureAwait (false)» во всех моих задачах. Посмотрите, работает ли это для вас.

Удачи.

+0

Спасибо, но, к сожалению, нет, это не помогло решить эту проблему. – hmqcnoesy

1

В this blog вы можете найти решение подобной проблемы - исключение при использовании SpeechSynthesizer при новой установке Windows 8.1. Проблема в этом случае связана с неправильным вводом права доступа для пользователя CurrentUserLexicon (который используется SpeechSynthesizer). Для устранения этого сообщения в блоге предлагается удалить запись разрешения «ВСЕ ПАРАМЕТРЫ ПРИЛОЖЕНИЙ» из раздела реестра Software \ Microsoft \ Speech \ CurrentUserLexicon.

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

  • Нет связанных вопросов^_^