Skip to content

Fix startLocalRecording() #578

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ let package = Package(
],
dependencies: [
// LK-Prefixed Dynamic WebRTC XCFramework
.package(url: "https://github.com/livekit/webrtc-xcframework.git", exact: "125.6422.16"),
.package(url: "https://github.com/livekit/webrtc-xcframework.git", exact: "125.6422.17"),
.package(url: "https://github.com/apple/swift-protobuf.git", from: "1.26.0"),
.package(url: "https://github.com/apple/swift-log.git", from: "1.5.4"),
// Only used for DocC generation
Expand Down
2 changes: 1 addition & 1 deletion Package@swift-5.9.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ let package = Package(
],
dependencies: [
// LK-Prefixed Dynamic WebRTC XCFramework
.package(url: "https://github.com/livekit/webrtc-xcframework.git", exact: "125.6422.16"),
.package(url: "https://github.com/livekit/webrtc-xcframework.git", exact: "125.6422.17"),
.package(url: "https://github.com/apple/swift-protobuf.git", from: "1.26.0"),
.package(url: "https://github.com/apple/swift-log.git", from: "1.5.4"),
// Only used for DocC generation
Expand Down
3 changes: 3 additions & 0 deletions Sources/LiveKit/Track/AudioManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,10 @@
public var localTracksCount: Int = 0
public var remoteTracksCount: Int = 0
public var isSpeakerOutputPreferred: Bool = true
public var customConfigureFunc: ConfigureAudioSessionFunc?

Check warning on line 104 in Sources/LiveKit/Track/AudioManager.swift

View workflow job for this annotation

GitHub Actions / test (macos-14, 15.4, iOS Simulator,OS=17.5,name=iPhone 15 Pro)

'ConfigureAudioSessionFunc' is deprecated

Check warning on line 104 in Sources/LiveKit/Track/AudioManager.swift

View workflow job for this annotation

GitHub Actions / test (macos-14, 15.4, iOS Simulator,OS=17.5,name=iPhone 15 Pro)

'ConfigureAudioSessionFunc' is deprecated

Check warning on line 104 in Sources/LiveKit/Track/AudioManager.swift

View workflow job for this annotation

GitHub Actions / test (macos-15, 16.2, iOS Simulator,OS=18.1,name=iPhone 16 Pro)

'ConfigureAudioSessionFunc' is deprecated

Check warning on line 104 in Sources/LiveKit/Track/AudioManager.swift

View workflow job for this annotation

GitHub Actions / test (macos-14, 15.4, tvOS Simulator,name=Apple TV)

'ConfigureAudioSessionFunc' is deprecated

Check warning on line 104 in Sources/LiveKit/Track/AudioManager.swift

View workflow job for this annotation

GitHub Actions / test (macos-14, 15.4, macOS,variant=Mac Catalyst)

'ConfigureAudioSessionFunc' is deprecated

Check warning on line 104 in Sources/LiveKit/Track/AudioManager.swift

View workflow job for this annotation

GitHub Actions / test (macos-14, 15.4, tvOS Simulator,name=Apple TV)

'ConfigureAudioSessionFunc' is deprecated

Check warning on line 104 in Sources/LiveKit/Track/AudioManager.swift

View workflow job for this annotation

GitHub Actions / test (macos-14, 15.4, macOS,variant=Mac Catalyst)

'ConfigureAudioSessionFunc' is deprecated

Check warning on line 104 in Sources/LiveKit/Track/AudioManager.swift

View workflow job for this annotation

GitHub Actions / test (macos-15, 16.2, macOS,variant=Mac Catalyst)

'ConfigureAudioSessionFunc' is deprecated

Check warning on line 104 in Sources/LiveKit/Track/AudioManager.swift

View workflow job for this annotation

GitHub Actions / test (macos-14, 15.4, visionOS Simulator,name=Apple Vision Pro)

'ConfigureAudioSessionFunc' is deprecated

Check warning on line 104 in Sources/LiveKit/Track/AudioManager.swift

View workflow job for this annotation

GitHub Actions / test (macos-14, 15.4, visionOS Simulator,name=Apple Vision Pro)

'ConfigureAudioSessionFunc' is deprecated
public var sessionConfiguration: AudioSessionConfiguration?

public var trackState: TrackState {

Check warning on line 107 in Sources/LiveKit/Track/AudioManager.swift

View workflow job for this annotation

GitHub Actions / test (macos-14, 15.4, iOS Simulator,OS=17.5,name=iPhone 15 Pro)

'TrackState' is deprecated

Check warning on line 107 in Sources/LiveKit/Track/AudioManager.swift

View workflow job for this annotation

GitHub Actions / test (macos-14, 15.4, iOS Simulator,OS=17.5,name=iPhone 15 Pro)

'TrackState' is deprecated

Check warning on line 107 in Sources/LiveKit/Track/AudioManager.swift

View workflow job for this annotation

GitHub Actions / test (macos-15, 16.2, iOS Simulator,OS=18.1,name=iPhone 16 Pro)

'TrackState' is deprecated

Check warning on line 107 in Sources/LiveKit/Track/AudioManager.swift

View workflow job for this annotation

GitHub Actions / test (macos-14, 15.4, tvOS Simulator,name=Apple TV)

'TrackState' is deprecated

Check warning on line 107 in Sources/LiveKit/Track/AudioManager.swift

View workflow job for this annotation

GitHub Actions / test (macos-14, 15.4, macOS,variant=Mac Catalyst)

'TrackState' is deprecated

Check warning on line 107 in Sources/LiveKit/Track/AudioManager.swift

View workflow job for this annotation

GitHub Actions / test (macos-14, 15.4, tvOS Simulator,name=Apple TV)

'TrackState' is deprecated

Check warning on line 107 in Sources/LiveKit/Track/AudioManager.swift

View workflow job for this annotation

GitHub Actions / test (macos-14, 15.4, macOS,variant=Mac Catalyst)

'TrackState' is deprecated

Check warning on line 107 in Sources/LiveKit/Track/AudioManager.swift

View workflow job for this annotation

GitHub Actions / test (macos-15, 16.2, macOS,variant=Mac Catalyst)

'TrackState' is deprecated

Check warning on line 107 in Sources/LiveKit/Track/AudioManager.swift

View workflow job for this annotation

GitHub Actions / test (macos-14, 15.4, visionOS Simulator,name=Apple Vision Pro)

'TrackState' is deprecated

Check warning on line 107 in Sources/LiveKit/Track/AudioManager.swift

View workflow job for this annotation

GitHub Actions / test (macos-14, 15.4, visionOS Simulator,name=Apple Vision Pro)

'TrackState' is deprecated
switch (localTracksCount > 0, remoteTracksCount > 0) {
case (true, false): return .localOnly
case (false, true): return .remoteOnly
Expand Down Expand Up @@ -241,6 +241,9 @@
/// Starts mic input to the SDK even without any ``Room`` or a connection.
/// Audio buffers will flow into ``LocalAudioTrack/add(audioRenderer:)`` and ``capturePostProcessingDelegate``.
public func startLocalRecording() {
// Always unmute APM if muted by last session.
RTC.audioProcessingModule.isMuted = false
// Start recording on the ADM.
RTC.audioDeviceModule.initAndStartRecording()
}

Expand Down
73 changes: 48 additions & 25 deletions Tests/LiveKitTests/AudioEngineTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -106,32 +106,55 @@
}

// Test start generating local audio buffer without joining to room.
func testPrejoinLocalAudioBuffer() async throws {
// Set up expectation...
let didReceiveAudioFrame = expectation(description: "Did receive audio frame")
didReceiveAudioFrame.assertForOverFulfill = false

// Start watching for audio frame...
let audioFrameWatcher = AudioTrackWatcher(id: "notifier01") { _ in
didReceiveAudioFrame.fulfill()
func testPreconnectAudioBuffer() async throws {
print("Setting recording always prepared mode...")
AudioManager.shared.isRecordingAlwaysPrepared = true

var counter = 0
// Executes 10 times by default.
measure {
counter += 1
print("Measuring attempt \(counter)...")
// Set up expectation...
let didReceiveAudioFrame = expectation(description: "Did receive audio frame")
didReceiveAudioFrame.assertForOverFulfill = false

let didConnectToRoom = expectation(description: "Did connect to room")
didConnectToRoom.assertForOverFulfill = false

// Create an audio frame watcher...
let audioFrameWatcher = AudioTrackWatcher(id: "notifier01") { _ in
didReceiveAudioFrame.fulfill()
}

let localMicTrack = LocalAudioTrack.createTrack()
// Attach audio frame watcher...
localMicTrack.add(audioRenderer: audioFrameWatcher)

Task.detached {
print("Starting local recording...")
AudioManager.shared.startLocalRecording()
}

// Wait for audio frame...
print("Waiting for first audio frame...")
// await fulfillment(of: [didReceiveAudioFrame], timeout: 10)
wait(for: [didReceiveAudioFrame], timeout: 30)

Task.detached {
print("Connecting to room...")
try await self.withRooms([RoomTestingOptions(canPublish: true)]) { rooms in
print("Publishing mic...")
try await rooms[0].localParticipant.setMicrophone(enabled: true)
didConnectToRoom.fulfill()
}
}

print("Waiting for room to connect & disconnect...")
wait(for: [didConnectToRoom], timeout: 30)

localMicTrack.remove(audioRenderer: audioFrameWatcher)
}

let localMicTrack = LocalAudioTrack.createTrack()
// Attach audio frame watcher...
localMicTrack.add(audioRenderer: audioFrameWatcher)

Task.detached {
print("Starting audio track in 3 seconds...")
try? await Task.sleep(nanoseconds: 3 * 1_000_000_000)
AudioManager.shared.startLocalRecording()
}

// Wait for audio frame...
print("Waiting for first audio frame...")
await fulfillment(of: [didReceiveAudioFrame], timeout: 10)

// Remove audio frame watcher...
localMicTrack.remove(audioRenderer: audioFrameWatcher)
}

// Test the manual rendering mode (no-device mode) of AVAudioEngine based AudioDeviceModule.
Expand Down Expand Up @@ -282,7 +305,7 @@
}

final class SineWaveNodeHook: AudioEngineObserver {
var next: (any LiveKit.AudioEngineObserver)?

Check warning on line 308 in Tests/LiveKitTests/AudioEngineTests.swift

View workflow job for this annotation

GitHub Actions / test (macos-14, 15.4, macOS)

stored property 'next' of 'Sendable'-conforming class 'SineWaveNodeHook' is mutable

let sineWaveNode = SineWaveSourceNode()

Expand All @@ -301,7 +324,7 @@
}

final class PlayerNodeHook: AudioEngineObserver {
var next: (any LiveKit.AudioEngineObserver)?

Check warning on line 327 in Tests/LiveKitTests/AudioEngineTests.swift

View workflow job for this annotation

GitHub Actions / test (macos-14, 15.4, macOS)

stored property 'next' of 'Sendable'-conforming class 'PlayerNodeHook' is mutable

public let playerNode = AVAudioPlayerNode()
public let playerMixerNode = AVAudioMixerNode()
Expand Down
3 changes: 1 addition & 2 deletions Tests/LiveKitTests/Support/Tracks.swift
Original file line number Diff line number Diff line change
Expand Up @@ -186,10 +186,9 @@ class AudioTrackWatcher: AudioRenderer {
}

func render(pcmBuffer: AVAudioPCMBuffer) {
print("did receive first audio frame: \(String(describing: pcmBuffer))")

_state.mutate {
if !$0.didRenderFirstFrame {
print("did receive first audio frame: \(String(describing: pcmBuffer))")
$0.didRenderFirstFrame = true
onDidRenderFirstFrame?(id)
}
Expand Down
Loading