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

Problem:

It's a common requirement to play prompts that are saved as wave files on a Windows share. Starting UCCX 8.x the platform is Linux-based, thus there's no possibility to "mount" Windows shares easily.

A user might want to save prompts recorded by UCCX on to a Windows share.

Analysis:

UCCX must be enabled to communicate using the CIFS/SMB protocol. Also, the file should be cached in order to eliminate delays.

Solution:

**** DISCLAIMER: This is a proof of concept. I did not check whether the LGPL license of the JCIFS library is compatible with UCCX. USE THIS AT YOUR OWN RISK. I am not responsible for any damage this solution may cause. I cannot guarrantee this would work with your installation of UCCX. Tested with IP IVR System version: 8.0.2.11004-12. ****

I. reading a prompt from a Windows share

1. Download the JCIFS library, available at http://jcifs.samba.org/ (click the Download link, then download a recent file, for instance, jcifs-1.3.17.jar

2. Upload this JAR file to UCCX, using the System > Custom File Configuration. After uploading, make sure to select the file as a "Selected Classpath Entries":

uccx_classpath.PNG

3. Restart the CCX engine.

4. Make sure you've got set up the following: the file is saved using a correct codec and format (check System > System Parameters Configuration, look for the Media Parameters section); also, the file must be available in a Windows share (default shares - like c$ - might not work); and of course, you need to have a user and a password.

5. Create a UCCX script. Add all the variables steps you need (for instance, Accept, etc).

6. Add a new variable, of type java.io.ByteArrayInputStream. Name it byteArrayIS (for instance).

7. Add a new variable, of type String. Name it smbFileURL (for instance).

8. Add a new Set step. The result wariable would be smbFileURL. For the value, use the following format:

smb://domain;user:password@ipaddress/share/file.wav

For example:

smb://ipcc;filereader:SuperS3crEt!@10.232.128.68/Temp/friday.wav

This means: ipcc\filereader user with password SuperS3crEt! may read the contents of the file friday.wav on the server 10.232.128.68 within the Temp share.

For more possibilities of this URL, take a look at the JCIFS documentation at http://jcifs.samba.org/src/docs/api/jcifs/smb/SmbFile.html (scroll down to SMB URL Examples).

8. Add a new Set step. The result variable would be byteArrayIS. As for the value, paste in the following closure:

{

int bufSize = 4096; // buffer size, bytes

java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();

try {

    jcifs.smb.SmbFile smbFile = new jcifs.smb.SmbFile(smbFileURL);

    java.io.InputStream in = smbFile.getInputStream();

    byte[] bytesRead = new byte[bufSize];

    int bytesReadLength = 0;

    while(( bytesReadLength = in.read( bytesRead )) > 0 ) {

        baos.write(bytesRead,0,bytesReadLength);

    } //while

    in.close();

    baos.close();

} catch (Exception e) {

return null;

} //try..catch

return new java.io.ByteArrayInputStream(baos.toByteArray());

}

(for more information how this works, look at the end of this section).

9. Add a new Play Prompt step. Use the following value on the Prompt tab:

(Prompt) byteArrayIS

10. Test it. You should be able to hear the contents of the file prompt.

Screenshot:

uccx_smbfilemagic.PNG

(Click the image above to enlarge it).

What just happened?

The closure above dissected:

int bufSize = 4096; // buffer size, bytes

We define the read buffer size. 4096 bytes, in other words, 4 kilobytes seems to be alright, you can modify this to 8KB or 16KB if the file reads slowly.

java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();

Just a ByteArrayOutputStream to hold the prompt contents.

The following try..catch block contains:

jcifs.smb.SmbFile smbFile = new jcifs.smb.SmbFile(smbFileURL);

A new File (or more precisely, a SmbFile) object is constructed, with one parameter: smbFileURL.

Of course, you can do something more with it, for instance, check whether the file exists. Again, take a look at the JCIFS API docs.

java.io.InputStream in = smbFile.getInputStream();

This is where we access the InputStream of the above SmbFile.

byte[] bytesRead = new byte[bufSize];

A byte array, for buffering the file contents. The buffer size is defined in the bufSize local variable.

int bytesReadLength = 0;

Another local variable, for checking how many bytes have been read from the InputStream of the SmbFile object.

And then the only thing we need to do is just read the bytes from the InputStream (in chunks, to give it some speed), and copy these bytes to the ByteArrayOutputStream:

while (( bytesReadLength = in.read( bytesRead )) > 0 ) {

     baos.write(bytesRead,0,bytesReadLength);

} //while

Of course, it's always good to close the resources:

in.close();

baos.close();

The catch block will return null (in case something goes wrong), but you can also include something more useful.

return null;

But if everything goes perfect, we can return a ByteArrayInputStream (by flipping the ByteArrayOutputStream above):

return new java.io.ByteArrayInputStream(baos.toByteArray());

The Play Prompt step (and every prompt-related step) can work perfectly with InputStreams, including ByteArrayInputStreams, the only thing to remember is to cast them to type Prompt. It's easy:

(Prompt) byteArrayIS

So again, we create an InputStream out of the file (which is accessible thanks to the JCIFS library), read the contents of the file in chunks, write these chunks to an OutputStream, finally, we just take the bytearray of this OutputStream, creating an InputStream, which we can hand over to the Play Prompt step.

II. writing a prompt to a Windows share

First, install the JCIFS library, by following the steps 1 to 3 (including) of the previous section (I. reading a prompt from a Windows share).

1. Add these new variables:

  • exitCode, type int, initial value = 0;
  • mydoc, type Document, initial value null;
  • smbFileURL, type String; initial value = "";

2. Create a new script, add all the necessary steps, for example, Accept.

3. Add a new Set step. Assign the value of the smbFileURL variable, following this format:

smb://domain;user:password@ipaddress/share/file.wav

For example:

smb://ipcc;filereader:SuperS3crEt!@10.232.128.68/Temp/friday.wav

This  means: ipcc\filereader user with password SuperS3crEt! may read the  contents of the file friday.wav on the server 10.232.128.68 within the  Temp share.

For more possibilities, please read the JCIFS API docs, at  http://jcifs.samba.org/src/docs/api/jcifs/smb/SmbFile.html (scroll down to SMB URL Examples).

4. Add a new Recording step, that would yield the value of the mydoc variable. Use a prompt of your choice (may be something like "please record your message" etc)

5. Add a new Set step to the Successful recording branch of the previous (Recording) step. Use the variable exitCode. The value would be this closure:

{

java.io.OutputStream os = null;

java.io.InputStream in = null;

try {

int bufSize = 4096;

jcifs.smb.SmbFile smbFile = new jcifs.smb.SmbFile(smbFileURL);

os = smbFile.getOutputStream();

in  = mydoc.getInputStream();

byte[] bytesRead = new byte[bufSize];

int bytesReadLength = 0;

while ((bytesReadLength = in.read(bytesRead)) > 0 ) {

    os.write(bytesRead,0,bytesReadLength);

}

} catch (Exception e) {

return -1;

} finally {

in.close();

os.close();

return 0;

}

}

6. Save your script and test it. A new file, specified in the smbFileURL variable should be created within the Windows share, with the preferred format of UCCX (either G.711 uLaw or G.729 depending on the settings of your UCCX system).

Notice: the value of the exitCode variable will be -1 if, for any reason, an error happens during writing the prompt file. If it is written successfully, the value of the exitCode variable is 0.

Screenshot:

uccx_smbfilemagic_write.PNG

What just happened?

The Recording step created a new recording of type Document. This is just plain ordinary Java object, which is actually a string, or rather, a stream of bytes that equals to the prompt file contents. All we need to do is just create an inputstream of this object, and copy the contents of it to another stream, namely a FileOutputStream of the SMB File we create. The closure also has got an exception catching mechanism, if any exception is raised, it would give back the control to the script with the value -1 of the exitCode variable so you can react on it (instead of just having the script die which may be an embarrassement in most of the cases).

FAQ:

Q1. I'm getting an error in CCX Editor: "error unmarshalling return nested exception is java.net.SocketException". Why?

A1. Make sure you restart the CCX Engine after uploading the JCIFS library and before trying to run the script. Yes, it's really necessary.

Q2. Will Cisco TAC support this?

A2. I don't know, ask them :-) Probably not, since it uses an external library.

Q3. JCIFS is licensed under LGPL. Can it be used with UCCX?

A3. Not sure. I am not a lawyer. Probably yes. But again, I am not sure about it.

Comments
mehti1980
Level 1
Level 1

Hi Gergely,

 

I can't having  writing the file out to one of our windows 2012 file server. When I run reactive script for debug I got error which you can see below. Can you help to me?

Capture2.JPG

 

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: