Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-mvc/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# System.Speech.Synthesis在2012 R2上因CPU过高而挂起_C#_Asp.net Mvc_Text To Speech_Windows Server 2012 R2_Speech Synthesis - Fatal编程技术网

C# System.Speech.Synthesis在2012 R2上因CPU过高而挂起

C# System.Speech.Synthesis在2012 R2上因CPU过高而挂起,c#,asp.net-mvc,text-to-speech,windows-server-2012-r2,speech-synthesis,C#,Asp.net Mvc,Text To Speech,Windows Server 2012 R2,Speech Synthesis,我有一个asp.NETMVC应用程序,它有一个控制器操作,将字符串作为输入,并发送合成语音的响应wav文件。以下是一个简化的示例: public async Task<ActionResult> Speak(string text) { Task<FileContentResult> task = Task.Run(() => { using (var synth = new System.Sp

我有一个asp.NETMVC应用程序,它有一个控制器操作,将字符串作为输入,并发送合成语音的响应wav文件。以下是一个简化的示例:

    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;
    }
所以很明显,我不能总的说来责怪服务器的语音合成。那么,也许我的代码中有问题,或者IIS配置中有什么奇怪的地方?如何使此控制器操作在这些服务器上正常工作

这是一种测试操作方法的简单方法(只需获得路由的
url
值):


通话
document.getElementById('btn')。addEventListener('click',函数(){
var text=document.getElementById('txt').value;
var url=window.location.href+'/speak?text='+encodeURIComponent(text);
var audio=document.createElement('audio');
var canplayWavFileInudioElement=audio.canPlayType('audio/wav');
var bgSound=document.createElement('bgSound');
bgSound.src=url;
var canPlayBgSoundElement=bgSound.getAttribute('src');
if(CANPLAYWAVFILEINUDIOLEMENT){
//可能是Firefox和Chrome
setAttribute('src',url);
setAttribute('autoplay','');
document.getElementsByTagName('body')[0].appendChild(音频);
}else if(canPlayBgSoundElement){
//internet explorer
document.getElementsByTagName('body')[0].appendChild(bgSound);
}否则{
警报(“此浏览器可能无法播放wav文件”);
}
});

我认为问题在于退货类型。IIS Express可以让您逍遥法外,但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;
}
公共异步任务发言(字符串文本)
{
任务=任务。运行(()=>
{
使用(var synth=new System.Speech.Synthesis.SpeechSynthesizer())
使用(var stream=new MemoryStream())
{
synth.SetOutputToWaveStream(流);
synth.Speak(文本);
var bytes=stream.GetBuffer();
返回文件(字节,“音频/x-wav”);
}
});
返回等待任务;
}

我打赌您还需要在IIS中添加音频/wav MIME类型。

这只是我的想法,还没有经过测试,但您可能可以执行以下操作:

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");
}

我以前在服务器2012R2上有过这样的经验(不是synth api,而是相同的问题)。我通过在所有任务上使用“wait task.configurewait(false)”修复了它。看看这对你是否有效


祝您好运。

您可以找到类似问题的解决方案-在新安装的Windows 8.1上使用SpeechSynthesizer时除外。这种情况下的问题是CurrentUserLexicon用户的权限条目错误(由SpeechSynthesizer使用)。为了解决这个问题,本文建议删除权限条目“所有应用程序包”从Software\Microsoft\Speech\CurrentUserLexicon注册表项。

我发现我可以在其他服务器上重现该问题,包括Azure VM,因此我排除了特定环境出现问题的可能性

此外,我发现,如果我在服务器上以管理员身份运行应用程序池,并且之前已登录到服务器,那么我可以在2012 R2上使代码正常工作。经过一个很长的排除权限问题的过程后,我决定一定是登录过程中出现了启用TTS API调用的某种情况正确工作。(无论是什么,我都无法通过procmon跟踪找到它)。因此幸运的是,ApplicationPoolIdentity可以通过在IIS中打开应用程序池的“高级设置”并将
加载用户配置文件
设置为
True
来应用类似的登录魔法

运行应用程序池的标识还需要获得读取
HKU\.Default\Software\Microsoft\Speech
的权限,该权限可通过使用本地服务器作为位置授予ApplicationPoolIdentity,并使用
IIS APPPOOL\.Net v4.5
作为用户名(其中
.Net v4.5
是应用程序池的名称)


一旦授予对注册表项的读取权限,并且将应用程序池配置为加载用户配置文件,上述代码就可以正常工作。在Azure VMs和MSDN ISOs的vanilla 2012 R2上进行了测试。

不幸的是,这不会改变2012 R2的行为。不,在IIS中已经配置了wav MIME类型。但这些类型仍然是用于静态文件。因此我SAPI筛选器可能需要正确配置?不,不是ISAPI筛选器。哦,我只是想到了一些东西。确保在构建要放到2012 R2服务器上的工件时,确保系统。语音引用设置为“始终复制”(如果尚未设置)。然后(应该在之前考虑到这一点)在任务主体周围放置一个try catch,看看它是否抛出(如果尚未抛出)。您是否尝试将其作为同步操作方法,而不将其包装到任务中?该代码中的线程池可能存在ASP.NET不知道的问题。@DmitryS。我不确定我是否可以进行类似的测试…如果
synth.Speak
不起作用t wrapped,我得到一个运行时异常:
invalidoOperationException
(此时无法启动异步操作)。我喜欢这种思路,但如果它是ASP.NET的线程池问题,为什么它会在这么多其他服务器上工作?合成器的最新版本有
SpeakAsync()
method。不用将代码包装在
Task.Run()
中,您只需执行
wait-SpeakAsync(text)
。可能我在这里遗漏了什么-
SpeakAsync()
方法不返回任务,因此无法等待它。(它返回
提示符
对象).您是否尝试过这里的建议:?我知道这是关于异常和非挂起,但仍然可能相关。谢谢您,但不幸的是,不,这无助于解决此特定问题。老兄,您是一个英雄
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;
}
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");
}