2

WebAPIを使用して簡単なWebサービスをセットアップしようとしています。これが私がコードのために持っているものです:

public class SpeakController : ApiController
    {
        //
        // api/speak

        public HttpResponseMessage Get(String textToConvert, String outputFile, string gender, string age = "Adult")
        {
            VoiceGender voiceGender = (VoiceGender)Enum.Parse(typeof(VoiceGender), gender);
            VoiceAge voiceAge = (VoiceAge)Enum.Parse(typeof(VoiceAge), age);

            using (SpeechSynthesizer synthesizer = new SpeechSynthesizer())
            {
                synthesizer.SelectVoiceByHints(voiceGender, voiceAge);
                synthesizer.SetOutputToWaveFile(outputFile, new SpeechAudioFormatInfo(8000, AudioBitsPerSample.Sixteen, AudioChannel.Mono));
                synthesizer.Speak(textToConvert);
            }

            return Request.CreateResponse(HttpStatusCode.OK, new Response { HttpStatusCode = (int)HttpStatusCode.OK, Message = "Payload Accepted." });
        }
    }

コードはかなり単純で、本番環境に対応しているわけではありません。しかし、私のテストでは、コントローラーへの要求に対して次のことが発生することに気づきました。

  • WAVファイルが正常に生成されます
  • デバッグ中に、コントロールヒットが戻ってメソッドを終了するのを確認できます
  • ただし、ブラウザが回転し続け、サーバーから応答が返ってこない

Postman(Chrome用のRESTクライアント)でも同じことを試しましたが、同じ結果が得られました。私はこれをブロッキングコールにしたいのですが、他のことを試すために、変更synthesizer.Speaksynthesizer.SpeakAsyncて同じ問題が発生しました。

ただし、以下に示すようにスニペットを個別にテストすると、コードは期待どおりに機能します。

コメントアウトされた音声セクションを使用したWebAPI呼び出しのテスト:

public class SpeakController : ApiController
{
    //
    // api/speak

    public HttpResponseMessage Get(String textToConvert, String outputFile, string gender, string age = "Adult")
    {
        VoiceGender voiceGender = (VoiceGender)Enum.Parse(typeof(VoiceGender), gender);
        VoiceAge voiceAge = (VoiceAge)Enum.Parse(typeof(VoiceAge), age);

        //using (SpeechSynthesizer synthesizer = new SpeechSynthesizer())
        //{
        //  synthesizer.SelectVoiceByHints(voiceGender, voiceAge);
        //  synthesizer.SetOutputToWaveFile(outputFile, new SpeechAudioFormatInfo(8000, AudioBitsPerSample.Sixteen, AudioChannel.Mono));
        //  synthesizer.Speak(textToConvert);
        //}

        return Request.CreateResponse(HttpStatusCode.OK, new Response { HttpStatusCode = (int)HttpStatusCode.OK, Message = "Payload Accepted." });
    }
}

コンソールアプリケーションで音声を個別にテストする:

static string usageInfo = "Invalid or no input arguments!"
    + "\n\nUsage: initiatives \"text to speak\" c:\\path\\to\\generate.wav gender"
    + "\nGender:\n\tMale or \n\tFemale"
    + "\n";

static void Main(string[] args)
{
    if (args.Length != 3)
    {
        Console.WriteLine(usageInfo);
    }
    else
    {
        ConvertStringToSpeechWav(args[0], args[1], (VoiceGender)Enum.Parse(typeof(VoiceGender), args[2]));
    }

    Console.WriteLine("Press any key to continue...");
    Console.ReadLine();
}

static void ConvertStringToSpeechWav(String textToConvert, String pathToCreateWavFile, VoiceGender gender, VoiceAge age = VoiceAge.Adult)
{
    using (SpeechSynthesizer synthesizer = new SpeechSynthesizer())
    {
        synthesizer.SelectVoiceByHints(gender, age);
        synthesizer.SetOutputToWaveFile(pathToCreateWavFile, new SpeechAudioFormatInfo(8000, AudioBitsPerSample.Sixteen, AudioChannel.Mono));
        synthesizer.Speak(textToConvert);
    }
}

WebAPIとSpeechSynthesisは一緒にうまく機能していないようです。これを理解するのに助けていただければ幸いです。

ありがとう!

4

1 に答える 1

1

なぜこれが発生するのかわかりませんが、SpeechSynthesizerを別のスレッドで実行するとうまくいくようです(互換性のないスレッドモデル?)。これが私が過去にそれをした方法です。

に基づく:ASP.NET MVCの超高速テキスト読み上げ(WAV-> MP3)

public dynamic Post(dynamic req)
{
    try 
    {
        string phrase = req["phrase"].Value;

        var stream = new MemoryStream();
        var t = new System.Threading.Thread(() =>
            {
                using (var synth = new SpeechSynthesizer())
                {
                    synth.SetOutputToWaveStream(stream);
                    synth.Speak(phrase);
                    synth.SetOutputToNull();
                }
            });

        t.Start();
        t.Join();

        stream.Position = 0;

        var resp = new HttpResponseMessage(HttpStatusCode.OK);
        resp.Content = new StreamContent(stream);

        resp.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
        resp.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
        resp.Content.Headers.ContentDisposition.FileName = "phrase.wav";

        return resp;
    }
    catch
    {
        return new HttpResponseMessage(HttpStatusCode.InternalServerError);
    }
}
于 2013-11-18T23:19:19.680 に答える