Voip Drupal and PhoneRecorderField - Resolving "Audio not recorded. Try again." error

This week I delievered the first phase of a VOIP based Drupal site to a medical industry client using the VoipDrupal suite of modules. Let me first take this opportunity to acknowledge the great work Leo Burd and his team at MIT Center have done in developing an excellent and comprehensive set of modules revolving around providing VOIP support in Drupal, I never thought I could do a Drupal VOIP project in such less time until I did it using the mentioned suite of modules.

Like any other job, this one too had some anxious moments. One of them and how I got past it is the topic of this blog post, getting a "Audio not recorded. Try again." error when using the PhoneRecorderField together with VoipDrupal to make voip based phone calls and recording the same.

I had setup my site correctly as per voipdrupal (and associated modules') documentation and everything seemed to work fine (except the last step). I could click a button to initiate outbound calls from my Drupal site, receive the call on my phone and leave a message for the site. Things were working fine, the message was getting recorded (as was confirmed by my Tropo script to me, Tropo was my voip provider) but on my Drupal page, after the call was completed, I always got a "Audio not recorded. Try again." error (instead of recording playback as was to be expected). I checked the official demo site http://voipdrupal.org and tried recording a message there, to my surprise the demo site also showed the same error to me (at the time I tested it).

I had an immediate pending demo the next day and needed to get the issue resolved. So I opened up the phonerecorderfield module's code and searched for this error. I was able to locate it in phonerecorderfield_get_recording method. A quick look at that method revealed that a call to phonerecorderfield_file_load returning empty result should be causing this issue. After browsing to phonerecorderfield_file_load, I was able to figure out that phonerecorderfield module is expecting an entry in phonerecorderfield_recording db table which it is not able to find leading to error.

The next step was to find out where is the entry inserted to this table and that happened to be in phonerecorderfield.script.inc file's _phonerecorderfield_record_callback method. The same method is registered as the callback method to be invoked after the call is finished in phonerecorderfield_voipscript_load_script method.

Having come this far, I was quickly able to establish that desired callback method (_phonerecorderfield_record_callback) was not being invoked when the call was finished and now the task was to find out why (my imagination was as the call was being invoked by phonerecorderfield itself, it should not have any issues invoking its own desired callback as needed). I analyzed Tropo's debugger logs but nothing useful came up. So I turned back to my Drupal codebase.

After some more searching in voipdrupal and phonerecorderfield modules' code, I was able to narrow down to voiptropo.inc file's _voiptropo_script_handler method's following lines where the above mentioned callback was supposed to be invoked:

 

        case 'VoipCmdSet';
          $var_name = $script->evalString($cmd->getParam('var_name'));
          $var_value = $script->evalString($cmd->getParam('var_value'));
          $script->setVar($var_name, $var_value);
          break;

I inserted some watchdog entries in the above code as well as noticed some other watchdog entries added implicitly by phonerecorderfield module which lead me to phonerecorderfield_call method in phonerecoderfield.module. And when I studied this method's code, one thing struck me immediately, these lines:

 

 $script_name=phonerecorderfield_get_widget_setting($machine_field_name, $_GET['node_type'], 'phonerecorderfield_script');
  $script = VoipScript::loadScript($script_name, $vars);

  $call = new VoipCall();
  $call->setDestNumber($number);
  $call->setDestName($user->name);
  $call->setCallerName('Phone Recorder Field');
  $call->setScript($script);

So, phonerecorderfield was loading a tropo voip script dynamically and using it (instead of using its own hard-coded script in phonerecorderfield_voipscript_load_script method). I went back to my audio field's CCK configuration and the reason was there in front of me. I had chosen my custom voip script for outbound calls and that custom script was not invoking phonerecorderfield's required callback.

I switched my audio field's script to "phonerecorderfield_default" script and when I went back to my node creation page, and initated another voip call, voila this time after the recording was saved, I was shown the playback controls on my Drupal page.

I now knew that my custom voip script needed to invoke the _phonerecorderfield_record_callback to enable phonerecorderfield to register the recording and be able to store and play it.

So I again switched back to my custom voip script and edited it to add the following lines in the section where the recording was successful:

 

      // Set variables from $vars to pass to callback function.
      $script->addSet('uid', $vars['uid']); 
      $script->addSet('name', $vars['name']); 
      $script->addSet('number', $vars['number']); 
      // Process recording.
      $script->addSet('callback_result',
        '^_phonerecorderfield_record_callback(%call_id, %recording_public_url, %recording_duration,%recording_fid, %uid, %name, %number)');

And bull's eye, my custom script was also now able to play nice with phonerecorderfield.

So to summarize, when using the phonerecorderfield in Drupal, you should either use that field's default script phonerecorderfield_default for recordings, or if you want to customize the script, then the above lines (in the last code snippet) need to be present in your script label section where you are accepting the recording from the user.

Phew, that was a close shave before the demo date...