Skip to content

Commit 21405b1

Browse files
committed
feat: refactored audio recorder
1 parent 7745098 commit 21405b1

3 files changed

Lines changed: 1649 additions & 470 deletions

File tree

getstream/video/rtc/connection_manager.py

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import uuid
33
import asyncio
44
import logging
5-
from typing import Optional, Dict, Set, List
5+
from typing import Optional, List
66

77
import aioice
88
import aiortc
@@ -25,7 +25,8 @@
2525
from twirp import context
2626

2727
from getstream.video.rtc.coordinator import join_call_coordinator_request
28-
from getstream.video.rtc.recording import AudioRecorder, RecordingType
28+
from getstream.video.rtc.recording import RecordingManager, RecordingType
29+
2930

3031
from getstream.video.rtc.track_util import (
3132
BufferedMediaTrack,
@@ -126,8 +127,7 @@ def __init__(self, call: Call, user_id: str = None, create: bool = True, **kwarg
126127

127128
self.participants_state = ParticipantsState()
128129

129-
# Audio recording functionality
130-
self.audio_recorder = AudioRecorder()
130+
self.recording_manager = RecordingManager()
131131

132132
async def _full_connect(self):
133133
"""Perform location discovery and join call via coordinator.
@@ -257,6 +257,8 @@ async def on_audio(pcm_data, user):
257257
)
258258
self.ws_client.on_event("ice_trickle", self._on_ice_trickle)
259259
self.ws_client.on_event("subscriber_offer", self._on_subscriber_offer)
260+
self.ws_client.on_event("participant_left", self._on_participant_left)
261+
260262
# Mark as running and clear stop event
261263
self.running = True
262264
self._stop_event.clear()
@@ -279,8 +281,7 @@ async def leave(self):
279281
self.running = False
280282
self._stop_event.set() # Signal the iterator to stop
281283

282-
# Stop recording if active
283-
self.audio_recorder.cleanup()
284+
await self.recording_manager.cleanup()
284285

285286
if self.ws_client:
286287
self.ws_client.close()
@@ -727,9 +728,8 @@ async def add_video_track(self, track: aiortc.mediastreams.MediaStreamTrack):
727728

728729
await self.add_tracks(video=track)
729730

730-
# Recording functionality methods
731-
732-
def start_recording(
731+
732+
async def start_recording(
733733
self,
734734
recording_types: List[RecordingType],
735735
user_ids: Optional[List[str]] = None,
@@ -739,13 +739,14 @@ def start_recording(
739739
Start recording audio tracks.
740740
741741
Args:
742-
recording_types: List of recording types to start (INDIVIDUAL, COMPOSITE)
742+
recording_types: List of recording types to start (TRACK, COMPOSITE)
743743
user_ids: Optional list of specific user IDs to record (None = all users)
744744
output_dir: Directory to save recording files
745745
"""
746-
self.audio_recorder.start_recording(recording_types, user_ids, output_dir)
746+
logger.info("Starting recording")
747+
await self.recording_manager.start_recording(recording_types, user_ids, output_dir)
747748

748-
def stop_recording(
749+
async def stop_recording(
749750
self,
750751
recording_types: Optional[List[RecordingType]] = None,
751752
user_ids: Optional[List[str]] = None
@@ -757,23 +758,36 @@ def stop_recording(
757758
recording_types: Optional list of recording types to stop (None = stop all)
758759
user_ids: Optional specific user IDs to stop recording (None = stop all users)
759760
"""
760-
self.audio_recorder.stop_recording(recording_types, user_ids)
761+
await self.recording_manager.stop_recording(recording_types, user_ids)
761762

762763
def _record_audio_data(self, pcm_data, user_id: str):
763764
"""
764-
Record audio data for a specific user and/or composite.
765+
Record audio data for a specific user
765766
766767
Args:
767768
pcm_data: PCM audio data (can be bytes, PcmData object, or numpy array)
768769
user_id: ID of the user whose audio this is
769770
"""
770-
self.audio_recorder.record_audio_data(pcm_data, user_id)
771+
self.recording_manager.record_audio_data(pcm_data, user_id)
771772

772773
@property
773774
def is_recording(self) -> bool:
774775
"""Check if recording is currently active."""
775-
return self.audio_recorder.is_recording
776+
return self.recording_manager.is_recording
776777

777778
def get_recording_status(self) -> dict:
778779
"""Get current recording status and information."""
779-
return self.audio_recorder.get_recording_status()
780+
return self.recording_manager.get_recording_status()
781+
782+
async def _on_participant_left(self, event):
783+
"""Handle participant leaving - cleanup their recording if active."""
784+
try:
785+
await self.participants_state._on_participant_left(event)
786+
787+
# Stop recording for the user who left
788+
if hasattr(event, 'participant') and hasattr(event.participant, 'user_id'):
789+
user_id = event.participant.user_id
790+
await self.recording_manager.on_user_left(user_id)
791+
792+
except Exception as e:
793+
logger.error(f"Error handling participant left event: {e}")

0 commit comments

Comments
 (0)