From 0bbc49987881209e8afb8be7a554e3edcdb844db Mon Sep 17 00:00:00 2001 From: jknapp Date: Sat, 30 Aug 2025 15:46:19 -0700 Subject: [PATCH] Fix call hold/resume and recording issues, add configurable hold music MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Hold/Resume Fixes - Fixed call disconnection issue when resuming from hold - Changed resume logic from webhook redirect to empty TwiML continuation - This allows browser phone calls to continue normally after hold ## Recording Stop Improvements - Enhanced error handling for recording stop functionality - Check recording status in database before attempting Twilio API call - Handle cases where recording is already stopped or completed - Graceful fallback if Twilio API call fails - Better logging for debugging recording issues ## Configurable Hold Music - Added "Hold Music URL" setting in admin Settings page - Allows admins to specify custom hold music instead of default cowbell - Supports MP3 and WAV files from any publicly accessible URL - Default remains Twilio's cowbell.mp3 for backwards compatibility - Setting automatically saved/loaded through WordPress settings API ## Technical Details - Hold music URL retrieved via get_option() with fallback - Recording stop checks database state before API calls - Improved error messages and logging throughout - All changes maintain backwards compatibility 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- admin/class-twp-admin.php | 68 ++++++++++++++++++++++++++++++++------- 1 file changed, 56 insertions(+), 12 deletions(-) diff --git a/admin/class-twp-admin.php b/admin/class-twp-admin.php index 4876ba7..2c23fbc 100644 --- a/admin/class-twp-admin.php +++ b/admin/class-twp-admin.php @@ -398,6 +398,20 @@ class TWP_Admin { +

Call Settings

+ + + + + +
Hold Music URL + +

URL to audio file to play when calls are placed on hold. Must be publicly accessible MP3 or WAV file.

+

Suggested sources: Upload to your Media Library or use a service like Freesound.org for royalty-free music.

+
+

Default Queue Settings

@@ -3005,6 +3019,7 @@ class TWP_Admin { register_setting('twilio-wp-settings-group', 'twp_elevenlabs_api_key'); register_setting('twilio-wp-settings-group', 'twp_elevenlabs_voice_id'); register_setting('twilio-wp-settings-group', 'twp_elevenlabs_model_id'); + register_setting('twilio-wp-settings-group', 'twp_hold_music_url'); register_setting('twilio-wp-settings-group', 'twp_default_queue_timeout'); register_setting('twilio-wp-settings-group', 'twp_default_queue_size'); register_setting('twilio-wp-settings-group', 'twp_urgent_keywords'); @@ -6890,17 +6905,20 @@ class TWP_Admin { if ($hold) { // Place call on hold with music + $hold_music_url = get_option('twp_hold_music_url', 'https://api.twilio.com/cowbell.mp3'); $twiml = new \Twilio\TwiML\VoiceResponse(); - $twiml->play('https://api.twilio.com/cowbell.mp3', ['loop' => 0]); + $twiml->play($hold_music_url, ['loop' => 0]); $call = $client->calls($call_sid)->update([ 'twiml' => $twiml->asXML() ]); } else { - // Resume call by redirecting back to conference or original context + // Resume call - for browser phone, just provide empty TwiML to continue + $twiml = new \Twilio\TwiML\VoiceResponse(); + // Empty TwiML allows the call to continue normally + $call = $client->calls($call_sid)->update([ - 'url' => home_url('/wp-json/twilio-webhook/v1/resume-call'), - 'method' => 'POST' + 'twiml' => $twiml->asXML() ]); } @@ -7065,19 +7083,44 @@ class TWP_Admin { $call_sid = sanitize_text_field($_POST['call_sid']); $recording_sid = sanitize_text_field($_POST['recording_sid']); + if (empty($recording_sid)) { + wp_send_json_error('Recording SID is required'); + return; + } + + global $wpdb; + $recordings_table = $wpdb->prefix . 'twp_call_recordings'; + + // Check if recording exists and is active + $recording_info = $wpdb->get_row($wpdb->prepare( + "SELECT * FROM $recordings_table WHERE recording_sid = %s", + $recording_sid + )); + + if (!$recording_info) { + wp_send_json_error('Recording not found in database'); + return; + } + + if ($recording_info->status === 'completed') { + // Already stopped, just update UI + wp_send_json_success(['message' => 'Recording already stopped']); + return; + } + try { $twilio = new TWP_Twilio_API(); $client = $twilio->get_client(); - // Stop the recording - $recording = $client->calls($call_sid) - ->recordings($recording_sid) - ->update(['status' => 'stopped']); - - // Update database - global $wpdb; - $recordings_table = $wpdb->prefix . 'twp_call_recordings'; + // Try to stop the recording in Twilio + try { + $recording = $client->recordings($recording_sid)->update(['status' => 'stopped']); + } catch (Exception $twilio_error) { + // Recording might already be stopped or completed on Twilio's side + error_log('TWP: Could not stop recording in Twilio (may already be stopped): ' . $twilio_error->getMessage()); + } + // Update database regardless $wpdb->update( $recordings_table, [ @@ -7089,6 +7132,7 @@ class TWP_Admin { wp_send_json_success(['message' => 'Recording stopped']); } catch (Exception $e) { + error_log('TWP: Error stopping recording: ' . $e->getMessage()); wp_send_json_error('Failed to stop recording: ' . $e->getMessage()); } }