@@ -233,9 +233,8 @@ public final class MediaChannel {
233233
234234 private let manager : Sora
235235
236- // 映像ハードミュートの同時呼び出しを防ぐための Actor です
237- // CameraVideoCapturer.current を操作するため、 MediaChannel 間でも排他実行します
238- // また、CameraVideoCapturer.current はグローバルのため static にしています
236+ // 映像ハードミュートの同時呼び出しを直列化するための Actor です
237+ // MediaChannel 間の排他実行を保証するため static にしています
239238 private static let videoHardMuteActor = VideoHardMuteActor ( )
240239
241240 // MARK: - インスタンスの生成
@@ -650,7 +649,7 @@ public final class MediaChannel {
650649 /// - Parameter mute: `true` で有効化、`false` で無効化
651650 /// - Returns: 成功した場合は `nil`、失敗した場合は `SoraError.mediaChannelError` を返します
652651 public func setAudioHardMute( _ mute: Bool ) -> Error ? {
653- // 接続中か
652+ // 接続されているか
654653 guard state == . connected else {
655654 return SoraError . mediaChannelError (
656655 reason: " MediaChannel is not connected (state: \( state) ) " )
@@ -680,7 +679,7 @@ public final class MediaChannel {
680679 /// - Parameter mute: `true` で有効化、`false` で無効化
681680 /// - Returns: 成功した場合は `nil`、失敗した場合は `SoraError.mediaChannelError` を返します
682681 public func setAudioSoftMute( _ mute: Bool ) -> Error ? {
683- // 接続中か
682+ // 接続されているか
684683 guard state == . connected else {
685684 return SoraError . mediaChannelError (
686685 reason: " MediaChannel is not connected (state: \( state) ) " )
@@ -713,34 +712,17 @@ public final class MediaChannel {
713712 }
714713
715714 /// MediaChannel の接続中に映像をソフトミュート有効化 / 無効化します
715+ /// 黒塗りフレームが送信される状態になります
716716 ///
717717 /// - Parameter mute: `true` で有効化、`false` で無効化
718718 /// - Returns: 成功した場合は `nil`、失敗した場合は `SoraError.mediaChannelError` を返します
719719 public func setVideoSoftMute( _ mute: Bool ) -> Error ? {
720- // 接続中か
721- guard state == . connected else {
722- return SoraError . mediaChannelError (
723- reason: " MediaChannel is not connected (state: \( state) ) " )
724- }
725-
726- // 接続設定で映像が有効になっているか
727- guard configuration. videoEnabled else {
728- return SoraError . mediaChannelError ( reason: " videoEnabled is false " )
729- }
730-
731- // 接続設定で配信側ロールになっているか
732- guard configuration. isSender else {
733- return SoraError . mediaChannelError ( reason: " role is not sender " )
734- }
735-
736- // 送信ストリームが有効か
737- guard let senderStream else {
738- return SoraError . mediaChannelError ( reason: " senderStream is unavailable " )
739- }
740-
741- // ローカル映像トラックが存在するか
742- guard senderStream. hasVideoTrack else {
743- return SoraError . mediaChannelError ( reason: " senderStream has no VideoTrack " )
720+ let senderStream : MediaStream
721+ switch requireSenderStreamForVideoMute ( ) {
722+ case . failure( let error) :
723+ return error
724+ case . success( let stream) :
725+ senderStream = stream
744726 }
745727
746728 // ローカル映像トラックの有効/無効を切り替えます
@@ -751,6 +733,9 @@ public final class MediaChannel {
751733
752734 /// MediaChannel の接続中に映像をハードミュート有効化 / 無効化します
753735 ///
736+ /// 端末カメラ利用が有効になっている必要があります
737+ /// 外部入力や別キャプチャ経路には対応していません
738+ ///
754739 /// 内部で Actor により、操作を排他実行します。
755740 /// 同時に呼び出された場合は Actor 側で `SoraError.mediaChannelError` がスローされます
756741 ///
@@ -761,19 +746,12 @@ public final class MediaChannel {
761746 /// - Parameter mute: `true` で有効化、`false` で無効化
762747 /// - Throws: エラー時は `SoraError.cameraError` または `SoraError.mediaChannelError` がスローされます
763748 public func setVideoHardMute( _ mute: Bool ) async throws {
764- // 接続中か
765- guard state == . connected else {
766- throw SoraError . mediaChannelError ( reason: " MediaChannel is not connected (state: \( state) ) " )
767- }
768-
769- // 接続設定で映像が有効になっているか
770- guard configuration. videoEnabled else {
771- throw SoraError . mediaChannelError ( reason: " videoEnabled is false " )
772- }
773-
774- // 接続設定で配信側ロールになっているか
775- guard configuration. isSender else {
776- throw SoraError . mediaChannelError ( reason: " role is not sender " )
749+ let senderStream : MediaStream
750+ switch requireSenderStreamForVideoMute ( ) {
751+ case . failure( let error) :
752+ throw error
753+ case . success( let stream) :
754+ senderStream = stream
777755 }
778756
779757 // 接続設定でカメラ利用が有効になっているか
@@ -782,16 +760,6 @@ public final class MediaChannel {
782760 throw SoraError . mediaChannelError ( reason: " cameraSettings.isEnabled is false " )
783761 }
784762
785- // 送信ストリームが有効か
786- guard let senderStream else {
787- throw SoraError . mediaChannelError ( reason: " senderStream is unavailable " )
788- }
789-
790- // ローカル映像トラックが存在するか
791- guard senderStream. hasVideoTrack else {
792- throw SoraError . mediaChannelError ( reason: " senderStream has no VideoTrack " )
793- }
794-
795763 if mute {
796764 // 黒塗りフレーム送出 -> ハードミュート有効化の順になるようにします
797765 senderStream. videoEnabled = false
@@ -803,6 +771,40 @@ public final class MediaChannel {
803771 }
804772 Logger . debug ( type: . mediaChannel, message: " setVideoHardMute mute= \( mute) " )
805773 }
774+
775+ // 映像ミュートのための接続状況や接続設定のチェックを実行した上で送信ストリームを取得します
776+ //
777+ // チェックを全て通過した場合は .success で送信ストリームを返します
778+ // 問題があった場合は .failure で SoraError.mediaChannelError を返します
779+ private func requireSenderStreamForVideoMute( ) -> Result < MediaStream , Error > {
780+ // 接続されているか
781+ guard state == . connected else {
782+ return . failure(
783+ SoraError . mediaChannelError ( reason: " MediaChannel is not connected (state: \( state) ) " ) )
784+ }
785+
786+ // 接続設定で映像が有効になっているか
787+ guard configuration. videoEnabled else {
788+ return . failure( SoraError . mediaChannelError ( reason: " videoEnabled is false " ) )
789+ }
790+
791+ // 接続設定で配信側ロールになっているか
792+ guard configuration. isSender else {
793+ return . failure( SoraError . mediaChannelError ( reason: " role is not sender " ) )
794+ }
795+
796+ // 送信ストリームが有効か
797+ guard let senderStream else {
798+ return . failure( SoraError . mediaChannelError ( reason: " senderStream is unavailable " ) )
799+ }
800+
801+ // 送信ストリームに映像トラックが含まれているか
802+ guard senderStream. hasVideoTrack else {
803+ return . failure( SoraError . mediaChannelError ( reason: " senderStream has no VideoTrack " ) )
804+ }
805+
806+ return . success( senderStream)
807+ }
806808}
807809
808810extension MediaChannel : CustomStringConvertible {
0 commit comments