@@ -96,6 +96,13 @@ public protocol AudioProcessing {
9696 /// Starts recording audio from the specified input device, resetting the previous state
9797 func startRecordingLive( inputDeviceID: DeviceID ? , callback: ( ( [ Float ] ) -> Void ) ? ) throws
9898
99+ /// Starts live audio recording and provides an async stream of audio samples.
100+ ///
101+ /// - Parameter inputDeviceID: The device ID of the input audio device to use for recording.
102+ /// This parameter is only valid on macOS; iOS always uses the default input device.
103+ /// - Returns: A tuple containing the async stream of audio sample buffers and the stream's continuation.
104+ func startStreamingRecordingLive( inputDeviceID: DeviceID ? ) -> ( AsyncThrowingStream < [ Float ] , Error > , AsyncThrowingStream < [ Float ] , Error > . Continuation )
105+
99106 /// Pause recording
100107 func pauseRecording( )
101108
@@ -128,10 +135,14 @@ public extension AudioProcessing {
128135 try AudioProcessor . loadAudio ( fromPath: audioFilePath)
129136 } . value
130137 }
131-
138+
132139 func startRecordingLive( inputDeviceID: DeviceID ? = nil , callback: ( ( [ Float ] ) -> Void ) ? ) throws {
133140 try startRecordingLive ( inputDeviceID: inputDeviceID, callback: callback)
134141 }
142+
143+ func startStreamingRecordingLive( inputDeviceID: DeviceID ? = nil ) -> ( AsyncThrowingStream < [ Float ] , Error > , AsyncThrowingStream < [ Float ] , Error > . Continuation ) {
144+ return startStreamingRecordingLive ( inputDeviceID: inputDeviceID)
145+ }
135146
136147 func resumeRecordingLive( inputDeviceID: DeviceID ? = nil , callback: ( ( [ Float ] ) -> Void ) ? ) throws {
137148 try resumeRecordingLive ( inputDeviceID: inputDeviceID, callback: callback)
@@ -1023,6 +1034,28 @@ public extension AudioProcessor {
10231034 lastInputDevice = inputDeviceID
10241035 }
10251036
1037+ /// Starts live audio recording and returns an async stream that yields sample buffers.
1038+ /// Recording stops automatically when the stream terminates.
1039+ func startStreamingRecordingLive( inputDeviceID: DeviceID ? = nil ) -> ( AsyncThrowingStream < [ Float ] , Error > , AsyncThrowingStream < [ Float ] , Error > . Continuation ) {
1040+ let ( stream, continuation) = AsyncThrowingStream < [ Float ] , Error > . makeStream ( bufferingPolicy: . unbounded)
1041+
1042+ continuation. onTermination = { [ weak self] _ in
1043+ guard let self = self else { return }
1044+ self . audioBufferCallback = nil
1045+ self . stopRecording ( )
1046+ }
1047+
1048+ do {
1049+ try self . startRecordingLive ( inputDeviceID: inputDeviceID) { @Sendable floats in
1050+ continuation. yield ( floats)
1051+ }
1052+ } catch {
1053+ continuation. finish ( throwing: error)
1054+ }
1055+
1056+ return ( stream, continuation)
1057+ }
1058+
10261059 func resumeRecordingLive( inputDeviceID: DeviceID ? = nil , callback: ( ( [ Float ] ) -> Void ) ? = nil ) throws {
10271060 try ? setupAudioSessionForDevice ( )
10281061
0 commit comments