Search code examples
xmlurltwiliotwilio-twimlgoogle-text-to-speech

How to integrate Google Text-To-Speech in Twilio (or URL with '&' in XML tag)


I want to use Google Text-To-Speech service in Twilio.

I have generated URL with several parameters, separated with ampersands(&).
For Example: http://translate.google.com/translate_tts?ie=UTF-8&q=Hello%20World&tl=en-us

The problem is: when I try to put this URL in TwiML tag, I have exception that written below:

Error on line 1 of document : The reference to entity "q" must end with the ';' delimiter. Please ensure that the response body is a valid XML document.

This is TwiML:

<Response>
    <Play>http://translate.google.com/translate_tts?ie=UTF-8&q=Hello%20World&tl=en-us</Play>
</Response>

Solutions, that I already tried:

1) Replace & with &amp;
It not helped for me. I this case I got another exception: returned the HTTP status code 404. Look like Twilio don't decode &amp; back to &.

2) Save Google output to file on server and put direct link to this file (without any &) to tag. It should work, but it look like dirty hack =)


Solution

  • Ok, I solved this problem on third way:

    I made "proxy" servlet for hiding all of parameters, that needed for google TTS Engine, inside this servlet. It's more easy to demonstrate in code:

    I put URL to my proxy servlet (instead URL to Google TTS Engine) to TwiML. For this servlet required only one parameter: message that will play. In this case I avoid ampersand symbol in TwiML.

    ...
    String url = Constants.APPLICATION_URL + "/tts/" +"?" + Constants.ParamName.GREETINGS + "=" + greetings;
    Play play = new Play(url);
    ...
    

    This is proxy servlet (it mapped to /tts/ path). make request to Google TTS Engine and send back response from it:

    ...
    this.greetings = request.getParameter(Constants.ParamName.GREETINGS);
    InputStream input = null;
    HttpURLConnection con = null;
    OutputStream output = null;
    try {
        URL obj = new URL("http://translate.google.com/translate_tts?ie=UTF-8&q=" + URLEncoder.encode(greetings, "UTF-8") + "&tl=en-us"));
        con = (HttpURLConnection) obj.openConnection();
        con.setConnectTimeout(5000);
        con.setRequestMethod("GET");
        con.setRequestProperty("User-Agent", "Mozilla/5.0");
        con.setRequestProperty("Content-Type", "audio/mpeg");
        input = con.getInputStream();
        response.setContentType("audio/mpeg");
        output = response.getOutputStream();
        byte[] buffer = new byte[10240];
        for (int length = 0; (length = input.read(buffer)) > 0;) {
            output.write(buffer, 0, length);
        }
    }
    ...
    

    Of course, this is look like a dirty hack, but I think it is better, than save temporary file on server.