2022-10-17 16:23:47 +00:00
//
// C o p y r i g h t 2 0 2 2 N e w V e c t o r L t d
//
// L i c e n s e d u n d e r t h e A p a c h e L i c e n s e , V e r s i o n 2 . 0 ( t h e " L i c e n s e " ) ;
// y o u m a y n o t u s e t h i s f i l e e x c e p t i n c o m p l i a n c e w i t h t h e L i c e n s e .
// Y o u m a y o b t a i n a c o p y o f t h e L i c e n s e a t
//
// h t t p : / / w w w . a p a c h e . o r g / l i c e n s e s / L I C E N S E - 2 . 0
//
// U n l e s s r e q u i r e d b y a p p l i c a b l e l a w o r a g r e e d t o i n w r i t i n g , s o f t w a r e
// d i s t r i b u t e d u n d e r t h e L i c e n s e i s d i s t r i b u t e d o n a n " A S I S " B A S I S ,
// W I T H O U T W A R R A N T I E S O R C O N D I T I O N S O F A N Y K I N D , e i t h e r e x p r e s s o r i m p l i e d .
// S e e t h e L i c e n s e f o r t h e s p e c i f i c l a n g u a g e g o v e r n i n g p e r m i s s i o n s a n d
// l i m i t a t i o n s u n d e r t h e L i c e n s e .
//
import Combine
import SwiftUI
2022-10-20 16:33:04 +00:00
// TODO: V o i c e B r o a d c a s t P l a y b a c k V i e w M o d e l m u s t b e r e v i s i t e d i n o r d e r t o n o t d e p e n d o n M a t r i x S D K
// W e n e e d a V o i c e B r o a d c a s t P l a y b a c k S e r v i c e P r o t o c o l a n d V o i c e B r o a d c a s t A g g r e g a t o r P r o t o c o l
import MatrixSDK
2022-10-17 16:23:47 +00:00
2022-10-19 13:32:03 +00:00
class VoiceBroadcastPlaybackViewModel : VoiceBroadcastPlaybackViewModelType , VoiceBroadcastPlaybackViewModelProtocol {
2022-10-19 10:56:59 +00:00
2022-10-17 16:23:47 +00:00
// MARK: - P r o p e r t i e s
// MARK: P r i v a t e
2022-10-19 10:56:59 +00:00
private let mediaServiceProvider : VoiceMessageMediaServiceProvider
private let cacheManager : VoiceMessageAttachmentCacheManager
2022-10-17 16:23:47 +00:00
2022-11-14 16:16:14 +00:00
private var voiceBroadcastAggregator : VoiceBroadcastAggregator
2022-10-19 21:09:48 +00:00
private var voiceBroadcastChunkQueue : [ VoiceBroadcastChunk ] = [ ]
2022-11-14 16:16:14 +00:00
private var voiceBroadcastAttachmentCacheManagerLoadResults : [ VoiceMessageAttachmentCacheManagerLoadResult ] = [ ]
private var audioPlayer : VoiceMessageAudioPlayer ?
private var displayLink : CADisplayLink !
2022-10-19 21:09:48 +00:00
2022-10-20 09:33:17 +00:00
private var isLivePlayback = false
2022-11-14 16:16:14 +00:00
private var acceptProgressUpdates = true
private var isActuallyPaused : Bool = false
2022-10-20 09:33:17 +00:00
2022-10-17 16:23:47 +00:00
// MARK: P u b l i c
// MARK: - S e t u p
2022-10-19 13:32:03 +00:00
init ( details : VoiceBroadcastPlaybackDetails ,
mediaServiceProvider : VoiceMessageMediaServiceProvider ,
2022-10-19 10:56:59 +00:00
cacheManager : VoiceMessageAttachmentCacheManager ,
voiceBroadcastAggregator : VoiceBroadcastAggregator ) {
self . mediaServiceProvider = mediaServiceProvider
self . cacheManager = cacheManager
self . voiceBroadcastAggregator = voiceBroadcastAggregator
2022-10-19 13:32:03 +00:00
let viewState = VoiceBroadcastPlaybackViewState ( details : details ,
2022-10-20 14:47:56 +00:00
broadcastState : VoiceBroadcastPlaybackViewModel . getBroadcastState ( from : voiceBroadcastAggregator . voiceBroadcastState ) ,
2022-10-19 13:32:03 +00:00
playbackState : . stopped ,
2022-11-14 16:16:14 +00:00
playingState : VoiceBroadcastPlayingState ( duration : Float ( voiceBroadcastAggregator . voiceBroadcast . duration ) ) ,
bindings : VoiceBroadcastPlaybackViewStateBindings ( progress : 0 ) )
2022-10-19 13:32:03 +00:00
super . init ( initialViewState : viewState )
2022-10-19 10:56:59 +00:00
2022-11-14 16:16:14 +00:00
displayLink = CADisplayLink ( target : WeakTarget ( self , selector : #selector ( handleDisplayLinkTick ) ) , selector : WeakTarget . triggerSelector )
displayLink . isPaused = true
displayLink . add ( to : . current , forMode : . common )
2022-10-19 10:56:59 +00:00
self . voiceBroadcastAggregator . delegate = self
2022-10-17 16:23:47 +00:00
}
2022-10-20 07:26:00 +00:00
private func release ( ) {
MXLog . debug ( " [VoiceBroadcastPlaybackViewModel] release " )
if let audioPlayer = audioPlayer {
audioPlayer . deregisterDelegate ( self )
self . audioPlayer = nil
}
}
2022-10-17 16:23:47 +00:00
// MARK: - P u b l i c
2022-10-19 08:01:36 +00:00
override func process ( viewAction : VoiceBroadcastPlaybackViewAction ) {
2022-10-18 14:36:02 +00:00
switch viewAction {
case . play :
play ( )
2022-10-20 09:33:17 +00:00
case . playLive :
playLive ( )
2022-10-18 14:36:02 +00:00
case . pause :
pause ( )
2022-11-14 16:16:14 +00:00
case . sliderChange ( let didChange ) :
didSliderChanged ( didChange )
2022-10-18 14:36:02 +00:00
}
}
2022-10-20 07:26:00 +00:00
// MARK: - P r i v a t e
2022-10-18 14:36:02 +00:00
// / L i s t e n v o i c e b r o a d c a s t
private func play ( ) {
2022-10-20 09:33:17 +00:00
isLivePlayback = false
2022-11-14 16:16:14 +00:00
displayLink . isPaused = false
isActuallyPaused = false
2022-10-20 09:33:17 +00:00
2022-10-19 21:09:48 +00:00
if voiceBroadcastAggregator . isStarted = = false {
// S t a r t t h e s t r e a m i n g b y f e t c h i n g b r o a d c a s t c h u n k s
2022-10-20 11:39:27 +00:00
// T h e a u d i o p l a y e r w i l l a u t o m a t i c a l l y s t a r t t h e p l a y b a c k o n i n c o m i n g c h u n k s
2022-10-19 21:09:48 +00:00
MXLog . debug ( " [VoiceBroadcastPlaybackViewModel] play: Start streaming " )
state . playbackState = . buffering
voiceBroadcastAggregator . start ( )
2022-11-14 16:16:14 +00:00
updateDuration ( )
} else if let audioPlayer = audioPlayer {
2022-10-20 07:26:00 +00:00
MXLog . debug ( " [VoiceBroadcastPlaybackViewModel] play: resume " )
2022-10-19 21:09:48 +00:00
audioPlayer . play ( )
2022-11-14 16:16:14 +00:00
} else {
2022-10-20 07:26:00 +00:00
let chunks = voiceBroadcastAggregator . voiceBroadcast . chunks
MXLog . debug ( " [VoiceBroadcastPlaybackViewModel] play: restart from the beginning: \( chunks . count ) chunks " )
2022-11-14 16:16:14 +00:00
// R e i n j e c t a l l t h e c h u n k s w e a l r e a d y h a v e a n d p l a y t h e m
2022-10-20 07:26:00 +00:00
voiceBroadcastChunkQueue . append ( contentsOf : chunks )
processPendingVoiceBroadcastChunks ( )
2022-10-19 21:09:48 +00:00
}
}
2022-10-20 09:33:17 +00:00
private func playLive ( ) {
guard isLivePlayback = = false else {
MXLog . debug ( " [VoiceBroadcastPlaybackViewModel] playLive: Already playing live " )
return
}
isLivePlayback = true
2022-11-14 16:16:14 +00:00
displayLink . isPaused = false
isActuallyPaused = false
2022-10-20 09:33:17 +00:00
2022-10-20 10:25:23 +00:00
// F l u s h t h e c u r r e n t a u d i o p l a y e r p l a y l i s t
audioPlayer ? . removeAllPlayerItems ( )
if voiceBroadcastAggregator . isStarted = = false {
// S t a r t t h e s t r e a m i n g b y f e t c h i n g b r o a d c a s t c h u n k s
2022-10-20 11:39:27 +00:00
// T h e a u d i o p l a y e r w i l l a u t o m a t i c a l l y s t a r t t h e p l a y b a c k o n i n c o m i n g c h u n k s
2022-10-20 10:25:23 +00:00
MXLog . debug ( " [VoiceBroadcastPlaybackViewModel] playLive: Start streaming " )
state . playbackState = . buffering
voiceBroadcastAggregator . start ( )
2022-11-14 16:16:14 +00:00
state . playingState . duration = Float ( voiceBroadcastAggregator . voiceBroadcast . duration )
} else {
2022-10-20 10:25:23 +00:00
let chunks = voiceBroadcastAggregator . voiceBroadcast . chunks
MXLog . debug ( " [VoiceBroadcastPlaybackViewModel] playLive: restart from the last chunk: \( chunks . count ) chunks " )
2022-11-14 16:16:14 +00:00
// R e i n j e c t a l l t h e c h u n k s w e a l r e a d y h a v e a n d p l a y t h e l a s t o n e
2022-10-20 10:25:23 +00:00
voiceBroadcastChunkQueue . append ( contentsOf : chunks )
processPendingVoiceBroadcastChunksForLivePlayback ( )
}
2022-10-20 09:33:17 +00:00
}
2022-11-14 16:16:14 +00:00
// / P a u s e v o i c e b r o a d c a s t
2022-10-19 21:09:48 +00:00
private func pause ( ) {
MXLog . debug ( " [VoiceBroadcastPlaybackViewModel] pause " )
2022-10-19 12:22:23 +00:00
2022-10-20 10:25:23 +00:00
isLivePlayback = false
2022-11-14 16:16:14 +00:00
displayLink . isPaused = true
isActuallyPaused = true
2022-10-20 10:25:23 +00:00
2022-10-19 21:09:48 +00:00
if let audioPlayer = audioPlayer , audioPlayer . isPlaying {
audioPlayer . pause ( )
2022-10-19 12:22:23 +00:00
}
2022-10-19 21:09:48 +00:00
}
2022-10-20 07:26:00 +00:00
private func stopIfVoiceBroadcastOver ( ) {
MXLog . debug ( " [VoiceBroadcastPlaybackViewModel] stopIfVoiceBroadcastOver " )
2022-11-14 16:16:14 +00:00
// C h e c k i f t h e b r o a d c a s t i s o v e r b e f o r e s t o p p i n g e v e r y t h i n g
2022-10-20 07:26:00 +00:00
// I f n o t , t h e p l a y e r s h o u l d n o t s t o p p e d . T h e v i e w s t a t e m u s t b e m o v e t o b u f f e r i n g
2022-11-14 16:16:14 +00:00
// TODO: D e f i n e w i t h m o r e a c c u r a c y t h e t h r e s h o l d t o d e t e c t t h e e n d o f t h e p l a y b a c k
let remainingTime = state . playingState . duration - state . bindings . progress
if remainingTime < 500 {
stop ( )
} else {
state . playbackState = . buffering
}
2022-10-20 07:26:00 +00:00
}
2022-10-19 21:09:48 +00:00
2022-10-20 07:26:00 +00:00
private func stop ( ) {
MXLog . debug ( " [VoiceBroadcastPlaybackViewModel] stop " )
2022-10-20 15:24:46 +00:00
isLivePlayback = false
2022-11-14 16:16:14 +00:00
displayLink . isPaused = true
2022-10-20 15:24:46 +00:00
2022-10-20 07:26:00 +00:00
// O b j e c t s w i l l b e r e l e a s e d o n a u d i o P l a y e r D i d S t o p P l a y i n g
audioPlayer ? . stop ( )
}
// MARK: - V o i c e b r o a d c a s t c h u n k s p l a y b a c k
2022-10-20 11:39:27 +00:00
// / S t a r t t h e p l a y b a c k f r o m t h e b e g i n n i n g o r p u s h m o r e c h u n k s t o i t
2022-11-14 16:16:14 +00:00
private func processPendingVoiceBroadcastChunks ( _ time : TimeInterval ? = nil ) {
2022-10-20 07:26:00 +00:00
reorderPendingVoiceBroadcastChunks ( )
2022-11-14 16:16:14 +00:00
processNextVoiceBroadcastChunk ( time )
2022-10-20 07:26:00 +00:00
}
2022-10-20 11:39:27 +00:00
// / S t a r t t h e p l a y b a c k f r o m t h e l a s t k n o w n c h u n k
2022-10-20 10:25:23 +00:00
private func processPendingVoiceBroadcastChunksForLivePlayback ( ) {
let chunks = reorderVoiceBroadcastChunks ( chunks : Array ( voiceBroadcastAggregator . voiceBroadcast . chunks ) )
if let lastChunk = chunks . last {
2022-10-20 15:24:46 +00:00
MXLog . debug ( " [VoiceBroadcastPlaybackViewModel] processPendingVoiceBroadcastChunksForLivePlayback. Use the last chunk: sequence: \( lastChunk . sequence ) out of the \( voiceBroadcastChunkQueue . count ) chunks " )
2022-10-20 10:25:23 +00:00
voiceBroadcastChunkQueue = [ lastChunk ]
}
processNextVoiceBroadcastChunk ( )
}
2022-10-20 07:26:00 +00:00
private func reorderPendingVoiceBroadcastChunks ( ) {
2022-10-20 11:39:27 +00:00
// M a k e s u r e w e d o w n l o a d a n d p r o c e s s c h u n k s i n t h e r i g h t o r d e r
2022-10-20 10:25:23 +00:00
voiceBroadcastChunkQueue = reorderVoiceBroadcastChunks ( chunks : voiceBroadcastChunkQueue )
}
private func reorderVoiceBroadcastChunks ( chunks : [ VoiceBroadcastChunk ] ) -> [ VoiceBroadcastChunk ] {
chunks . sorted ( by : { $0 . sequence < $1 . sequence } )
2022-10-20 07:26:00 +00:00
}
2022-11-14 16:16:14 +00:00
private func processNextVoiceBroadcastChunk ( _ time : TimeInterval ? = nil ) {
2022-10-19 21:09:48 +00:00
MXLog . debug ( " [VoiceBroadcastPlaybackViewModel] processNextVoiceBroadcastChunk: \( voiceBroadcastChunkQueue . count ) chunks remaining " )
guard voiceBroadcastChunkQueue . count > 0 else {
// W e c a c h e d a l l c h u n k s . N o t h i n g m o r e t o d o
2022-10-19 12:22:23 +00:00
return
}
2022-11-14 16:16:14 +00:00
if ( isActuallyPaused = = false && state . playbackState = = . paused ) || state . playbackState = = . stopped {
state . playbackState = . buffering
}
2022-10-20 07:26:00 +00:00
// TODO: C o n t r o l t h e d o w n l o a d r a t e t o a v o i d t o d o w n l o a d a l l c h u n k i n m a s s
// W e c o u l d s y n c h r o n i s e i t w i t h t h e n u m b e r o f c h u n k s i n t h e p l a y e r p l a y l i s t ( a u d i o P l a y e r . p l a y e r I t e m s )
2022-10-19 21:09:48 +00:00
let chunk = voiceBroadcastChunkQueue . removeFirst ( )
2022-10-19 15:28:08 +00:00
// n u m b e r O f S a m p l e s i s f o r t h e e q u a l i z e r v i e w w e d o n o t s u p p o r t y e t
2022-10-19 21:09:48 +00:00
cacheManager . loadAttachment ( chunk . attachment , numberOfSamples : 1 ) { [ weak self ] result in
2022-10-19 12:22:23 +00:00
guard let self = self else {
return
}
2022-10-20 07:26:00 +00:00
// TODO: M a k e s u r e t h e r e h a s n o n e w i n c o m i n g c h u n k t h a t s h o u l d b e b e f o r e t h i s a t t a c h m e n t
// B e c a r e f u l t h a t t h i s n e w c h u n k i s n o t o l d e r t h a n t h e c h u n k b e i n g p l a y e d b y t h e a u d i o p l a y e r . E l s e
// w e w i l l g e t a n u n e x e c p t e d r e w i n d .
2022-11-14 16:16:14 +00:00
2022-10-19 12:22:23 +00:00
switch result {
2022-11-14 16:16:14 +00:00
case . success ( let result ) :
guard result . eventIdentifier = = chunk . attachment . eventId else {
return
}
self . voiceBroadcastAttachmentCacheManagerLoadResults . append ( result )
if let audioPlayer = self . audioPlayer {
// A p p e n d t h e c h u n k t o t h e c u r r e n t p l a y l i s t
audioPlayer . addContentFromURL ( result . url )
2022-10-19 12:22:23 +00:00
2022-11-14 16:16:14 +00:00
// R e s u m e t h e p l a y e r . N e e d e d a f t e r a b u f f e r i n g
if audioPlayer . isPlaying = = false && self . state . playbackState = = . buffering {
MXLog . debug ( " [VoiceBroadcastPlaybackViewModel] processNextVoiceBroadcastChunk: Resume the player " )
self . displayLink . isPaused = false
2022-10-19 21:09:48 +00:00
audioPlayer . play ( )
2022-11-14 16:16:14 +00:00
if let time = time {
audioPlayer . seekToTime ( time )
}
2022-10-19 21:09:48 +00:00
}
2022-11-14 16:16:14 +00:00
} else {
// I n i t a n d s t a r t t h e p l a y e r o n t h e f i r s t c h u n k
let audioPlayer = self . mediaServiceProvider . audioPlayerForIdentifier ( result . eventIdentifier )
audioPlayer . registerDelegate ( self )
audioPlayer . loadContentFromURL ( result . url , displayName : chunk . attachment . originalFileName )
self . displayLink . isPaused = false
audioPlayer . play ( )
if let time = time {
audioPlayer . seekToTime ( time )
2022-10-19 21:09:48 +00:00
}
2022-11-14 16:16:14 +00:00
self . audioPlayer = audioPlayer
}
case . failure ( let error ) :
MXLog . error ( " [VoiceBroadcastPlaybackViewModel] processVoiceBroadcastChunkQueue: loadAttachment error " , context : error )
if self . voiceBroadcastChunkQueue . count = = 0 {
// N o m o r e c h u n k t o t r y . G o t o e r r o r
self . state . playbackState = . error
}
2022-10-19 12:22:23 +00:00
}
2022-10-19 21:09:48 +00:00
self . processNextVoiceBroadcastChunk ( )
2022-10-19 12:22:23 +00:00
}
2022-10-17 16:23:47 +00:00
}
2022-10-20 14:47:56 +00:00
2022-11-14 16:16:14 +00:00
private func updateDuration ( ) {
let duration = voiceBroadcastAggregator . voiceBroadcast . duration
let time = TimeInterval ( duration / 1000 )
let formatter = DateComponentsFormatter ( )
formatter . unitsStyle = . abbreviated
state . playingState . duration = Float ( duration )
state . playingState . durationLabel = formatter . string ( from : time )
}
private func didSliderChanged ( _ didChange : Bool ) {
acceptProgressUpdates = ! didChange
if didChange {
audioPlayer ? . pause ( )
displayLink . isPaused = true
} else {
// F l u s h t h e c u r r e n t a u d i o p l a y e r p l a y l i s t
audioPlayer ? . removeAllPlayerItems ( )
let chunks = reorderVoiceBroadcastChunks ( chunks : Array ( voiceBroadcastAggregator . voiceBroadcast . chunks ) )
// R e i n j e c t t h e c h u n k s w e n e e d a n d p l a y t h e m
let remainingTime = state . playingState . duration - state . bindings . progress
var chunksDuration : UInt = 0
for chunk in chunks . reversed ( ) {
chunksDuration += chunk . duration
voiceBroadcastChunkQueue . append ( chunk )
if Float ( chunksDuration ) >= remainingTime {
break
}
}
MXLog . debug ( " [VoiceBroadcastPlaybackViewModel] didSliderChanged: restart to time: \( state . bindings . progress ) milliseconds " )
let time = state . bindings . progress - state . playingState . duration + Float ( chunksDuration )
processPendingVoiceBroadcastChunks ( TimeInterval ( time / 1000 ) )
}
}
@objc private func handleDisplayLinkTick ( ) {
updateUI ( )
}
private func updateUI ( ) {
guard let playingEventId = voiceBroadcastAttachmentCacheManagerLoadResults . first ( where : { result in
result . url = = audioPlayer ? . currentUrl
} ) ? . eventIdentifier ,
let playingSequence = voiceBroadcastAggregator . voiceBroadcast . chunks . first ( where : { chunk in
chunk . attachment . eventId = = playingEventId
} ) ? . sequence else {
return
}
let progress = Double ( voiceBroadcastAggregator . voiceBroadcast . chunks . filter { chunk in
chunk . sequence < playingSequence
} . reduce ( 0 ) { $0 + $1 . duration } ) + ( audioPlayer ? . currentTime . rounded ( ) ? ? 0 ) * 1000
state . bindings . progress = Float ( progress )
}
2022-10-20 14:47:56 +00:00
private static func getBroadcastState ( from state : VoiceBroadcastInfo . State ) -> VoiceBroadcastState {
var broadcastState : VoiceBroadcastState
switch state {
case . started :
broadcastState = VoiceBroadcastState . live
case . paused :
broadcastState = VoiceBroadcastState . paused
case . resumed :
broadcastState = VoiceBroadcastState . live
case . stopped :
broadcastState = VoiceBroadcastState . stopped
}
return broadcastState
}
2022-10-19 12:22:23 +00:00
}
2022-10-20 11:39:27 +00:00
// MARK: V o i c e B r o a d c a s t A g g r e g a t o r D e l e g a t e
2022-10-19 10:56:59 +00:00
extension VoiceBroadcastPlaybackViewModel : VoiceBroadcastAggregatorDelegate {
func voiceBroadcastAggregatorDidStartLoading ( _ aggregator : VoiceBroadcastAggregator ) {
}
func voiceBroadcastAggregatorDidEndLoading ( _ aggregator : VoiceBroadcastAggregator ) {
}
func voiceBroadcastAggregator ( _ aggregator : VoiceBroadcastAggregator , didFailWithError : Error ) {
2022-10-19 21:09:48 +00:00
MXLog . error ( " [VoiceBroadcastPlaybackViewModel] voiceBroadcastAggregator didFailWithError: " , context : didFailWithError )
2022-10-19 10:56:59 +00:00
}
2022-10-19 15:28:08 +00:00
func voiceBroadcastAggregator ( _ aggregator : VoiceBroadcastAggregator , didReceiveChunk : VoiceBroadcastChunk ) {
2022-10-19 21:09:48 +00:00
voiceBroadcastChunkQueue . append ( didReceiveChunk )
2022-10-19 15:28:08 +00:00
}
2022-10-20 14:47:56 +00:00
func voiceBroadcastAggregator ( _ aggregator : VoiceBroadcastAggregator , didReceiveState : VoiceBroadcastInfo . State ) {
state . broadcastState = VoiceBroadcastPlaybackViewModel . getBroadcastState ( from : didReceiveState )
}
2022-10-19 10:56:59 +00:00
func voiceBroadcastAggregatorDidUpdateData ( _ aggregator : VoiceBroadcastAggregator ) {
2022-10-20 10:25:23 +00:00
if isLivePlayback && state . playbackState = = . buffering {
2022-11-14 16:16:14 +00:00
// W e s t a r t e d d i r e c t l y w i t h a l i v e p l a y b a c k b u t t h e r e w a s n o k n o w n c h u n k s a t t h a t t i m e
2022-10-20 11:39:27 +00:00
// T h e s e a r e t h e f i r s t c h u n k s w e g e t . S t a r t t h e p l a y b a c k o n t h e l a t e s t o n e
2022-10-20 10:25:23 +00:00
processPendingVoiceBroadcastChunksForLivePlayback ( )
2022-11-14 16:16:14 +00:00
} else {
2022-10-20 10:25:23 +00:00
processPendingVoiceBroadcastChunks ( )
}
2022-10-19 10:56:59 +00:00
}
}
2022-10-19 12:22:23 +00:00
2022-10-20 11:39:27 +00:00
// MARK: - V o i c e M e s s a g e A u d i o P l a y e r D e l e g a t e
2022-10-19 12:22:23 +00:00
extension VoiceBroadcastPlaybackViewModel : VoiceMessageAudioPlayerDelegate {
func audioPlayerDidFinishLoading ( _ audioPlayer : VoiceMessageAudioPlayer ) {
}
func audioPlayerDidStartPlaying ( _ audioPlayer : VoiceMessageAudioPlayer ) {
2022-10-20 09:33:17 +00:00
if isLivePlayback {
state . playbackState = . playingLive
2022-11-14 16:16:14 +00:00
} else {
2022-10-20 09:33:17 +00:00
state . playbackState = . playing
}
2022-10-19 12:22:23 +00:00
}
func audioPlayerDidPausePlaying ( _ audioPlayer : VoiceMessageAudioPlayer ) {
2022-10-19 13:01:43 +00:00
state . playbackState = . paused
2022-10-19 12:22:23 +00:00
}
func audioPlayerDidStopPlaying ( _ audioPlayer : VoiceMessageAudioPlayer ) {
2022-10-20 07:26:00 +00:00
MXLog . debug ( " [VoiceBroadcastPlaybackViewModel] audioPlayerDidStopPlaying " )
2022-10-19 13:01:43 +00:00
state . playbackState = . stopped
2022-10-20 07:26:00 +00:00
release ( )
2022-10-19 12:22:23 +00:00
}
func audioPlayer ( _ audioPlayer : VoiceMessageAudioPlayer , didFailWithError error : Error ) {
2022-10-19 13:01:43 +00:00
state . playbackState = . error
2022-10-19 12:22:23 +00:00
}
func audioPlayerDidFinishPlaying ( _ audioPlayer : VoiceMessageAudioPlayer ) {
2022-10-20 07:26:00 +00:00
MXLog . debug ( " [VoiceBroadcastPlaybackViewModel] audioPlayerDidFinishPlaying: \( audioPlayer . playerItems . count ) " )
stopIfVoiceBroadcastOver ( )
2022-10-19 12:22:23 +00:00
}
}