From c1901490ae0078ca272d266df3054e7c10ce5cbe Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Sun, 15 Feb 2026 10:04:24 +0530 Subject: [PATCH] fix: send OutputAudio frame and let transport chunk it --- api/routes/telephony.py | 2 +- .../workflow/pipecat_engine_custom_tools.py | 65 +++++-------------- pipecat | 2 +- 3 files changed, 18 insertions(+), 51 deletions(-) diff --git a/api/routes/telephony.py b/api/routes/telephony.py index 43ee771..1ed04ed 100644 --- a/api/routes/telephony.py +++ b/api/routes/telephony.py @@ -1643,7 +1643,7 @@ async def complete_transfer_function_call(transfer_id: str, request: Request): conference_name = transfer_context.conference_name if transfer_context else None # Determine the result based on call status with user-friendly messaging - if call_status in ("answered", "completed"): + if call_status in ("in-progress", "answered"): result = { "status": "success", "message": "Great! The destination number answered. Let me transfer you now.", diff --git a/api/services/workflow/pipecat_engine_custom_tools.py b/api/services/workflow/pipecat_engine_custom_tools.py index 5518f0d..e07fb6b 100644 --- a/api/services/workflow/pipecat_engine_custom_tools.py +++ b/api/services/workflow/pipecat_engine_custom_tools.py @@ -14,6 +14,7 @@ from typing import TYPE_CHECKING, Any, Optional from loguru import logger +from api.constants import APP_ROOT_DIR from api.db import db_client from api.enums import ToolCategory from api.services.telephony.call_transfer_manager import get_call_transfer_manager @@ -548,65 +549,31 @@ class CustomToolManager: sample_rate: Sample rate for the hold music (default 8000Hz for Twilio) """ try: - import os - # Path to hold music file based on sample rate - assets_dir = os.path.join( - os.path.dirname(os.path.dirname(os.path.dirname(__file__))), "assets" + hold_music_file = ( + APP_ROOT_DIR / "assets" / f"transfer_hold_ring_{sample_rate}.wav" ) - - # Select appropriate hold music file - if sample_rate == 16000: - hold_music_file = os.path.join( - assets_dir, "transfer_hold_ring_16000.wav" - ) - else: # Default to 8000Hz for Twilio - hold_music_file = os.path.join( - assets_dir, "transfer_hold_ring_8000.wav" - ) + hold_audio_data = load_hold_audio(hold_music_file, sample_rate) + num_samples = len(hold_audio_data) // 2 + duration = int(num_samples / sample_rate) logger.info(f"Starting hold music loop with file: {hold_music_file}") - # Load hold music audio data - hold_audio_data = load_hold_audio(hold_music_file, sample_rate) - if not hold_audio_data: - logger.error("Failed to load hold music data") - return - - # Convert bytes to audio frames - each frame should be about 20ms worth of audio - # For 8000Hz: 20ms = 160 samples = 320 bytes (16-bit) - # For 16000Hz: 20ms = 320 samples = 640 bytes (16-bit) - frame_size = 320 if sample_rate == 8000 else 640 - - audio_data = hold_audio_data - total_length = len(audio_data) - position = 0 - - logger.info( - f"Hold music loaded: {total_length} bytes, frame size: {frame_size}" - ) - while not stop_event.is_set(): - # Extract audio chunk - if position + frame_size > total_length: - # Reached end of audio, loop back to beginning - position = 0 - - audio_chunk = audio_data[position : position + frame_size] - position += frame_size - - # Create audio frame - audio_frame = OutputAudioRawFrame( - audio=audio_chunk, + # Queue the hold audio frame + frame = OutputAudioRawFrame( + audio=hold_audio_data, sample_rate=sample_rate, num_channels=1, ) + await self._engine.task.queue_frame(frame) - # Queue the frame - await self._engine.task.queue_frame(audio_frame) - - # Sleep for frame duration (20ms) - await asyncio.sleep(0.02) + # Wait for the audio to play or until stopped + try: + await asyncio.wait_for(stop_event.wait(), timeout=duration + 1.5) + break # Stop event was set + except asyncio.TimeoutError: + pass # Continue looping logger.info("Hold music loop stopped") diff --git a/pipecat b/pipecat index ff7d4c1..c37cedc 160000 --- a/pipecat +++ b/pipecat @@ -1 +1 @@ -Subproject commit ff7d4c19bf02bf0e14bfe7ae20e016e04b8ba27d +Subproject commit c37cedc16fa9a9a72fe2dcb270fcc1ffe0071480