iristk.speech.nuancecloud.NuanceCloudSynthesizer.java Source code

Java tutorial

Introduction

Here is the source code for iristk.speech.nuancecloud.NuanceCloudSynthesizer.java

Source

/*
 * TTSHTTPClient.java
 *
 * This is a simple command-line java app that shows how to use the NMDP HTTP Client Interface for
 *   Text-to-Speech (TTS) requests using the POST method
 *
 * This basic java app will:
 *   1. Create an instance of an HttpClient to interact with our HTTP Client Interface for TTS
 *   2. Use some simple helper methods to setup the URI and HTTP POST parameters
 *   3. Execute the HTTP Request
 *   4. Process the HTTP Response, writing the generated audio to file
 *
 *   Output of progress of the request is logged to console
 *   Values to be passed to the HTTP Client Interface are simply hard-coded class members for demo purposes
 *
 * @copyright  Copyright (c) 2010 Nuance Communications, inc. (http://www.nuance.com)
 *
 * @Created   : April 28, 2011
 * @Author   : Peter Freshman
 */
package iristk.speech.nuancecloud;

import iristk.audio.Sound;
import iristk.speech.Synthesizer;
import iristk.speech.SynthesizerEngine;
import iristk.speech.Transcription;
import iristk.speech.Voice;
import iristk.speech.Voice.Gender;
import iristk.speech.VoiceList;
import iristk.system.InitializationException;
import iristk.util.Language;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.sound.sampled.AudioFormat;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIUtils;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;

public class NuanceCloudSynthesizer implements Synthesizer {

    private String DEVICE_ID = "0000";
    private String CODEC = "audio/x-wav;codec=pcm;bit=16;rate=16000";
    private String APP_ID;
    private String APP_KEY;
    private static short PORT = (short) 443;
    private static String HOSTNAME = "tts.nuancemobility.net";
    private static String TTS = "/NMDPTTSCmdServlet/tts";

    private HttpClient httpclient = null;
    private AudioFormat audioFormat = new AudioFormat(16000, 16, 1, true, false);
    private VoiceList voices = new VoiceList();

    public NuanceCloudSynthesizer() throws Exception {
        Properties properties = new Properties();
        properties.load(new FileReader(NuanceCloudPackage.PACKAGE.getPath("license.properties")));
        this.APP_ID = properties.getProperty("APP_ID");
        this.APP_KEY = properties.getProperty("APP_KEY");
        httpclient = getHttpClient();
        voices.add(new Voice(this, "Samantha", Gender.FEMALE, Language.ENGLISH_US, false));
        voices.add(new Voice(this, "Tom", Gender.MALE, Language.ENGLISH_US, false));
        voices.add(new Voice(this, "Allison", Gender.FEMALE, Language.ENGLISH_US, false));
        voices.add(new Voice(this, "Ava", Gender.FEMALE, Language.ENGLISH_US, false));
        voices.add(new Voice(this, "Susan", Gender.FEMALE, Language.ENGLISH_US, false));
        voices.add(new Voice(this, "Zoe", Gender.FEMALE, Language.ENGLISH_US, false));
        voices.add(new Voice(this, "Alva", Gender.FEMALE, Language.SWEDISH, false));
        voices.add(new Voice(this, "Oskar", Gender.MALE, Language.SWEDISH, false));
    }

    @Override
    public SynthesizerEngine getEngine(Voice voice) throws InitializationException {
        return new NuanceCloudSynthesizerEngine(voice);
    }

    @Override
    public VoiceList getVoices() {
        return voices;
    }

    @Override
    public String getName() {
        return "Nuance Cloud";
    }

    /*
     * This function will initialize httpclient, set some basic HTTP parameters (version, UTF),
     *   and setup SSL settings for communication between the httpclient and our Nuance servers
     */
    private HttpClient getHttpClient() throws NoSuchAlgorithmException, KeyManagementException {
        // Standard HTTP parameters
        HttpParams params = new BasicHttpParams();
        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
        HttpProtocolParams.setContentCharset(params, "UTF-8");
        HttpProtocolParams.setUseExpectContinue(params, false);

        // Initialize the HTTP client
        httpclient = new DefaultHttpClient(params);

        // Initialize/setup SSL
        TrustManager easyTrustManager = new X509TrustManager() {
            @Override
            public void checkClientTrusted(java.security.cert.X509Certificate[] arg0, String arg1)
                    throws java.security.cert.CertificateException {
                // TODO Auto-generated method stub
            }

            @Override
            public void checkServerTrusted(java.security.cert.X509Certificate[] arg0, String arg1)
                    throws java.security.cert.CertificateException {
                // TODO Auto-generated method stub
            }

            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                // TODO Auto-generated method stub
                return null;
            }
        };

        SSLContext sslcontext = SSLContext.getInstance("TLS");
        sslcontext.init(null, new TrustManager[] { easyTrustManager }, null);
        SSLSocketFactory sf = new SSLSocketFactory(sslcontext);
        sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
        Scheme sch = new Scheme("https", sf, PORT); // PORT = 443
        httpclient.getConnectionManager().getSchemeRegistry().register(sch);

        // Return the initialized instance of our httpclient
        return httpclient;
    }

    private class NuanceCloudSynthesizerEngine implements SynthesizerEngine {

        private Voice voice;

        NuanceCloudSynthesizerEngine(Voice voice) {
            this.voice = voice;
        }

        @Override
        public Transcription synthesize(String text, File file) {
            try {
                HttpPost httppost = getHeader(text);
                //System.out.println("executing request " + httppost.getRequestLine());
                HttpResponse response = httpclient.execute(httppost);
                processResponse(response, file);
            } catch (ClientProtocolException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return new Transcription();
        }

        @Override
        public Transcription transcribe(String text) {
            return new Transcription();
        }

        @Override
        public AudioFormat getAudioFormat() {
            return audioFormat;
        }

        @Override
        public Voice getVoice() {
            return voice;
        }

        /*
         * This is a simpler helper function to setup the Header parameters
         */
        private HttpPost getHeader(String text) throws URISyntaxException, UnsupportedEncodingException {
            List<NameValuePair> qparams = new ArrayList<NameValuePair>();

            qparams.add(new BasicNameValuePair("appId", APP_ID));
            qparams.add(new BasicNameValuePair("appKey", APP_KEY));
            qparams.add(new BasicNameValuePair("id", DEVICE_ID));
            qparams.add(new BasicNameValuePair("voice", voice.getName()));
            qparams.add(new BasicNameValuePair("ttsLang", voice.getLanguage().getCode().replace("-", "_")));

            URI uri = URIUtils.createURI("https", HOSTNAME, PORT, TTS, URLEncodedUtils.format(qparams, "UTF-8"),
                    null);

            HttpPost httppost = new HttpPost(uri);
            httppost.addHeader("Content-Type", "text/plain");
            httppost.addHeader("Accept", CODEC);

            // We'll also set the content of the POST request now...
            HttpEntity entity = new StringEntity(text, "iso-8859-1");
            httppost.setEntity(entity);

            return httppost;
        }

        /*
         * This function will take the HTTP response and parse out header values, write the audio that's been returned
         *   to filed, and log details to the console
         */
        private void processResponse(HttpResponse response, File outFile)
                throws IllegalStateException, IOException {
            HttpEntity resEntity = response.getEntity();

            //System.out.println("----------------------------------------");
            //System.out.println(response.getStatusLine());

            // The request failed. Check out the status line to see what the problem is.
            //   Typically an issue with one of the parameters passed in...
            if (resEntity == null)
                return;

            // Grab the date
            Header date = response.getFirstHeader("Date");
            //if( date != null )
            //   System.out.println("Date: " + date.getValue());

            // ALWAYS grab the Nuance-generated session id. Makes it a WHOLE LOT EASIER for us to hunt down your issues in our logs
            Header sessionid = response.getFirstHeader("x-nuance-sessionid");
            //if( sessionid != null )
            //   System.out.println("x-nuance-sessionid: " + sessionid.getValue());

            // Check to see if we have a 200 OK response. Otherwise, review the technical documentation to understand why you recieved
            //   the HTTP error code that came back
            //String status = response.getStatusLine().toString();
            //boolean okFound = ( status.indexOf("200 OK") > -1 );
            //if( okFound )
            //{
            //   System.out.println("Response content length: " + resEntity.getContentLength());
            //   System.out.println("Chunked?: " + resEntity.isChunked());
            //}

            // Grab the returned audio (or error message) returned in the body of the response
            InputStream in = resEntity.getContent();
            byte[] buffer = new byte[1024 * 16];
            int len;

            ByteArrayOutputStream bout = new ByteArrayOutputStream();

            // Attempt to write to file...
            try {
                while ((len = in.read(buffer)) > 0) {
                    bout.write(buffer, 0, len);
                }

                Sound s = new Sound(bout.toByteArray(), getAudioFormat());
                s.save(outFile);
            } catch (Exception e) {
                System.err.println("Failed to save file: " + e.getMessage());
                e.printStackTrace();
            }

            //System.out.println("----------------------------------------");

            // And we're done.
            resEntity.consumeContent();
        }

    }

}