Fix call hold/resume and recording issues, add configurable hold music

## 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 <noreply@anthropic.com>
This commit is contained in:
2025-08-30 15:46:19 -07:00
parent 060b95c710
commit 0bbc499878

View File

@@ -398,6 +398,20 @@ class TWP_Admin {
</tr>
</table>
<h2>Call Settings</h2>
<table class="form-table">
<tr>
<th scope="row">Hold Music URL</th>
<td>
<input type="url" name="twp_hold_music_url"
value="<?php echo esc_attr(get_option('twp_hold_music_url', 'https://api.twilio.com/cowbell.mp3')); ?>"
class="regular-text" />
<p class="description">URL to audio file to play when calls are placed on hold. Must be publicly accessible MP3 or WAV file.</p>
<p class="description"><strong>Suggested sources:</strong> Upload to your Media Library or use a service like Freesound.org for royalty-free music.</p>
</td>
</tr>
</table>
<h2>Default Queue Settings</h2>
<table class="form-table">
<tr>
@@ -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());
}
}