Controllare il Text-To-Speech da un’applicazione client (Italiano)

Inviato da Marco Minerva

Qualche tempo fa ho presentato la mia libreria che permette di aggiungere funzionalità di Text-To-Speech in un’applicazione .NET Gadgeteer. In tale occasione, abbiamo visto un esempio in cui il testo da riprodurre era incluso direttamente nell’applicazione.

Ma possiamo fare qualcosa di più interessante. Sfruttando il supporto al networking incluso nella piattaforma .NET Gadgeteer, è semplice creare un servizio che gira sul device e aspetta comandi di text-to-speech provenienti da un client esterno: in altre parole, noi inviamo una stringa con il testo e il device lo riproduce.

Vediamo come creare questo sistema. Useremo una scheda FEZ Spider, a cui collegheremo i moduli Ethernet e Music. Nel metodo ProgramStarted, inseriamo il solito codice per l’inizializzazione:

ethernet.NetworkUp += new GTM.Module.NetworkModule.NetworkEventHandler(ethernet_NetworkUp);
ethernet.NetworkDown += new GTM.Module.NetworkModule.NetworkEventHandler(ethernet_NetworkDown);
ethernet.UseDHCP();

music.MusicFinished += (m) => { };

speech = new SpeechSynthesizer(BING_APPID);
speech.GetSpeakBytesCompleted += 
                    new SpeechSynthesizer.GetSpeakBytesEventHandler(speech_GetSpeakBytesCompleted);

Notiamo che abbiamo creato un gestore per l’evento MusicFinished, anche se non facciamo niente al suo interno. Questo accorgimento è necessario perché, con la versione corrente del driver per il Music Module, se non inseriamo esplicitamente un gestore per questo evento, l’applicazione andrà in errore al termine della riproduzione.

Nelle ultime due linee, creiamo un’istanza della classe SpeechSynthesizer della mia libreria per il Text-To-Speech. Stiamo usando una vecchia versione che richiede ancora un Bing Application ID perché la nuova release effettua richieste SSL che non sono ancora supportate da .NET Gadgeteer. Potete trovare questa versione della libreria nel codice sorgente allegato a questo post.

Nell’evento NetworkUp creiamo il servizio e avviamo il Web Server del device sulla porta 80:

private void ethernet_NetworkUp(GTM.Module.NetworkModule sender, 
                                                         GTM.Module.NetworkModule.NetworkState state)
{
    Debug.Print("Network up: " + ethernet.NetworkSettings.IPAddress);

    var webEvent = WebServer.SetupWebEvent("speech");
    webEvent.WebEventReceived += new WebEvent.ReceivedWebEventHandler(webEvent_WebEventReceived);
    WebServer.StartLocalServer(ethernet.NetworkSettings.IPAddress, 80);
}

Con questo codice, il device avvia un Web Server in ascolto sulla porta 80, in grado di rispondere a richieste GET sulla risorsa speech, ovvero nella forma http://device_ip/speech. Queste richieste sono gestite nell’handler webEvent_WebEventReceived:

private void webEvent_WebEventReceived(string path, WebServer.HttpMethod method, Responder responder)
{
    string text = responder.GetParameterValueFromURL("text");
    string language = responder.GetParameterValueFromURL("language");

    if (text != null && text.Trim().Length > 0 && language != null && language.Trim().Length > 0)
    {
        // Makes the request for speak bytes.
        speech.GetSpeakBytesAsync(text, language);
    }

    responder.Respond("OK");
}

private void speech_GetSpeakBytesCompleted(object sender, GetSpeakBytesEventArgs e)
{
    if (e.Error == null)
        music.Play(e.Data);
    else
        Debug.Print(e.Error.Message);
}

Recuperiamo i parametri text e language dal Query string e, se sono corretti, effettuiamo una richiesta asincrona alla libreria per il Text-To-Speech. Al suo completamento, nel gestore dell’evento GetSpeakBytesCompleted riproduciamo il parlato usando Music module.

Questo è tutto. Quando l’applicazione viene avviata e la connessione alla rete è disponibile, l’indirizzo IP del device viene mostrato nella finestra Output di Visual Studio. Possiamo fare richieste usando un normale web browser, usando il seguente formato:

http://device_ip/speech?text=%5Byour_text%5D&language=%5Btext_language%5D

Ad esempio:

http://192.168.0.123/speech?text=Test&language=en

In alternativa, possiamo usare l’applicazione console Remote Speech Client inclusa nell’esempio che accompagna questo post. Essa è interessante perché mostra come inviare richieste al device da una qualsiasi applicazione .NET.

In conclusione, questo è il codice completo del file Program.cs della nostra applicazione .NET Gadgeteer.

public partial class Program
{
    private const string BING_APPID = "";
    private SpeechSynthesizer speech;

    // This method is run when the mainboard is powered up or reset.
    void ProgramStarted()
    {
        ethernet.NetworkUp += new GTM.Module.NetworkModule.NetworkEventHandler(ethernet_NetworkUp);
        ethernet.NetworkDown += new GTM.Module.NetworkModule.NetworkEventHandler(ethernet_NetworkDown);
        ethernet.UseDHCP();

        music.MusicFinished += (m) => { };

        speech = new SpeechSynthesizer(BING_APPID);
        speech.GetSpeakBytesCompleted += 
                        new SpeechSynthesizer.GetSpeakBytesEventHandler(speech_GetSpeakBytesCompleted);

        // Use Debug.Print to show messages in Visual Studio's "Output" window during debugging.
        Debug.Print("Program Started");
    }

    private void ethernet_NetworkDown(GTM.Module.NetworkModule sender, 
                                                        GTM.Module.NetworkModule.NetworkState state)
    {
        Debug.Print("Network down!");
    }

    private void ethernet_NetworkUp(GTM.Module.NetworkModule sender, 
                                                      GTM.Module.NetworkModule.NetworkState state)
    {
        Debug.Print("Network up: " + ethernet.NetworkSettings.IPAddress);

        var webEvent = WebServer.SetupWebEvent("speech");
        webEvent.WebEventReceived += new WebEvent.ReceivedWebEventHandler(webEvent_WebEventReceived);
        WebServer.StartLocalServer(ethernet.NetworkSettings.IPAddress, 80);
    }

    private void webEvent_WebEventReceived(string path, WebServer.HttpMethod method, Responder responder)
    {
        string text = responder.GetParameterValueFromURL("text");
        string language = responder.GetParameterValueFromURL("language");

        if (text != null && text.Trim().Length > 0 && language != null && language.Trim().Length > 0)
        {
            // Makes the request for speak bytes.
            speech.GetSpeakBytesAsync(text, language);
        }

        responder.Respond("OK");
    }

    private void speech_GetSpeakBytesCompleted(object sender, GetSpeakBytesEventArgs e)
    {
        if (e.Error == null)
            music.Play(e.Data);
        else
            Debug.Print(e.Error.Message);
    }
}

L’applicazione completa è disponibile per il download.

RemoteSpeech.zip

Advertisements

  1. Leave a comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: