Multiple Recordings and Copying Recordings in VoiceModel

I had a couple of enhancement requests in the VoiceModel Project around making user recordings.  The first request was to allow the directory that holds the recordings to be specified as a file structure or file share. And the second request was to allow multiple recordings in a single session.  I finally got some time to look at implementing these enhancements and was pleasantly surprised that the features were already in place because of the flexibility in the VoiceModel architecture and state machine. Well, for the most part. I will explain one little change I had to make to VoiceModel to get this to work.

To test this out I updated the RecordingExample project in the VMWithExamples solution. You can get the source code here. Basically my solution was to add an On-Exit-Action to the recording state that copies the recorded file to another location.  This satisfies the request to be able to put recording in another location, including a file share.   Here is what the On-Exit-Action looks like.

flow.AddState(ViewStateBuilder.Build("getRecording", "playback",
    new Record("getRecording", "Please record your information after the beep.  Press the pound key when you are finished."))
    .AddOnExitAction(delegate(CallFlow cf, State state, Event e)
    {
        VoiceModel.Logger.ILoggerService logger = VoiceModel.Logger.LoggerFactory.GetInstance();
        try
        {
            //Copy last recording to another location
            string recordingPhysicalPath = Server.MapPath(RecordingPath);
            string recordingFileName = recordingPhysicalPath + "//" + cf.SessionId + ".wav";
            logger.Debug("Copying recording " + recordingFileName);
            System.IO.File.Copy(recordingFileName, "c://tmp//" + cf.SessionId + "_first.wav");
        }
        catch (Exception ex)
        {
            logger.Error("Error copying recording: " + ex.Message);
        }
    }), true);


That is all that is required to copy your recording to any location and even rename them. You will notice that I kept the session ID in the name to make sure the file name was unique and would not be copied over by another call into the system. You can use any scheme you would like to manage these file. For example, maybe you collected a unique caller identifier earlier in the voice application that you could use to organize recordings by caller.

It turns out this helps satisfy the second requirement for multiple recordings. Since we can copy the recording to another location for safe keeping we can just add another Record object in the application and it will replace the original recording. Then you just copy it again to another location using a different file name. I tested this out in the example and it works fine. The first recording I named [SessionId]_first.wav and the second recording I named [SessionId]_second.wav.

But I did find a problem on playback of the recordings.  The URI for audio recording for the first and second recordings are the same since the file name is solely base on the session ID.  I used Voxeo Cloud VoiceXML Platform to test this and it does an excellent job of caching audio files which I did not want in this case.  This caused the application to voice back the first recording when the caller should have been listening to the second recording.  I solved this by changing VoiceModel to specify not the use cache in the HTML header when retrieving audio recordings. You can get the latest release of  VoiceModel with this fix on NuGet.  This would have also been an issue if you  are setting up something like a voice mail system with VoiceModel, where you give the caller a chance to re-record what they have already recorded.  Playback would always just used the first recording.

This example also demonstrates how easy it is to add logging to your VoiceModel applications. This proved invaluable when troubleshooting initial issues when trying to copy recordings.  The only other thing you need to do to add this logging is make sure you have a log4net config file in the root of your application directory.

I love it when enhancement requests can be handled with very little change to the code.



Comments

Popular posts from this blog

Using Claims in ASP.NET Identity

Customizing Claims for Authorization in ASP.NET Core 2.0

Seeding & Customizing ASP.NET MVC SimpleMembership