diff --git a/VoiceInk/PlaybackController.swift b/VoiceInk/PlaybackController.swift index b4dfd3b..376fd63 100644 --- a/VoiceInk/PlaybackController.swift +++ b/VoiceInk/PlaybackController.swift @@ -15,6 +15,12 @@ class PlaybackController: ObservableObject { @Published var isPauseMediaEnabled: Bool = UserDefaults.standard.bool(forKey: "isPauseMediaEnabled") { didSet { UserDefaults.standard.set(isPauseMediaEnabled, forKey: "isPauseMediaEnabled") + + if isPauseMediaEnabled { + startMediaTracking() + } else { + stopMediaTracking() + } } } @@ -25,19 +31,40 @@ class PlaybackController: ObservableObject { UserDefaults.standard.set(false, forKey: "isPauseMediaEnabled") } - mediaController.startListening() + setupMediaControllerCallbacks() + + if isPauseMediaEnabled { + startMediaTracking() + } + } + + private func setupMediaControllerCallbacks() { mediaController.onTrackInfoReceived = { [weak self] trackInfo in self?.isMediaPlaying = trackInfo.payload.isPlaying ?? false self?.lastKnownTrackInfo = trackInfo } - mediaController.onListenerTerminated = { + mediaController.onListenerTerminated = { [weak self] in + guard let self = self, self.isPauseMediaEnabled else { return } + DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { - self.mediaController.startListening() + self.startMediaTracking() } } } + private func startMediaTracking() { + mediaController.startListening() + } + + private func stopMediaTracking() { + mediaController.stopListening() + isMediaPlaying = false + lastKnownTrackInfo = nil + wasPlayingWhenRecordingStarted = false + originalMediaAppBundleId = nil + } + func pauseMedia() async { wasPlayingWhenRecordingStarted = false originalMediaAppBundleId = nil @@ -51,18 +78,25 @@ class PlaybackController: ObservableObject { wasPlayingWhenRecordingStarted = true originalMediaAppBundleId = bundleId + + // Add a small delay to ensure state is set before sending command + try? await Task.sleep(nanoseconds: 50_000_000) + mediaController.pause() } func resumeMedia() async { + let shouldResume = wasPlayingWhenRecordingStarted + let originalBundleId = originalMediaAppBundleId + defer { wasPlayingWhenRecordingStarted = false originalMediaAppBundleId = nil } guard isPauseMediaEnabled, - wasPlayingWhenRecordingStarted, - let bundleId = originalMediaAppBundleId else { + shouldResume, + let bundleId = originalBundleId else { return } @@ -77,6 +111,8 @@ class PlaybackController: ObservableObject { return } + try? await Task.sleep(nanoseconds: 50_000_000) + mediaController.play() } @@ -91,4 +127,5 @@ extension UserDefaults { get { bool(forKey: "isPauseMediaEnabled") } set { set(newValue, forKey: "isPauseMediaEnabled") } } -} \ No newline at end of file +} + diff --git a/VoiceInk/Recorder.swift b/VoiceInk/Recorder.swift index 010dd5a..6cc1d01 100644 --- a/VoiceInk/Recorder.swift +++ b/VoiceInk/Recorder.swift @@ -77,10 +77,13 @@ class Recorder: NSObject, ObservableObject, AVAudioRecorderDelegate { hasDetectedAudioInCurrentSession = false - Task { - await playbackController.pauseMedia() - _ = await mediaController.muteSystemAudio() - } + // Coordinate media control and system audio sequentially for better reliability + await playbackController.pauseMedia() + + // Small delay to allow media command to process before muting system audio + try? await Task.sleep(nanoseconds: 100_000_000) // 100ms + + _ = await mediaController.muteSystemAudio() let deviceID = deviceManager.getCurrentDevice() if deviceID != 0 {