@@ -521,6 +521,53 @@ public final class MediaChannel {
521521 return result
522522 ? nil : SoraError . messagingError ( reason: " failed to send message: label => \( label) " )
523523 }
524+
525+ /// MediaChannel の接続中にマイクをハードミュート有効化/無効化します
526+ /// - Parameter mute: `true` で有効化、`false` で無効化
527+ /// - Returns: 成功した場合は `nil`、失敗した場合は `Error` を返します
528+ public func setAudioHardMute( _ mute: Bool ) -> Error ? {
529+ guard state == . connected else {
530+ return SoraError . mediaChannelError (
531+ reason: " MediaChannel is not connected (state: \( state) ) " )
532+ }
533+
534+ guard configuration. audioEnabled else {
535+ return SoraError . mediaChannelError ( reason: " audioEnabled is false " )
536+ }
537+
538+ if !NativePeerChannelFactory. default. audioDeviceModuleWrapper. setAudioHardMute ( mute) {
539+ return SoraError . mediaChannelError (
540+ reason: " AudioDeviceModuleWrapper::setAudioHardMute failed " )
541+ }
542+
543+ return nil
544+ }
545+
546+ /// MediaChannel の接続中にマイクをソフトミュート有効化 / 無効化します
547+ /// - Parameter mute: `true` で有効化、`false` で無効化
548+ /// - Returns: 成功した場合は `nil`、失敗した場合は `Error` を返します
549+ public func setAudioSoftMute( _ mute: Bool ) -> Error ? {
550+ guard state == . connected else {
551+ return SoraError . mediaChannelError (
552+ reason: " MediaChannel is not connected (state: \( state) ) " )
553+ }
554+
555+ guard configuration. audioEnabled else {
556+ return SoraError . mediaChannelError ( reason: " audioEnabled is false " )
557+ }
558+
559+ guard let senderStream else {
560+ return SoraError . mediaChannelError ( reason: " senderStream is unavailable " )
561+ }
562+
563+ guard senderStream. hasAudioTrack else {
564+ return SoraError . mediaChannelError ( reason: " senderStream has no AudioTrack " )
565+ }
566+
567+ senderStream. audioEnabled = !mute
568+ Logger . debug ( type: . mediaChannel, message: " setAudioSoftMute mute= \( mute) " )
569+ return nil
570+ }
524571}
525572
526573extension MediaChannel : CustomStringConvertible {
0 commit comments