cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
4712
Views
10
Helpful
17
Comments
Gergely Szabo
VIP Alumni
VIP Alumni

This document was inspired by this thread.

Problem: UCCX needs to send a recording using the Hypertext Transfer Protocol (HTTP), which is not always suitable for binary data (like a recording).

Analysis: The Base64 encoding algorithm is an excellent method of transforming binary objects into ASCII characters that may be safely transmitted over a text-based protocol like HTTP.

Disclaimer: * * * The usual blah-blah. I am not responsible for anything. UCCX Premium or IP IVR license only (custom Java used). Tested with UCCX Premium 7.0(1)_Build168. * * *

Solution:

1. Download the Apache Commons Codec library. N.B.: there are separate versions of Commons Codec for different Java versions, so this might be the right time to look up the Java version of your UCCX server. Use the compatibility matrix - or, alternatively, use Recipe #2 from this document. In this example, I use UCCX 7.0, this means Java 5 is I need to work with, so I downloaded Commons Codec 1.6).

2. Unzip/Untar-gz the package, and upload the commons-codec-1.x.jar file to UCCX's classpath, and select it on the "Custom File Configuration" page.

3. Reload the server. Or reboot it. Yes, it's really necessary. No, it won't work without this.

4. Create a new script, using the UCCX Script editor.

5. Insert the following variables:

base64encodedRecording - type String - inital value: ""

recording - type Document - initial value: DOC[]

serverResponse - type Document - initial value: DOC[]

url - type String - the URL of the target application, we will send the Base64 encoded recording to here.

6. Insert all the necessary steps to the script (for instance, Accept, Play Prompt, etc).

7. Insert a Recording step. The result document would be the recording variable.

8. Add a Set node to the Successful branch of the Recording step. The result would be the variable named base64encodedRecording. Insert the following code block:

{

java.io.InputStream is = new org.apache.commons.codec.binary.Base64InputStream(recording.getInputStream(),true);

byte[] b = new byte[1024]; // change it to a higher value if it's too slow

StringBuffer buf = new StringBuffer();

int bytesRead = 0;

while ((bytesRead = is.read(b,0,b.length)) != -1) {buf.append(new String(b,0,bytesRead)); }

return buf.toString();

}

As we can see, I got the InputStream object of the recording document, and wrapped it into another InputStream, more precisely, with a Base64InputStream (by specifying true - see the second parameter) I asked it to encode everything I read from the source InputStream, using the Base64 algorithm. Then I just read chunks of bytes out of it - 1024 bytes long chunks - and appending them into a StringBuffer, which then I hand over at the last line, transformed into a String.

9. The next two steps are easy: with a Create URL Document step, with the URL pointing to the HTTP application which, the HTTP method would be POST, and the parameter, in this example named "base64encodedRecording" holds the value of the variable named base64encodedRecording (the last setting, the Document is not used in this example, I used a dummy variable named ServerResponse). Then, using the Cache Document step, the script actually issues the HTTP request.

Testing:

I created a simple Grails application "Base64Recording", with one controller "TakeAndSaveController" with one method, "index" (this is why, in my script the value of the url variable is "http://192.168.11.37:8080/Base64Recording/takeAndSave/index":

package base64encodecprompt

class TakeAndSaveController {

    def index() {

        def encoded = params.base64encodedRecording.replaceAll("\r|\n", "").trim()

        def decoded = encoded.decodeBase64()

        new File("/tmp/recording.wav").withOutputStream {

            it.write(decoded)

        }

    }

}

Here's a screenshot:

screenshot1.png

What happens here: I take the parameter named "base64encodedRecording" (out of the params object), while replacing all the newline characters (\n, \r) and trimming the leading and trailing whitespaces (just to be on the safe side) - this yields the encoded variable.

Then, I decode the binary object, by calling the decodeBase64() method on encoded - resulting decoded.

Finally, I create a file named /tmp/recording.wav, and with its OutputStream I just write the binary object into it.

I created an application, then a trigger, called in, after the prompt I created a recording, and in a couple of moments, a file named /tmp/recording.wav appeared on my computer, created by the Grails application.

There are several things to be aware of:

- While encoding the binary stream into Base64 text, line separators (by default, CRLF) are added, after the 76th character. There's nothing wrong with it, but the receiving application may need to remove these extra characters (this is what I did by calling the replaceAll method in my Grails controller).

- Base64 will introduce overhead, making the encoded string longer by 33% of the original string. This may be taken into account when sending large recordings.

Screenshot of the whole UCCX script, for inspiration:

screenshot2.png

Enjoy.

G.

Comments
Gergely Szabo
VIP Alumni
VIP Alumni

OK, I am installing a 9.0 UCCX to test this. I hope I can replicate this problem there. G.

Clifford McGlamry
Spotlight
Spotlight

I'm not sure if this thread is still active....BUT.

 

I need to do the exact reverse of this.  I'm getting a prompt via HTTP that is a base 64 encoded WAV file, and I need to unpack it.  I cannot seem to figure out the correct way to do this (I can do it in C#, but not in Java).  The obvious Java methods are not decoding the entire thing.

If anyone has any ideas, my head is getting bruised from banging it against the wall here...

Getting Started

Find answers to your questions by entering keywords or phrases in the Search bar above. New here? Use these resources to familiarize yourself with the community: