diff --git a/Examples/iOS/IngestViewController.swift b/Examples/iOS/IngestViewController.swift index 3ea5a4f6e..509c627fa 100644 --- a/Examples/iOS/IngestViewController.swift +++ b/Examples/iOS/IngestViewController.swift @@ -24,7 +24,7 @@ final class IngestViewController: UIViewController { private var retryCount: Int = 0 private var preferedStereo = false private let netStreamSwitcher: HKStreamSwitcher = .init() - private lazy var mixer = MediaMixer() + private lazy var mixer = MediaMixer(multiCamSessionEnabled: true, multiTrackAudioMixingEnabled: false, useManualCapture: true) private lazy var audioCapture: AudioCapture = { let audioCapture = AudioCapture() audioCapture.delegate = self @@ -37,9 +37,7 @@ final class IngestViewController: UIViewController { super.viewDidLoad() Task { // If you want to use the multi-camera feature, please make create a MediaMixer with a multiCamSession mode. - // ``` - // let mixer = MediaMixer(multiCamSessionEnabled: true, multiTrackAudioMixingEnabled: false) - // ``` + // let mixer = MediaMixer(multiCamSessionEnabled: true) if let orientation = DeviceUtil.videoOrientation(by: UIApplication.shared.statusBarOrientation) { await mixer.setVideoOrientation(orientation) } @@ -83,6 +81,7 @@ final class IngestViewController: UIViewController { try? await mixer.attachVideo(front, track: 1) { videoUnit in videoUnit.isVideoMirrored = true } + await mixer.startRunning() } NotificationCenter.default.addObserver(self, selector: #selector(on(_:)), name: UIDevice.orientationDidChangeNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(didInterruptionNotification(_:)), name: AVAudioSession.interruptionNotification, object: nil) @@ -94,6 +93,7 @@ final class IngestViewController: UIViewController { super.viewWillDisappear(animated) Task { await netStreamSwitcher.close() + await mixer.stopRunning() try? await mixer.attachAudio(nil) try? await mixer.attachVideo(nil, track: 0) try? await mixer.attachVideo(nil, track: 1) diff --git a/HaishinKit/Sources/Mixer/MediaMixer.swift b/HaishinKit/Sources/Mixer/MediaMixer.swift index 304bc9ea4..5702eef99 100644 --- a/HaishinKit/Sources/Mixer/MediaMixer.swift +++ b/HaishinKit/Sources/Mixer/MediaMixer.swift @@ -92,10 +92,11 @@ public final actor MediaMixer { public private(set) var isRunning = false private var outputs: [any MediaMixerOutput] = [] + private var cancellables: Set = [] + private let useManualCapture: Bool private lazy var audioIO = AudioCaptureUnit(session) private lazy var videoIO = VideoCaptureUnit(session) private lazy var session = CaptureSession() - private var cancellables: Set = [] @ScreenActor private lazy var displayLink = DisplayLinkChoreographer() @@ -105,21 +106,35 @@ public final actor MediaMixer { /// - Parameters: /// - multiCamSessionEnabled: Specifies the AVCaptureMultiCamSession enabled. /// - multiTrackAudioMixingEnabled: Specifies the feature to mix multiple audio tracks. For example, it is possible to mix .appAudio and .micAudio from ReplayKit. - public init(multiCamSessionEnabled: Bool = true, multiTrackAudioMixingEnabled: Bool = false) { + /// - useManualCapture: Specifies whether to start capturing manually. #1642 + public init( + multiCamSessionEnabled: Bool = true, + multiTrackAudioMixingEnabled: Bool = false, + useManualCapture: Bool = false + ) { + self.useManualCapture = useManualCapture Task { - await setMultiCamSessionEnabled(multiCamSessionEnabled) - await setMultiTrackAudioMixingEnabled(multiTrackAudioMixingEnabled) - await startRunning() + await session.isMultiCamSessionEnabled = true + await audioIO.isMultiTrackAudioMixingEnabled = multiCamSessionEnabled + if !useManualCapture { + await startRunning() + } } } + #else /// Creates a new instance. /// /// - Parameters: /// - multiTrackAudioMixingEnabled: Specifies the feature to mix multiple audio tracks. For example, it is possible to mix .appAudio and .micAudio from ReplayKit. - public init(multiTrackAudioMixingEnabled: Bool = false) { + /// - useManualCapture: Specifies whether to start capturing manually. #1642 + public init( + multiTrackAudioMixingEnabled: Bool = false, + useManualCapture: Bool = false + ) { + self.useManualCapture = useManualCapture Task { - await setMultiTrackAudioMixingEnabled(multiTrackAudioMixingEnabled) + await audioIO.isMultiTrackAudioMixingEnabled = multiTrackAudioMixingEnabled await startRunning() } } @@ -128,9 +143,8 @@ public final actor MediaMixer { /// Attaches a video device. /// /// If you want to use the multi-camera feature, please make create a MediaMixer with a multiCamSession mode for iOS. - /// ``` /// let mixer = MediaMixer(multiCamSessionEnabled: true, multiTrackAudioMixingEnabled: false) - /// ``` + /// @available(tvOS 17.0, *) public func attachVideo(_ device: AVCaptureDevice?, track: UInt8 = 0, configuration: VideoDeviceConfigurationBlock? = nil) async throws { return try await withCheckedThrowingContinuation { continuation in @@ -294,7 +308,7 @@ public final actor MediaMixer { } outputs.append(output) if #available(tvOS 17.0, *) { - if !isCapturing { + if !isCapturing && !useManualCapture { startCapturing() } } @@ -307,16 +321,6 @@ public final actor MediaMixer { } } - #if os(iOS) || os(tvOS) - func setMultiCamSessionEnabled(_ multiCamSessionEnabled: Bool) { - session.isMultiCamSessionEnabled = multiCamSessionEnabled - } - #endif - - func setMultiTrackAudioMixingEnabled(_ multiTrackAudioMixingEnabled: Bool) { - audioIO.isMultiTrackAudioMixingEnabled = multiTrackAudioMixingEnabled - } - func setVideoRenderingMode(_ mode: VideoMixerSettings.Mode) { switch mode { case .passthrough: @@ -391,6 +395,9 @@ extension MediaMixer: AsyncRunner { } } setVideoRenderingMode(videoMixerSettings.mode) + if useManualCapture { + session.startRunning() + } #if os(iOS) || os(tvOS) || os(visionOS) NotificationCenter .Publisher(center: .default, name: UIApplication.didEnterBackgroundNotification, object: nil) @@ -416,6 +423,9 @@ extension MediaMixer: AsyncRunner { return } isRunning = false + if useManualCapture { + session.stopRunning() + } cancellables.forEach { $0.cancel() } cancellables.removeAll() Task { @ScreenActor in