From 8b87055aa3de0902899ba4fbbeb994b8c80ad424 Mon Sep 17 00:00:00 2001 From: yostyle Date: Tue, 11 Oct 2022 03:10:37 +0200 Subject: [PATCH] Refactoring --- Riot/Modules/Room/RoomViewController.m | 26 +++-- .../MXSession+VoiceBroadcast.swift | 12 +- .../UserVoiceBroadcastService.swift | 55 --------- .../UserVoiceBroadcastServiceProtocol.swift | 30 ----- .../UserVoiceBroadcastServiceProvider.swift | 66 ----------- .../VoiceBroadcastEventContent.h | 0 .../VoiceBroadcastEventContent.m | 0 .../VoiceBroadcastService.swift | 76 ++++++------- .../VoiceBroadcastServiceError.swift | 0 .../VoiceBroadcastServiceProvider.swift | 107 ++++++++++++++++++ 10 files changed, 167 insertions(+), 205 deletions(-) delete mode 100644 Riot/Modules/VoiceBroadcast/UserVoiceBroadcastService.swift delete mode 100644 Riot/Modules/VoiceBroadcast/UserVoiceBroadcastServiceProtocol.swift delete mode 100644 Riot/Modules/VoiceBroadcast/UserVoiceBroadcastServiceProvider.swift rename Riot/Modules/VoiceBroadcast/{ => VoiceBroadcastSDK}/VoiceBroadcastEventContent.h (100%) rename Riot/Modules/VoiceBroadcast/{ => VoiceBroadcastSDK}/VoiceBroadcastEventContent.m (100%) rename Riot/Modules/VoiceBroadcast/{ => VoiceBroadcastSDK}/VoiceBroadcastService.swift (95%) rename Riot/Modules/VoiceBroadcast/{ => VoiceBroadcastSDK}/VoiceBroadcastServiceError.swift (100%) create mode 100644 Riot/Modules/VoiceBroadcast/VoiceBroadcastServiceProvider.swift diff --git a/Riot/Modules/Room/RoomViewController.m b/Riot/Modules/Room/RoomViewController.m index 8d21792996..c8a95e95c7 100644 --- a/Riot/Modules/Room/RoomViewController.m +++ b/Riot/Modules/Room/RoomViewController.m @@ -2317,15 +2317,23 @@ - (void)setupActions { } MXSession* session = self.roomDataSource.mxSession; - - [session setupUserVoiceBroadcastServiceFor:self.roomDataSource.room]; - NSInteger voiceBroadcastServiceState = session.userVoiceBroadcastService.state; - if (voiceBroadcastServiceState == StateStopped) { - [session.userVoiceBroadcastService start]; - } else { - [session.userVoiceBroadcastService stop]; - } - + [session getOrCreateVoiceBroadcastServiceFor:self.roomDataSource.room completion:^(VoiceBroadcastService *voiceBroadcastService) { + if (voiceBroadcastService) { + if ([[voiceBroadcastService getState] isEqualToString:@"stopped"]) { + [session.voiceBroadcastService startVoiceBroadcastWithSuccess:^(NSString * _Nullable success) { + + } failure:^(NSError * _Nonnull error) { + + }]; + } else { + [session.voiceBroadcastService stopVoiceBroadcastWithSuccess:^(NSString * _Nullable success) { + + } failure:^(NSError * _Nonnull error) { + + }]; + } + } + }]; }]]; } roomInputView.actionsBar.actionItems = actionItems; diff --git a/Riot/Modules/VoiceBroadcast/MXSession+VoiceBroadcast.swift b/Riot/Modules/VoiceBroadcast/MXSession+VoiceBroadcast.swift index a0b29bdf53..0e23461790 100644 --- a/Riot/Modules/VoiceBroadcast/MXSession+VoiceBroadcast.swift +++ b/Riot/Modules/VoiceBroadcast/MXSession+VoiceBroadcast.swift @@ -19,13 +19,13 @@ import MatrixSDK extension MXSession { - /// Convenient getter to retrieve UserVoiceBroadcastService associated to the session - @objc var userVoiceBroadcastService: UserVoiceBroadcastServiceProtocol? { - return UserVoiceBroadcastServiceProvider.shared.userVoiceBroadcastService + /// Convenient getter to retrieve VoiceBroadcastService associated to the session + @objc var voiceBroadcastService: VoiceBroadcastService? { + return VoiceBroadcastServiceProvider.shared.voiceBroadcastService } - /// Initialize UserVoiceBroadcastService - @objc public func setupUserVoiceBroadcastService(for room: MXRoom) { - UserVoiceBroadcastServiceProvider.shared.setupUserVoiceBroadcastServiceIfNeeded(for: room) + /// Initialize VoiceBroadcastService + @objc public func getOrCreateVoiceBroadcastService(for room: MXRoom, completion: @escaping (VoiceBroadcastService?) -> Void) { + VoiceBroadcastServiceProvider.shared.getOrCreateVoiceBroadcastService(for: room, completion: completion) } } diff --git a/Riot/Modules/VoiceBroadcast/UserVoiceBroadcastService.swift b/Riot/Modules/VoiceBroadcast/UserVoiceBroadcastService.swift deleted file mode 100644 index 3cfa629170..0000000000 --- a/Riot/Modules/VoiceBroadcast/UserVoiceBroadcastService.swift +++ /dev/null @@ -1,55 +0,0 @@ -// -// Copyright 2022 New Vector Ltd -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import Foundation - -/// UserVoiceBroadcastService handles live VoiceBroadcast sharing for the current user -class UserVoiceBroadcastService: UserVoiceBroadcastServiceProtocol { - - // MARK: - Constants - - // MARK: - Properties - - // MARK: Private - - private var voiceBroadcastService: VoiceBroadcastService - - // MARK: Public - - // MARK: - Setup - - init(room: MXRoom) { - self.voiceBroadcastService = VoiceBroadcastService(room: room) - } - - // MARK: - Public - - func start() { - voiceBroadcastService.startVoiceBroadcast { (response) in - - } - } - - func stop() { - voiceBroadcastService.stopVoiceBroadcast { (response) in - - } - } - - func state() -> VoiceBroadcastService.State { - return voiceBroadcastService.state - } -} diff --git a/Riot/Modules/VoiceBroadcast/UserVoiceBroadcastServiceProtocol.swift b/Riot/Modules/VoiceBroadcast/UserVoiceBroadcastServiceProtocol.swift deleted file mode 100644 index 5dff4b71e7..0000000000 --- a/Riot/Modules/VoiceBroadcast/UserVoiceBroadcastServiceProtocol.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// Copyright 2022 New Vector Ltd -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import Foundation - -/// Describes service that monitor current user voice broadcast -@objc protocol UserVoiceBroadcastServiceProtocol { - - /// Start monitoring of the user voice broadcast recording. - func start() - - /// Stop monitoring user voice broadcast - func stop() - - /// State monitoring user voice broadcast - func state() -> VoiceBroadcastService.State -} diff --git a/Riot/Modules/VoiceBroadcast/UserVoiceBroadcastServiceProvider.swift b/Riot/Modules/VoiceBroadcast/UserVoiceBroadcastServiceProvider.swift deleted file mode 100644 index db155fe3d1..0000000000 --- a/Riot/Modules/VoiceBroadcast/UserVoiceBroadcastServiceProvider.swift +++ /dev/null @@ -1,66 +0,0 @@ -// -// Copyright 2022 New Vector Ltd -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import Foundation - -/// UserVoiceBroadcastServiceProvider to setup UserVoiceBroadcastService and retrieve the existing UserVoiceBroadcastService. -class UserVoiceBroadcastServiceProvider { - - // MARK: - Constants - - static let shared = UserVoiceBroadcastServiceProvider() - - // MARK: - Properties - - // UserVoiceBroadcastService per session - public var userVoiceBroadcastService: UserVoiceBroadcastService? = nil - - // MARK: - Setup - - private init() {} - - // MARK: - Public - - public func setupUserVoiceBroadcastServiceIfNeeded(for room: MXRoom) { - - guard self.userVoiceBroadcastService == nil else { - return - } - - self.setupUserVoiceBroadcastService(for: room) - } - - public func tearDownUserVoiceBroadcastService() { - - self.userVoiceBroadcastService = nil - - MXLog.debug("Stop monitoring voice broadcast recording") - } - - // MARK: - Private - - // MARK: UserVoiceBroadcastService setup - - private func setupUserVoiceBroadcastService(for room: MXRoom) { - - let userVoiceBroadcastService = UserVoiceBroadcastService(room: room) - - self.userVoiceBroadcastService = userVoiceBroadcastService - - MXLog.debug("Start monitoring voice broadcast recording") - } - -} diff --git a/Riot/Modules/VoiceBroadcast/VoiceBroadcastEventContent.h b/Riot/Modules/VoiceBroadcast/VoiceBroadcastSDK/VoiceBroadcastEventContent.h similarity index 100% rename from Riot/Modules/VoiceBroadcast/VoiceBroadcastEventContent.h rename to Riot/Modules/VoiceBroadcast/VoiceBroadcastSDK/VoiceBroadcastEventContent.h diff --git a/Riot/Modules/VoiceBroadcast/VoiceBroadcastEventContent.m b/Riot/Modules/VoiceBroadcast/VoiceBroadcastSDK/VoiceBroadcastEventContent.m similarity index 100% rename from Riot/Modules/VoiceBroadcast/VoiceBroadcastEventContent.m rename to Riot/Modules/VoiceBroadcast/VoiceBroadcastSDK/VoiceBroadcastEventContent.m diff --git a/Riot/Modules/VoiceBroadcast/VoiceBroadcastService.swift b/Riot/Modules/VoiceBroadcast/VoiceBroadcastSDK/VoiceBroadcastService.swift similarity index 95% rename from Riot/Modules/VoiceBroadcast/VoiceBroadcastService.swift rename to Riot/Modules/VoiceBroadcast/VoiceBroadcastSDK/VoiceBroadcastService.swift index 0861c3826e..4c1655aca1 100644 --- a/Riot/Modules/VoiceBroadcast/VoiceBroadcastService.swift +++ b/Riot/Modules/VoiceBroadcast/VoiceBroadcastSDK/VoiceBroadcastService.swift @@ -33,39 +33,29 @@ public class VoiceBroadcastService: NSObject { // MARK: - Properties private var voiceBroadcastInfoEventId: String? - private unowned let room: MXRoom + public let room: MXRoom public private(set) var state: State // MARK: - Setup - public init(room: MXRoom) { + public init(room: MXRoom, state: State) { self.room = room - state = State.stopped + self.state = state } // MARK: - Constants - @objc public enum State: Int { + public enum State: String { case started case paused case resumed case stopped - - /// A string representation of the result. - var description: String { - switch self { - case .started: - return "started" - case .paused: - return "paused" - case .resumed: - return "resumed" - case .stopped: - return "stopped" - } - } } + // MARK: - Public + + // MARK: Voice broadcast info + /// Start a voice broadcast. /// - Parameters: /// - completion: A closure called when the operation completes. Provides the event id of the event generated on the home server on success. @@ -106,6 +96,34 @@ public class VoiceBroadcastService: NSObject { return sendVoiceBroadcastInfo(state: State.stopped, completion: completion) } + func getState() -> String { + return self.state.rawValue + } + + // MARK: Voice broadcast chunk + + /// Send a bunch of a voice broadcast. + /// + /// While sending, a fake event will be echoed in the messages list. + /// Once complete, this local echo will be replaced by the event saved by the homeserver. + /// + /// - Parameters: + /// - audioFileLocalURL: the local filesystem path of the audio file to send. + /// - mimeType: (optional) the mime type of the file. Defaults to `audio/ogg` + /// - duration: the length of the voice message in milliseconds + /// - samples: an array of floating point values normalized to [0, 1], boxed within NSNumbers + /// - success: A block object called when the operation succeeds. It returns the event id of the event generated on the homeserver + /// - failure: A block object called when the operation fails. + func sendChunkOfVoiceBroadcast(audioFileLocalURL: URL, mimeType: String?, duration: UInt, samples: [Float]?, success:@escaping ((String?) -> Void), failure:@escaping ((Error?) -> Void)) { + guard let voiceBroadcastInfoEventId = self.voiceBroadcastInfoEventId else { + return failure(VoiceBroadcastServiceError.notStarted) + } + + self.room.sendChunkOfVoiceBroadcast(localURL: audioFileLocalURL, voiceBroadcastInfoEventId: voiceBroadcastInfoEventId, mimeType: mimeType, duration: duration, samples: samples, success: success, failure: failure) + } + + // MARK: - Private + private func sendVoiceBroadcastInfo(state: State, completion: @escaping (MXResponse) -> Void) -> MXHTTPOperation? { guard let userId = self.room.mxSession.myUserId else { completion(.failure(VoiceBroadcastServiceError.missingUserId)) @@ -115,7 +133,7 @@ public class VoiceBroadcastService: NSObject { let stateKey = userId let voiceBroadcastContent = VoiceBroadcastEventContent() - voiceBroadcastContent.state = state.description + voiceBroadcastContent.state = state.rawValue if state != State.started { guard let voiceBroadcastInfoEventId = self.voiceBroadcastInfoEventId else { @@ -145,26 +163,6 @@ public class VoiceBroadcastService: NSObject { } } } - - /// Send a bunch of a voice broadcast. - /// - /// While sending, a fake event will be echoed in the messages list. - /// Once complete, this local echo will be replaced by the event saved by the homeserver. - /// - /// - Parameters: - /// - audioFileLocalURL: the local filesystem path of the audio file to send. - /// - mimeType: (optional) the mime type of the file. Defaults to `audio/ogg` - /// - duration: the length of the voice message in milliseconds - /// - samples: an array of floating point values normalized to [0, 1], boxed within NSNumbers - /// - success: A block object called when the operation succeeds. It returns the event id of the event generated on the homeserver - /// - failure: A block object called when the operation fails. - func sendChunkOfVoiceBroadcast(audioFileLocalURL: URL, mimeType: String?, duration: UInt, samples: [Float]?, success:@escaping ((String?) -> Void), failure:@escaping ((Error?) -> Void)) { - guard let voiceBroadcastInfoEventId = self.voiceBroadcastInfoEventId else { - return failure(VoiceBroadcastServiceError.notStarted) - } - - self.room.sendChunkOfVoiceBroadcast(localURL: audioFileLocalURL, voiceBroadcastInfoEventId: voiceBroadcastInfoEventId, mimeType: mimeType, duration: duration, samples: samples, success: success, failure: failure) - } } // MARK: - Objective-C interface diff --git a/Riot/Modules/VoiceBroadcast/VoiceBroadcastServiceError.swift b/Riot/Modules/VoiceBroadcast/VoiceBroadcastSDK/VoiceBroadcastServiceError.swift similarity index 100% rename from Riot/Modules/VoiceBroadcast/VoiceBroadcastServiceError.swift rename to Riot/Modules/VoiceBroadcast/VoiceBroadcastSDK/VoiceBroadcastServiceError.swift diff --git a/Riot/Modules/VoiceBroadcast/VoiceBroadcastServiceProvider.swift b/Riot/Modules/VoiceBroadcast/VoiceBroadcastServiceProvider.swift new file mode 100644 index 0000000000..789ea8ba23 --- /dev/null +++ b/Riot/Modules/VoiceBroadcast/VoiceBroadcastServiceProvider.swift @@ -0,0 +1,107 @@ +// +// Copyright 2022 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation + +/// VoiceBroadcastServiceProvider to setup VoiceBroadcastService or retrieve the existing VoiceBroadcastService. +class VoiceBroadcastServiceProvider { + + // MARK: - Constants + + static let shared = VoiceBroadcastServiceProvider() + + // MARK: - Properties + + // VoiceBroadcastService in the current session + public var voiceBroadcastService: VoiceBroadcastService? = nil + + // MARK: - Setup + + private init() {} + + // MARK: - Public + + public func getOrCreateVoiceBroadcastService(for room: MXRoom, completion: @escaping (VoiceBroadcastService?) -> Void) { + guard let voiceBroadcastService = self.voiceBroadcastService else { + self.setupVoiceBroadcastService(for: room) { voiceBroadcastService in + completion(voiceBroadcastService) + } + return + } + + if voiceBroadcastService.room.roomId == room.roomId { + completion(voiceBroadcastService) + } + + completion(nil) + } + + public func tearDownVoiceBroadcastService() { + + self.voiceBroadcastService = nil + + MXLog.debug("Stop monitoring voice broadcast recording") + } + + // MARK: - Private + + // MARK: VoiceBroadcastService setup + + private func createVoiceBroadcastService(for room: MXRoom, state: VoiceBroadcastService.State) { + + let voiceBroadcastService = VoiceBroadcastService(room: room, state: VoiceBroadcastService.State.stopped) + + self.voiceBroadcastService = voiceBroadcastService + + MXLog.debug("Start monitoring voice broadcast recording") + } + + private func setupVoiceBroadcastService(for room: MXRoom, completion: @escaping (VoiceBroadcastService?) -> Void) { + self.getLastVoiceBroadcastInfo(for: room) { event in + guard let voiceBroadcastInfoEvent = event else { + self.createVoiceBroadcastService(for: room, state: VoiceBroadcastService.State.stopped) + completion(self.voiceBroadcastService) + return + } + + guard let voiceBroadcastInfoEventContent = VoiceBroadcastEventContent(fromJSON: voiceBroadcastInfoEvent.content) else { + self.createVoiceBroadcastService(for: room, state: VoiceBroadcastService.State.stopped) + completion(self.voiceBroadcastService) + return + } + + if voiceBroadcastInfoEventContent.state == VoiceBroadcastService.State.stopped.rawValue { + self.createVoiceBroadcastService(for: room, state: VoiceBroadcastService.State.stopped) + completion(self.voiceBroadcastService) + } else if voiceBroadcastInfoEvent.stateKey == room.mxSession.myUserId { + self.createVoiceBroadcastService(for: room, state: VoiceBroadcastService.State(rawValue: voiceBroadcastInfoEventContent.state) ?? VoiceBroadcastService.State.stopped) + completion(self.voiceBroadcastService) + } else { + completion(nil) + } + } + } + + /// Get latest voice broadcast info in a room + /// - Parameters: + /// - roomId: The room id of the room + /// - completion: Give the lastest voice broadcast info of the room. + private func getLastVoiceBroadcastInfo(for room: MXRoom, completion: @escaping (MXEvent?) -> Void) { + room.state { roomState in + completion(roomState?.stateEvents(with: .custom(VoiceBroadcastSettings.eventType))?.last ?? nil) + } + } +}