mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-21 17:12:45 +02:00
#4655 - Allowing voice message playback to be controlled from the lock screen or the control center.
This commit is contained in:
committed by
Stefan Ceriu
parent
c4351e1e67
commit
949551c8da
@@ -15,20 +15,44 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import MediaPlayer
|
||||
|
||||
@objc public class VoiceMessageMediaServiceProvider: NSObject, VoiceMessageAudioPlayerDelegate, VoiceMessageAudioRecorderDelegate {
|
||||
|
||||
private enum Constants {
|
||||
static let roomAvatarImageSize: CGFloat = 100.0
|
||||
static let roomAvatarFontSize: CGFloat = 40.0
|
||||
}
|
||||
|
||||
private let audioPlayers: NSMapTable<NSString, VoiceMessageAudioPlayer>
|
||||
private let audioRecorders: NSHashTable<VoiceMessageAudioRecorder>
|
||||
|
||||
// Retain currently playing audio player so it doesn't stop playing on timeline cell reusage
|
||||
private var displayLink: CADisplayLink!
|
||||
|
||||
// Retain currently playing audio player so it doesn't stop playing on timeline cell reuse
|
||||
private var currentlyPlayingAudioPlayer: VoiceMessageAudioPlayer?
|
||||
|
||||
@objc public static let sharedProvider = VoiceMessageMediaServiceProvider()
|
||||
|
||||
private var roomAvatar: UIImage?
|
||||
@objc public var currentRoomSummary: MXRoomSummary? {
|
||||
didSet {
|
||||
roomAvatar = AvatarGenerator.generateAvatar(forMatrixItem: currentRoomSummary?.roomId,
|
||||
withDisplayName: currentRoomSummary?.displayname,
|
||||
size: Constants.roomAvatarImageSize,
|
||||
andFontSize: Constants.roomAvatarFontSize)
|
||||
}
|
||||
}
|
||||
|
||||
private override init() {
|
||||
audioPlayers = NSMapTable<NSString, VoiceMessageAudioPlayer>(valueOptions: .weakMemory)
|
||||
audioRecorders = NSHashTable<VoiceMessageAudioRecorder>(options: .weakMemory)
|
||||
|
||||
super.init()
|
||||
|
||||
displayLink = CADisplayLink(target: WeakTarget(self, selector: #selector(handleDisplayLinkTick)), selector: WeakTarget.triggerSelector)
|
||||
displayLink.isPaused = true
|
||||
displayLink.add(to: .current, forMode: .common)
|
||||
}
|
||||
|
||||
@objc func audioPlayerForIdentifier(_ identifier: String) -> VoiceMessageAudioPlayer {
|
||||
@@ -57,12 +81,21 @@ import Foundation
|
||||
|
||||
func audioPlayerDidStartPlaying(_ audioPlayer: VoiceMessageAudioPlayer) {
|
||||
currentlyPlayingAudioPlayer = audioPlayer
|
||||
setUpRemoteCommandCenter()
|
||||
stopAllServicesExcept(audioPlayer)
|
||||
}
|
||||
|
||||
func audioPlayerDidStopPlaying(_ audioPlayer: VoiceMessageAudioPlayer) {
|
||||
if currentlyPlayingAudioPlayer == audioPlayer {
|
||||
currentlyPlayingAudioPlayer = nil
|
||||
tearDownRemoteCommandCenter()
|
||||
}
|
||||
}
|
||||
|
||||
func audioPlayerDidFinishPlaying(_ audioPlayer: VoiceMessageAudioPlayer) {
|
||||
if currentlyPlayingAudioPlayer == audioPlayer {
|
||||
currentlyPlayingAudioPlayer = nil
|
||||
tearDownRemoteCommandCenter()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,4 +129,90 @@ import Foundation
|
||||
audioPlayer.unloadContent()
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func handleDisplayLinkTick() {
|
||||
updateNowPlayingInfoCenter()
|
||||
}
|
||||
|
||||
private func setUpRemoteCommandCenter() {
|
||||
displayLink.isPaused = false
|
||||
|
||||
UIApplication.shared.beginReceivingRemoteControlEvents()
|
||||
|
||||
let commandCenter = MPRemoteCommandCenter.shared()
|
||||
|
||||
commandCenter.playCommand.isEnabled = true
|
||||
commandCenter.playCommand.removeTarget(nil)
|
||||
commandCenter.playCommand.addTarget { [weak self] event in
|
||||
guard let audioPlayer = self?.currentlyPlayingAudioPlayer else {
|
||||
return MPRemoteCommandHandlerStatus.commandFailed
|
||||
}
|
||||
|
||||
audioPlayer.play()
|
||||
|
||||
return MPRemoteCommandHandlerStatus.success
|
||||
}
|
||||
|
||||
commandCenter.pauseCommand.isEnabled = true
|
||||
commandCenter.pauseCommand.removeTarget(nil)
|
||||
commandCenter.pauseCommand.addTarget { [weak self] event in
|
||||
guard let audioPlayer = self?.currentlyPlayingAudioPlayer else {
|
||||
return MPRemoteCommandHandlerStatus.commandFailed
|
||||
}
|
||||
|
||||
audioPlayer.pause()
|
||||
|
||||
return MPRemoteCommandHandlerStatus.success
|
||||
}
|
||||
|
||||
commandCenter.skipForwardCommand.isEnabled = true
|
||||
commandCenter.skipForwardCommand.removeTarget(nil)
|
||||
commandCenter.skipForwardCommand.addTarget { [weak self] event in
|
||||
guard let audioPlayer = self?.currentlyPlayingAudioPlayer, let skipEvent = event as? MPSkipIntervalCommandEvent else {
|
||||
return MPRemoteCommandHandlerStatus.commandFailed
|
||||
}
|
||||
|
||||
audioPlayer.seekToTime(audioPlayer.currentTime + skipEvent.interval)
|
||||
|
||||
return MPRemoteCommandHandlerStatus.success
|
||||
}
|
||||
|
||||
commandCenter.skipBackwardCommand.isEnabled = true
|
||||
commandCenter.skipBackwardCommand.removeTarget(nil)
|
||||
commandCenter.skipBackwardCommand.addTarget { [weak self] event in
|
||||
guard let audioPlayer = self?.currentlyPlayingAudioPlayer, let skipEvent = event as? MPSkipIntervalCommandEvent else {
|
||||
return MPRemoteCommandHandlerStatus.commandFailed
|
||||
}
|
||||
|
||||
audioPlayer.seekToTime(audioPlayer.currentTime - skipEvent.interval)
|
||||
|
||||
return MPRemoteCommandHandlerStatus.success
|
||||
}
|
||||
}
|
||||
|
||||
private func tearDownRemoteCommandCenter() {
|
||||
displayLink.isPaused = true
|
||||
|
||||
UIApplication.shared.endReceivingRemoteControlEvents()
|
||||
|
||||
let nowPlayingInfoCenter = MPNowPlayingInfoCenter.default()
|
||||
nowPlayingInfoCenter.nowPlayingInfo = nil
|
||||
}
|
||||
|
||||
private func updateNowPlayingInfoCenter() {
|
||||
guard let audioPlayer = currentlyPlayingAudioPlayer else {
|
||||
return
|
||||
}
|
||||
|
||||
let artwork = MPMediaItemArtwork(boundsSize: .init(width: Constants.roomAvatarImageSize, height: Constants.roomAvatarImageSize)) { [weak self] size in
|
||||
return self?.roomAvatar ?? UIImage()
|
||||
}
|
||||
|
||||
let nowPlayingInfoCenter = MPNowPlayingInfoCenter.default()
|
||||
nowPlayingInfoCenter.nowPlayingInfo = [MPMediaItemPropertyTitle: audioPlayer.displayName ?? "Voice message",
|
||||
MPMediaItemPropertyArtist: currentRoomSummary?.displayname as Any,
|
||||
MPMediaItemPropertyArtwork: artwork,
|
||||
MPMediaItemPropertyPlaybackDuration: audioPlayer.duration as Any,
|
||||
MPNowPlayingInfoPropertyElapsedPlaybackTime: audioPlayer.currentTime as Any]
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user