Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VoiceBroadcast: Manage app crash cases when recording #7188

Merged
merged 14 commits into from
Dec 23, 2022
55 changes: 55 additions & 0 deletions Riot/Categories/MXRoom+VoiceBroadcast.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
//
// 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 MatrixSDK

extension MXRoom {

func stopUncompletedVoiceBroadcastIfNeeded() {
// Detection of a potential uncompleted VoiceBroadcast
// Check whether a VoiceBroadcast is in progress on the current session for this room whereas no VoiceBroadcast Service is available.
self.lastVoiceBroadcastStateEvent { event in
guard let event = event,
event.stateKey == self.mxSession.myUserId,
let eventDeviceId = event.content[VoiceBroadcastSettings.voiceBroadcastContentKeyDeviceId] as? String,
eventDeviceId == self.mxSession.myDeviceId,
let voiceBroadcastInfo = VoiceBroadcastInfo(fromJSON: event.content),
let state = VoiceBroadcastInfoState(rawValue: voiceBroadcastInfo.state),
state != .stopped,
giomfo marked this conversation as resolved.
Show resolved Hide resolved
self.mxSession.voiceBroadcastService == nil else {
return
}

self.mxSession.getOrCreateVoiceBroadcastService(for: self) { service in
guard let service = service else {
return
}

service.stopVoiceBroadcast(lastChunkSequence: 0,
voiceBroadcastId: voiceBroadcastInfo.voiceBroadcastId ?? event.eventId) { response in
MXLog.debug("[MXRoom] stopUncompletedVoiceBroadcastIfNeeded stopVoiceBroadcast with response : \(response)")
self.mxSession.tearDownVoiceBroadcastService()
}
}
}
}

func lastVoiceBroadcastStateEvent(completion: @escaping (MXEvent?) -> Void) {
self.state { roomState in
completion(roomState?.stateEvents(with: .custom(VoiceBroadcastSettings.voiceBroadcastInfoContentKeyType))?.last)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public class RecentsListService: NSObject, RecentsListServiceProtocol {
public private(set) var query: String?
public private(set) var space: MXSpace?
private var fetchersCreated: Bool = false
private var uncompletedVoiceBroadcastCleaningDone: Bool = false

// MARK: - Fetchers

Expand Down Expand Up @@ -757,6 +758,7 @@ public class RecentsListService: NSObject, RecentsListServiceProtocol {
forSection: section,
totalCountsChanged: totalCountsChanged) }
} else {
stopUncompletedVoiceBroadcastIfNeeded()
multicastDelegate.invoke { $0.recentsListServiceDidChangeData?(self,
totalCountsChanged: totalCountsChanged) }
}
Expand Down Expand Up @@ -784,6 +786,31 @@ extension RecentsListService: MXRoomListDataFetcherDelegate {

}

// MARK: - VoiceBroadcast
extension RecentsListService {

private func stopUncompletedVoiceBroadcastIfNeeded() {
guard uncompletedVoiceBroadcastCleaningDone == false,
let breadcrumbsFetcher = breadcrumbsRoomListDataFetcher else {
return
}
// We limit for the moment the uncompleted voice broadcast cleaning to the breadcrumbs rooms list
stopUncompletedVoiceBroadcastIfNeeded(for: breadcrumbsFetcher)
uncompletedVoiceBroadcastCleaningDone = true
}

private func stopUncompletedVoiceBroadcastIfNeeded(for fetcher: MXRoomListDataFetcher) {
fetcher.data?.rooms.forEach({ roomSummary in
guard let roomSummary = roomSummary as? MXRoomSummary,
let room = roomSummary.room else {
return
}

room.stopUncompletedVoiceBroadcastIfNeeded()
})
}
}

// MARK: - FetcherTypes

private struct FetcherTypes: OptionSet {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,4 +229,7 @@ public class MockRecentsListService: NSObject, RecentsListServiceProtocol {
multicastDelegate.invoke({ $0.recentsListServiceDidChangeData?(self, totalCountsChanged: true) })
}

public func stopUncompletedVoiceBroadcastIfNeeded(for listData: MatrixSDK.MXRoomListData?) {
// nothing here
}
}
2 changes: 2 additions & 0 deletions Riot/Modules/Room/RoomViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -1082,6 +1082,8 @@ - (void)displayRoom:(MXKRoomDataSource *)dataSource
[self setupUserSuggestionViewIfNeeded];

[self updateTopBanners];

[self stopUncompletedVoiceBroadcastIfNeeded];
}

- (void)onRoomDataSourceReady
Expand Down
7 changes: 7 additions & 0 deletions Riot/Modules/Room/RoomViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -316,3 +316,10 @@ extension RoomViewController: ComposerLinkActionBridgePresenterDelegate {
composerLinkActionBridgePresenter = nil
}
}

// MARK: - VoiceBroadcast
extension RoomViewController {
@objc func stopUncompletedVoiceBroadcastIfNeeded() {
self.roomDataSource.room.stopUncompletedVoiceBroadcastIfNeeded()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -113,15 +113,17 @@ public class VoiceBroadcastAggregator {
}

private func updateState() {
self.room.state { roomState in
guard let event = roomState?.stateEvents(with: .custom(VoiceBroadcastSettings.voiceBroadcastInfoContentKeyType))?.last,
// This update is useful only in case of a live broadcast (The aggregator considers the broadcast stopped by default)
// We will consider here only the most recent voice broadcast state event
self.room.lastVoiceBroadcastStateEvent { event in
guard let event = event,
event.stateKey == self.voiceBroadcastSenderId,
let voiceBroadcastInfo = VoiceBroadcastInfo(fromJSON: event.content),
(event.eventId == self.voiceBroadcastStartEventId || voiceBroadcastInfo.voiceBroadcastId == self.voiceBroadcastStartEventId),
let state = VoiceBroadcastInfoState(rawValue: voiceBroadcastInfo.state) else {
return
}

self.delegate?.voiceBroadcastAggregator(self, didReceiveState: state)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,14 @@ public class VoiceBroadcastService: NSObject {
/// stop a voice broadcast info.
/// - Parameters:
/// - lastChunkSequence: The last sent chunk number.
/// - voiceBroadcastId: The VoiceBroadcast identifier to stop. Use it only to force stop a specific VoiceBroadcast.
/// - completion: A closure called when the operation completes. Provides the event id of the event generated on the home server on success.
func stopVoiceBroadcast(lastChunkSequence: Int, completion: @escaping (MXResponse<String?>) -> Void) {
func stopVoiceBroadcast(lastChunkSequence: Int,
voiceBroadcastId: String? = nil,
completion: @escaping (MXResponse<String?>) -> Void) {
if let voiceBroadcastId = voiceBroadcastId {
self.voiceBroadcastId = voiceBroadcastId
}
sendVoiceBroadcastInfo(lastChunkSequence: lastChunkSequence, state: VoiceBroadcastInfoState.stopped, completion: completion)
}

Expand Down Expand Up @@ -132,7 +138,7 @@ public class VoiceBroadcastService: NSObject {
case .resumed:
return [.paused, .stopped]
case .stopped:
return [.started]
return [.started, .stopped]
}
}

Expand Down
1 change: 1 addition & 0 deletions changelog.d/pr-7188.change
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Labs: VoiceBroadcast: Handle potential crash whereas a voice broadcast is in progress