Skip to content

Commit 92b5e78

Browse files
Merge pull request #173 from boostcampwm-2024/feat/#162-mic-mute
[FEAT/#162] 마이크 뮤트 기능을 구현했습니다.
2 parents 0a6303b + 82e9fce commit 92b5e78

File tree

22 files changed

+252
-33
lines changed

22 files changed

+252
-33
lines changed

PhotoGether/DataLayer/PhotoGetherData/PhotoGetherData/ConnectionClientImpl.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ public final class ConnectionClientImpl: ConnectionClient {
7676
return capturedImage
7777
}
7878

79+
public func toggleLocalAudioTrackState(isEnable: Bool) {
80+
self.webRTCService.setLocalAudioState(isEnable)
81+
}
82+
7983
/// remoteVideoTrack과 상대방의 화면을 볼 수 있는 뷰를 바인딩합니다.
8084
public func bindRemoteVideo() {
8185
guard let remoteVideoView = remoteVideoView as? RTCMTLVideoView else { return }

PhotoGether/DataLayer/PhotoGetherData/PhotoGetherData/ConnectionRepositoryImpl.swift

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@ public final class ConnectionRepositoryImpl: ConnectionRepository {
1414
public var didEnterNewUserPublisher: AnyPublisher<(UserInfo, UIView), Never> {
1515
didEnterNewUserSubject.eraseToAnyPublisher()
1616
}
17+
private let didChangeLocalAudioTrackStateSubject = CurrentValueSubject<Bool, Never>(false)
18+
public var didChangeLocalAudioTrackStatePublisher: AnyPublisher<Bool, Never> {
19+
didChangeLocalAudioTrackStateSubject
20+
.eraseToAnyPublisher()
21+
}
22+
public var currentLocalVideoInputState: Bool {
23+
didChangeLocalAudioTrackStateSubject.value
24+
}
1725
private let _localVideoView = CapturableVideoView()
1826
public private(set) var localUserInfo: UserInfo?
1927

@@ -73,7 +81,6 @@ public final class ConnectionRepositoryImpl: ConnectionRepository {
7381
let width2 = CMVideoFormatDescriptionGetDimensions(frame2.formatDescription).width
7482
return width1 < width2
7583
}).first else { return }
76-
7784
// 가장 높은 fps 선택
7885
guard let fps = (format.videoSupportedFrameRateRanges
7986
.sorted { return $0.maxFrameRate < $1.maxFrameRate })
@@ -144,6 +151,14 @@ public final class ConnectionRepositoryImpl: ConnectionRepository {
144151
)
145152
}
146153
}
154+
155+
public func switchLocalAudioTrackState() {
156+
let presentAudioState = didChangeLocalAudioTrackStateSubject.value
157+
clients.forEach {
158+
$0.toggleLocalAudioTrackState(isEnable: !presentAudioState)
159+
}
160+
didChangeLocalAudioTrackStateSubject.send(!presentAudioState)
161+
}
147162
}
148163

149164
extension ConnectionRepositoryImpl {

PhotoGether/DataLayer/PhotoGetherData/PhotoGetherData/Interface/Service/WebRTCService.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,5 @@ public protocol WebRTCService: RTCPeerConnectionDelegate, RTCDataChannelDelegate
3434
// MARK: Audio
3535
func muteAudio()
3636
func unmuteAudio()
37+
func setLocalAudioState(_ isEnabled: Bool)
3738
}

PhotoGether/DataLayer/PhotoGetherData/PhotoGetherData/ServiceImpl/WebRTCServiceImpl.swift

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public final class WebRTCServiceImpl: NSObject, WebRTCService {
3333
]
3434
private var localVideoTrack: RTCVideoTrack?
3535
private var remoteVideoTrack: RTCVideoTrack?
36+
private var localAudioTrack: RTCAudioTrack
3637
private var localDataChannel: RTCDataChannel?
3738
private var remoteDataChannel: RTCDataChannel?
3839

@@ -42,7 +43,11 @@ public final class WebRTCServiceImpl: NSObject, WebRTCService {
4243
let audioConfig = RTCAudioSessionConfiguration.webRTC()
4344
audioConfig.category = AVAudioSession.Category.playAndRecord.rawValue
4445
audioConfig.mode = AVAudioSession.Mode.voiceChat.rawValue
45-
audioConfig.categoryOptions = [.defaultToSpeaker]
46+
audioConfig.categoryOptions = [
47+
.defaultToSpeaker, // 하단 스피커를 기본으로 설정
48+
.allowBluetooth, // 블루투스 기기의 음성 입출력 지원
49+
.allowAirPlay // AirPlay를 통해 연결된 다른 기기로 음성 출력 지원
50+
]
4651
RTCAudioSessionConfiguration.setWebRTC(audioConfig)
4752

4853
let mediaConstraint = PeerConnectionSupport.mediaConstraint()
@@ -57,16 +62,18 @@ public final class WebRTCServiceImpl: NSObject, WebRTCService {
5762
}
5863

5964
self.peerConnection = peerConnection
65+
// MARK: AudioTrack 생성
66+
self.localAudioTrack = PeerConnectionSupport.createAudioTrack()
6067

6168
super.init()
6269

6370
// MARK: DataChannel 연결
6471
self.connectDataChannel(dataChannel: createDataChannel())
6572

6673
// MARK: AudioTrack 연결
67-
let audioTrack = PeerConnectionSupport.createAudioTrack()
68-
self.connectAudioTrack(audioTrack: audioTrack)
74+
self.connectAudioTrack(audioTrack: self.localAudioTrack)
6975
self.configureAudioSession()
76+
self.localAudioTrack.isEnabled = false
7077

7178
self.peerConnection.delegate = self
7279
self.bindNoti()
@@ -222,12 +229,12 @@ public extension WebRTCServiceImpl {
222229
private func configureAudioSession() {
223230
self.rtcAudioSession.lockForConfiguration()
224231
do {
232+
225233
try self.rtcAudioSession.setCategory(
226234
.playAndRecord,
227235
mode: .voiceChat,
228236
options: .defaultToSpeaker
229237
)
230-
try self.rtcAudioSession.overrideOutputAudioPort(.speaker)
231238
try self.rtcAudioSession.setActive(true)
232239
} catch let error {
233240
PTGLogger.default.log("Error changeing AVAudioSession category: \(error)")
@@ -269,6 +276,10 @@ public extension WebRTCServiceImpl {
269276
self.setAudioEnabled(true)
270277
}
271278

279+
func setLocalAudioState(_ isEnabled: Bool) {
280+
self.localAudioTrack.isEnabled = isEnabled
281+
}
282+
272283
private func setAudioEnabled(_ isEnabled: Bool) {
273284
setTrackEnabled(RTCAudioTrack.self, isEnabled: isEnabled)
274285
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import PhotoGetherDomainInterface
2+
3+
public final class GetVoiceInputStateUseCaseImpl: GetVoiceInputStateUseCase {
4+
public func execute() -> Bool {
5+
return connectionRepository.currentLocalVideoInputState
6+
}
7+
8+
private let connectionRepository: ConnectionRepository
9+
10+
public init(connectionRepository: ConnectionRepository) {
11+
self.connectionRepository = connectionRepository
12+
}
13+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import Combine
2+
import PhotoGetherDomainInterface
3+
4+
public final class ToggleLocalMicStateUseCaseImpl: ToggleLocalMicStateUseCase {
5+
public func execute() -> AnyPublisher<Bool, Never> {
6+
connectionRepository.switchLocalAudioTrackState()
7+
return connectionRepository.didChangeLocalAudioTrackStatePublisher
8+
}
9+
10+
private let connectionRepository: ConnectionRepository
11+
12+
public init(connectionRepository: ConnectionRepository) {
13+
self.connectionRepository = connectionRepository
14+
}
15+
}

PhotoGether/DomainLayer/PhotoGetherDomain/PhotoGetherDomainInterface/ConnectionClient.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public protocol ConnectionClient {
1919
func setRemoteUserInfo(_ remoteUserInfo: UserInfo)
2020
func sendData(data: Data)
2121
func captureVideo() -> UIImage
22+
func toggleLocalAudioTrackState(isEnable: Bool)
2223
func bindLocalVideo(videoSource: RTCVideoSource?, _ localVideoView: UIView)
2324
func bindRemoteVideo()
2425
}

PhotoGether/DomainLayer/PhotoGetherDomain/PhotoGetherDomainInterface/Repository/ConnectionRepository.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,18 @@ import Combine
33

44
public protocol ConnectionRepository {
55
var didEnterNewUserPublisher: AnyPublisher<(UserInfo, UIView), Never> { get }
6+
var didChangeLocalAudioTrackStatePublisher: AnyPublisher<Bool, Never> { get }
67

78
var localUserInfo: UserInfo? { get }
89

910
var clients: [ConnectionClient] { get }
1011
var localVideoView: UIView { get }
1112
var capturedLocalVideo: UIImage? { get }
13+
var currentLocalVideoInputState: Bool { get }
1214

1315
func createRoom() -> AnyPublisher<RoomOwnerEntity, Error>
1416
func joinRoom(to roomID: String, hostID: String) -> AnyPublisher<Bool, Error>
1517
func sendOffer() async throws
16-
func stopCaptureLocalVideo() -> Bool
18+
func stopCaptureLocalVideo() -> Bool
19+
func switchLocalAudioTrackState()
1720
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
public protocol GetVoiceInputStateUseCase {
2+
func execute() -> Bool
3+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import Combine
2+
3+
public protocol ToggleLocalMicStateUseCase {
4+
func execute() -> AnyPublisher<Bool, Never>
5+
}

0 commit comments

Comments
 (0)