14
14
* limitations under the License.
15
15
*/
16
16
17
- package im.vector.app.features.voicebroadcast
17
+ package im.vector.app.features.voicebroadcast.listening
18
18
19
19
import android.media.AudioAttributes
20
20
import android.media.MediaPlayer
21
21
import androidx.annotation.MainThread
22
22
import im.vector.app.core.di.ActiveSessionHolder
23
23
import im.vector.app.features.home.room.detail.timeline.helper.AudioMessagePlaybackTracker
24
24
import im.vector.app.features.voice.VoiceFailure
25
+ import im.vector.app.features.voicebroadcast.getVoiceBroadcastChunk
26
+ import im.vector.app.features.voicebroadcast.getVoiceBroadcastEventId
27
+ import im.vector.app.features.voicebroadcast.isVoiceBroadcast
28
+ import im.vector.app.features.voicebroadcast.listening.VoiceBroadcastPlayer.Listener
29
+ import im.vector.app.features.voicebroadcast.listening.VoiceBroadcastPlayer.State
25
30
import im.vector.app.features.voicebroadcast.model.VoiceBroadcastState
26
31
import im.vector.app.features.voicebroadcast.model.asVoiceBroadcastEvent
32
+ import im.vector.app.features.voicebroadcast.sequence
27
33
import im.vector.app.features.voicebroadcast.usecase.GetVoiceBroadcastUseCase
28
34
import kotlinx.coroutines.CoroutineScope
29
35
import kotlinx.coroutines.Dispatchers
@@ -43,14 +49,13 @@ import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings
43
49
import timber.log.Timber
44
50
import java.util.concurrent.CopyOnWriteArrayList
45
51
import javax.inject.Inject
46
- import javax.inject.Singleton
47
52
48
53
@Singleton
49
- class VoiceBroadcastPlayer @Inject constructor(
54
+ class VoiceBroadcastPlayerImpl @Inject constructor(
50
55
private val sessionHolder : ActiveSessionHolder ,
51
56
private val playbackTracker : AudioMessagePlaybackTracker ,
52
57
private val getVoiceBroadcastUseCase : GetVoiceBroadcastUseCase ,
53
- ) {
58
+ ) : VoiceBroadcastPlayer {
54
59
private val session
55
60
get() = sessionHolder.getActiveSession()
56
61
@@ -75,9 +80,9 @@ class VoiceBroadcastPlayer @Inject constructor(
75
80
private var currentSequence: Int? = null
76
81
77
82
private var playlist = emptyList<MessageAudioEvent >()
78
- var currentVoiceBroadcastId: String? = null
83
+ override var currentVoiceBroadcastId: String? = null
79
84
80
- private var state : State = State .IDLE
85
+ override var playingState = State .IDLE
81
86
@MainThread
82
87
set(value) {
83
88
Timber .w(" ## VoiceBroadcastPlayer state: $field -> $value " )
@@ -94,22 +99,22 @@ class VoiceBroadcastPlayer @Inject constructor(
94
99
*/
95
100
private val listeners: MutableMap <String , CopyOnWriteArrayList <Listener >> = mutableMapOf ()
96
101
97
- fun playOrResume (roomId : String , eventId : String ) {
98
- val hasChanged = currentVoiceBroadcastId != eventId
102
+ override fun playOrResume (roomId : String , voiceBroadcastId : String ) {
103
+ val hasChanged = currentVoiceBroadcastId != voiceBroadcastId
99
104
when {
100
- hasChanged -> startPlayback(roomId, eventId )
101
- state == State .PAUSED -> resumePlayback()
105
+ hasChanged -> startPlayback(roomId, voiceBroadcastId )
106
+ playingState == State .PAUSED -> resumePlayback()
102
107
else -> Unit
103
108
}
104
109
}
105
110
106
- fun pause () {
111
+ override fun pause () {
107
112
currentMediaPlayer?.pause()
108
113
currentVoiceBroadcastId?.let { playbackTracker.pausePlayback(it) }
109
- state = State .PAUSED
114
+ playingState = State .PAUSED
110
115
}
111
116
112
- fun stop () {
117
+ override fun stop () {
113
118
// Stop playback
114
119
currentMediaPlayer?.stop()
115
120
currentVoiceBroadcastId?.let { playbackTracker.stopPlayback(it) }
@@ -131,7 +136,7 @@ class VoiceBroadcastPlayer @Inject constructor(
131
136
timelineListener = null
132
137
133
138
// Update state
134
- state = State .IDLE
139
+ playingState = State .IDLE
135
140
136
141
// Clear playlist
137
142
playlist = emptyList()
@@ -143,29 +148,29 @@ class VoiceBroadcastPlayer @Inject constructor(
143
148
/* *
144
149
* Add a [Listener] to the given voice broadcast id.
145
150
*/
146
- fun addListener (voiceBroadcastId : String , listener : Listener ) {
151
+ override fun addListener (voiceBroadcastId : String , listener : Listener ) {
147
152
listeners[voiceBroadcastId]?.add(listener) ? : run {
148
153
listeners[voiceBroadcastId] = CopyOnWriteArrayList <Listener >().apply { add(listener) }
149
154
}
150
- if (voiceBroadcastId == currentVoiceBroadcastId) listener.onStateChanged(state ) else listener.onStateChanged(State .IDLE )
155
+ if (voiceBroadcastId == currentVoiceBroadcastId) listener.onStateChanged(playingState ) else listener.onStateChanged(State .IDLE )
151
156
}
152
157
153
158
/* *
154
159
* Remove a [Listener] from the given voice broadcast id.
155
160
*/
156
- fun removeListener (voiceBroadcastId : String , listener : Listener ) {
161
+ override fun removeListener (voiceBroadcastId : String , listener : Listener ) {
157
162
listeners[voiceBroadcastId]?.remove(listener)
158
163
}
159
164
160
165
private fun startPlayback (roomId : String , eventId : String ) {
161
166
val room = session.getRoom(roomId) ? : error(" Unknown roomId: $roomId " )
162
167
// Stop listening previous voice broadcast if any
163
- if (state != State .IDLE ) stop()
168
+ if (playingState != State .IDLE ) stop()
164
169
165
170
currentRoomId = roomId
166
171
currentVoiceBroadcastId = eventId
167
172
168
- state = State .BUFFERING
173
+ playingState = State .BUFFERING
169
174
170
175
val voiceBroadcastState = getVoiceBroadcastUseCase.execute(roomId, eventId)?.content?.voiceBroadcastState
171
176
if (voiceBroadcastState == VoiceBroadcastState .STOPPED ) {
@@ -187,7 +192,7 @@ class VoiceBroadcastPlayer @Inject constructor(
187
192
currentMediaPlayer?.start()
188
193
currentVoiceBroadcastId?.let { playbackTracker.startPlayback(it) }
189
194
currentSequence = sequence
190
- withContext(Dispatchers .Main ) { state = State .PLAYING }
195
+ withContext(Dispatchers .Main ) { playingState = State .PLAYING }
191
196
nextMediaPlayer = prepareNextMediaPlayer()
192
197
} catch (failure: Throwable ) {
193
198
Timber .e(failure, " Unable to start playback" )
@@ -219,7 +224,7 @@ class VoiceBroadcastPlayer @Inject constructor(
219
224
private fun resumePlayback () {
220
225
currentMediaPlayer?.start()
221
226
currentVoiceBroadcastId?.let { playbackTracker.startPlayback(it) }
222
- state = State .PLAYING
227
+ playingState = State .PLAYING
223
228
}
224
229
225
230
private fun updatePlaylist (playlist : List <MessageAudioEvent >) {
@@ -285,7 +290,7 @@ class VoiceBroadcastPlayer @Inject constructor(
285
290
if (newChunks.isEmpty()) return
286
291
updatePlaylist(playlist + newChunks)
287
292
288
- when (state ) {
293
+ when (playingState ) {
289
294
State .PLAYING -> {
290
295
if (nextMediaPlayer == null ) {
291
296
coroutineScope.launch { nextMediaPlayer = prepareNextMediaPlayer() }
@@ -330,7 +335,7 @@ class VoiceBroadcastPlayer @Inject constructor(
330
335
// We'll not receive new chunks anymore so we can stop the live listening
331
336
stop()
332
337
} else {
333
- state = State .BUFFERING
338
+ playingState = State .BUFFERING
334
339
}
335
340
}
336
341
@@ -339,15 +344,4 @@ class VoiceBroadcastPlayer @Inject constructor(
339
344
return true
340
345
}
341
346
}
342
-
343
- enum class State {
344
- PLAYING ,
345
- PAUSED ,
346
- BUFFERING ,
347
- IDLE
348
- }
349
-
350
- fun interface Listener {
351
- fun onStateChanged (state : State )
352
- }
353
347
}
0 commit comments