Skip to content

Commit 174ba4f

Browse files
author
Florian Renaud
committed
VoiceBroadcastPlayer - Create player interface and move implementation to dedicated class
1 parent 40ea00f commit 174ba4f

20 files changed

+156
-71
lines changed

vector/src/main/java/im/vector/app/core/di/VoiceModule.kt

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,33 @@ package im.vector.app.core.di
1818

1919
import android.content.Context
2020
import android.os.Build
21+
import dagger.Binds
2122
import dagger.Module
2223
import dagger.Provides
2324
import dagger.hilt.InstallIn
2425
import dagger.hilt.components.SingletonComponent
25-
import im.vector.app.features.voicebroadcast.VoiceBroadcastRecorder
26-
import im.vector.app.features.voicebroadcast.VoiceBroadcastRecorderQ
26+
import im.vector.app.features.voicebroadcast.listening.VoiceBroadcastPlayer
27+
import im.vector.app.features.voicebroadcast.listening.VoiceBroadcastPlayerImpl
28+
import im.vector.app.features.voicebroadcast.recording.VoiceBroadcastRecorder
29+
import im.vector.app.features.voicebroadcast.recording.VoiceBroadcastRecorderQ
2730
import javax.inject.Singleton
2831

29-
@Module
3032
@InstallIn(SingletonComponent::class)
31-
object VoiceModule {
32-
@Provides
33-
@Singleton
34-
fun providesVoiceBroadcastRecorder(context: Context): VoiceBroadcastRecorder? {
35-
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
36-
VoiceBroadcastRecorderQ(context)
37-
} else {
38-
null
33+
@Module
34+
abstract class VoiceModule {
35+
36+
companion object {
37+
@Provides
38+
@Singleton
39+
fun providesVoiceBroadcastRecorder(context: Context): VoiceBroadcastRecorder? {
40+
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
41+
VoiceBroadcastRecorderQ(context)
42+
} else {
43+
null
44+
}
3945
}
4046
}
47+
48+
@Binds
49+
abstract fun bindVoiceBroadcastPlayer(player: VoiceBroadcastPlayerImpl): VoiceBroadcastPlayer
4150
}

vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ import im.vector.app.features.raw.wellknown.isSecureBackupRequired
4242
import im.vector.app.features.raw.wellknown.withElementWellKnown
4343
import im.vector.app.features.session.coroutineScope
4444
import im.vector.app.features.settings.VectorPreferences
45-
import im.vector.app.features.voicebroadcast.usecase.StopOngoingVoiceBroadcastUseCase
45+
import im.vector.app.features.voicebroadcast.recording.usecase.StopOngoingVoiceBroadcastUseCase
4646
import im.vector.lib.core.utils.compat.getParcelableExtraCompat
4747
import kotlinx.coroutines.Dispatchers
4848
import kotlinx.coroutines.delay

vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/VoiceBroadcastItemFactory.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@ import im.vector.app.features.home.room.detail.timeline.item.MessageVoiceBroadca
2626
import im.vector.app.features.home.room.detail.timeline.item.MessageVoiceBroadcastListeningItem_
2727
import im.vector.app.features.home.room.detail.timeline.item.MessageVoiceBroadcastRecordingItem
2828
import im.vector.app.features.home.room.detail.timeline.item.MessageVoiceBroadcastRecordingItem_
29-
import im.vector.app.features.voicebroadcast.VoiceBroadcastPlayer
30-
import im.vector.app.features.voicebroadcast.VoiceBroadcastRecorder
29+
import im.vector.app.features.voicebroadcast.listening.VoiceBroadcastPlayer
3130
import im.vector.app.features.voicebroadcast.model.MessageVoiceBroadcastInfoContent
3231
import im.vector.app.features.voicebroadcast.model.VoiceBroadcastState
3332
import im.vector.app.features.voicebroadcast.model.asVoiceBroadcastEvent
33+
import im.vector.app.features.voicebroadcast.recording.VoiceBroadcastRecorder
3434
import org.matrix.android.sdk.api.session.Session
3535
import org.matrix.android.sdk.api.session.getRoom
3636
import org.matrix.android.sdk.api.session.getUserOrDefault

vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/AbsMessageVoiceBroadcastItem.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ import im.vector.app.R
2525
import im.vector.app.core.extensions.tintBackground
2626
import im.vector.app.core.resources.ColorProvider
2727
import im.vector.app.core.resources.DrawableProvider
28-
import im.vector.app.features.voicebroadcast.VoiceBroadcastPlayer
29-
import im.vector.app.features.voicebroadcast.VoiceBroadcastRecorder
28+
import im.vector.app.features.voicebroadcast.listening.VoiceBroadcastPlayer
3029
import im.vector.app.features.voicebroadcast.model.VoiceBroadcastState
30+
import im.vector.app.features.voicebroadcast.recording.VoiceBroadcastRecorder
3131
import org.matrix.android.sdk.api.util.MatrixItem
3232

3333
abstract class AbsMessageVoiceBroadcastItem<H : AbsMessageVoiceBroadcastItem.Holder> : AbsMessageItem<H>() {

vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageVoiceBroadcastListeningItem.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import com.airbnb.epoxy.EpoxyModelClass
2323
import im.vector.app.R
2424
import im.vector.app.core.epoxy.onClick
2525
import im.vector.app.features.home.room.detail.RoomDetailAction
26-
import im.vector.app.features.voicebroadcast.VoiceBroadcastPlayer
26+
import im.vector.app.features.voicebroadcast.listening.VoiceBroadcastPlayer
2727
import im.vector.app.features.voicebroadcast.views.VoiceBroadcastMetadataView
2828

2929
@EpoxyModelClass

vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageVoiceBroadcastRecordingItem.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ import com.airbnb.epoxy.EpoxyModelClass
2222
import im.vector.app.R
2323
import im.vector.app.core.epoxy.onClick
2424
import im.vector.app.features.home.room.detail.RoomDetailAction.VoiceBroadcastAction
25-
import im.vector.app.features.voicebroadcast.VoiceBroadcastRecorder
2625
import im.vector.app.features.voicebroadcast.model.VoiceBroadcastState
26+
import im.vector.app.features.voicebroadcast.recording.VoiceBroadcastRecorder
2727
import im.vector.app.features.voicebroadcast.views.VoiceBroadcastMetadataView
2828

2929
@EpoxyModelClass

vector/src/main/java/im/vector/app/features/voicebroadcast/VoiceBroadcastHelper.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@
1616

1717
package im.vector.app.features.voicebroadcast
1818

19-
import im.vector.app.features.voicebroadcast.usecase.PauseVoiceBroadcastUseCase
20-
import im.vector.app.features.voicebroadcast.usecase.ResumeVoiceBroadcastUseCase
21-
import im.vector.app.features.voicebroadcast.usecase.StartVoiceBroadcastUseCase
22-
import im.vector.app.features.voicebroadcast.usecase.StopVoiceBroadcastUseCase
19+
import im.vector.app.features.voicebroadcast.listening.VoiceBroadcastPlayer
20+
import im.vector.app.features.voicebroadcast.recording.usecase.PauseVoiceBroadcastUseCase
21+
import im.vector.app.features.voicebroadcast.recording.usecase.ResumeVoiceBroadcastUseCase
22+
import im.vector.app.features.voicebroadcast.recording.usecase.StartVoiceBroadcastUseCase
23+
import im.vector.app.features.voicebroadcast.recording.usecase.StopVoiceBroadcastUseCase
2324
import javax.inject.Inject
2425

2526
/**
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* Copyright (c) 2022 New Vector Ltd
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package im.vector.app.features.voicebroadcast.listening
18+
19+
interface VoiceBroadcastPlayer {
20+
21+
/**
22+
* The current playing voice broadcast identifier, if any.
23+
*/
24+
val currentVoiceBroadcastId: String?
25+
26+
/**
27+
* The current playing [State], [State.IDLE] by default.
28+
*/
29+
val playingState: State
30+
31+
/**
32+
* Start playback of the given voice broadcast.
33+
*/
34+
fun playOrResume(roomId: String, voiceBroadcastId: String)
35+
36+
/**
37+
* Pause playback of the current voice broadcast, if any.
38+
*/
39+
fun pause()
40+
41+
/**
42+
* Stop playback of the current voice broadcast, if any, and reset the player state.
43+
*/
44+
fun stop()
45+
46+
/**
47+
* Add a [Listener] to the given voice broadcast id.
48+
*/
49+
fun addListener(voiceBroadcastId: String, listener: Listener)
50+
51+
/**
52+
* Remove a [Listener] from the given voice broadcast id.
53+
*/
54+
fun removeListener(voiceBroadcastId: String, listener: Listener)
55+
56+
/**
57+
* Player states.
58+
*/
59+
enum class State {
60+
PLAYING,
61+
PAUSED,
62+
BUFFERING,
63+
IDLE
64+
}
65+
66+
/**
67+
* Listener related to [VoiceBroadcastPlayer].
68+
*/
69+
fun interface Listener {
70+
/**
71+
* Notify about [VoiceBroadcastPlayer.playingState] changes.
72+
*/
73+
fun onStateChanged(state: State)
74+
}
75+
}

vector/src/main/java/im/vector/app/features/voicebroadcast/VoiceBroadcastPlayer.kt renamed to vector/src/main/java/im/vector/app/features/voicebroadcast/listening/VoiceBroadcastPlayerImpl.kt

Lines changed: 28 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,22 @@
1414
* limitations under the License.
1515
*/
1616

17-
package im.vector.app.features.voicebroadcast
17+
package im.vector.app.features.voicebroadcast.listening
1818

1919
import android.media.AudioAttributes
2020
import android.media.MediaPlayer
2121
import androidx.annotation.MainThread
2222
import im.vector.app.core.di.ActiveSessionHolder
2323
import im.vector.app.features.home.room.detail.timeline.helper.AudioMessagePlaybackTracker
2424
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
2530
import im.vector.app.features.voicebroadcast.model.VoiceBroadcastState
2631
import im.vector.app.features.voicebroadcast.model.asVoiceBroadcastEvent
32+
import im.vector.app.features.voicebroadcast.sequence
2733
import im.vector.app.features.voicebroadcast.usecase.GetVoiceBroadcastUseCase
2834
import kotlinx.coroutines.CoroutineScope
2935
import kotlinx.coroutines.Dispatchers
@@ -43,14 +49,13 @@ import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings
4349
import timber.log.Timber
4450
import java.util.concurrent.CopyOnWriteArrayList
4551
import javax.inject.Inject
46-
import javax.inject.Singleton
4752

4853
@Singleton
49-
class VoiceBroadcastPlayer @Inject constructor(
54+
class VoiceBroadcastPlayerImpl @Inject constructor(
5055
private val sessionHolder: ActiveSessionHolder,
5156
private val playbackTracker: AudioMessagePlaybackTracker,
5257
private val getVoiceBroadcastUseCase: GetVoiceBroadcastUseCase,
53-
) {
58+
) : VoiceBroadcastPlayer {
5459
private val session
5560
get() = sessionHolder.getActiveSession()
5661

@@ -75,9 +80,9 @@ class VoiceBroadcastPlayer @Inject constructor(
7580
private var currentSequence: Int? = null
7681

7782
private var playlist = emptyList<MessageAudioEvent>()
78-
var currentVoiceBroadcastId: String? = null
83+
override var currentVoiceBroadcastId: String? = null
7984

80-
private var state: State = State.IDLE
85+
override var playingState = State.IDLE
8186
@MainThread
8287
set(value) {
8388
Timber.w("## VoiceBroadcastPlayer state: $field -> $value")
@@ -94,22 +99,22 @@ class VoiceBroadcastPlayer @Inject constructor(
9499
*/
95100
private val listeners: MutableMap<String, CopyOnWriteArrayList<Listener>> = mutableMapOf()
96101

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
99104
when {
100-
hasChanged -> startPlayback(roomId, eventId)
101-
state == State.PAUSED -> resumePlayback()
105+
hasChanged -> startPlayback(roomId, voiceBroadcastId)
106+
playingState == State.PAUSED -> resumePlayback()
102107
else -> Unit
103108
}
104109
}
105110

106-
fun pause() {
111+
override fun pause() {
107112
currentMediaPlayer?.pause()
108113
currentVoiceBroadcastId?.let { playbackTracker.pausePlayback(it) }
109-
state = State.PAUSED
114+
playingState = State.PAUSED
110115
}
111116

112-
fun stop() {
117+
override fun stop() {
113118
// Stop playback
114119
currentMediaPlayer?.stop()
115120
currentVoiceBroadcastId?.let { playbackTracker.stopPlayback(it) }
@@ -131,7 +136,7 @@ class VoiceBroadcastPlayer @Inject constructor(
131136
timelineListener = null
132137

133138
// Update state
134-
state = State.IDLE
139+
playingState = State.IDLE
135140

136141
// Clear playlist
137142
playlist = emptyList()
@@ -143,29 +148,29 @@ class VoiceBroadcastPlayer @Inject constructor(
143148
/**
144149
* Add a [Listener] to the given voice broadcast id.
145150
*/
146-
fun addListener(voiceBroadcastId: String, listener: Listener) {
151+
override fun addListener(voiceBroadcastId: String, listener: Listener) {
147152
listeners[voiceBroadcastId]?.add(listener) ?: run {
148153
listeners[voiceBroadcastId] = CopyOnWriteArrayList<Listener>().apply { add(listener) }
149154
}
150-
if (voiceBroadcastId == currentVoiceBroadcastId) listener.onStateChanged(state) else listener.onStateChanged(State.IDLE)
155+
if (voiceBroadcastId == currentVoiceBroadcastId) listener.onStateChanged(playingState) else listener.onStateChanged(State.IDLE)
151156
}
152157

153158
/**
154159
* Remove a [Listener] from the given voice broadcast id.
155160
*/
156-
fun removeListener(voiceBroadcastId: String, listener: Listener) {
161+
override fun removeListener(voiceBroadcastId: String, listener: Listener) {
157162
listeners[voiceBroadcastId]?.remove(listener)
158163
}
159164

160165
private fun startPlayback(roomId: String, eventId: String) {
161166
val room = session.getRoom(roomId) ?: error("Unknown roomId: $roomId")
162167
// Stop listening previous voice broadcast if any
163-
if (state != State.IDLE) stop()
168+
if (playingState != State.IDLE) stop()
164169

165170
currentRoomId = roomId
166171
currentVoiceBroadcastId = eventId
167172

168-
state = State.BUFFERING
173+
playingState = State.BUFFERING
169174

170175
val voiceBroadcastState = getVoiceBroadcastUseCase.execute(roomId, eventId)?.content?.voiceBroadcastState
171176
if (voiceBroadcastState == VoiceBroadcastState.STOPPED) {
@@ -187,7 +192,7 @@ class VoiceBroadcastPlayer @Inject constructor(
187192
currentMediaPlayer?.start()
188193
currentVoiceBroadcastId?.let { playbackTracker.startPlayback(it) }
189194
currentSequence = sequence
190-
withContext(Dispatchers.Main) { state = State.PLAYING }
195+
withContext(Dispatchers.Main) { playingState = State.PLAYING }
191196
nextMediaPlayer = prepareNextMediaPlayer()
192197
} catch (failure: Throwable) {
193198
Timber.e(failure, "Unable to start playback")
@@ -219,7 +224,7 @@ class VoiceBroadcastPlayer @Inject constructor(
219224
private fun resumePlayback() {
220225
currentMediaPlayer?.start()
221226
currentVoiceBroadcastId?.let { playbackTracker.startPlayback(it) }
222-
state = State.PLAYING
227+
playingState = State.PLAYING
223228
}
224229

225230
private fun updatePlaylist(playlist: List<MessageAudioEvent>) {
@@ -285,7 +290,7 @@ class VoiceBroadcastPlayer @Inject constructor(
285290
if (newChunks.isEmpty()) return
286291
updatePlaylist(playlist + newChunks)
287292

288-
when (state) {
293+
when (playingState) {
289294
State.PLAYING -> {
290295
if (nextMediaPlayer == null) {
291296
coroutineScope.launch { nextMediaPlayer = prepareNextMediaPlayer() }
@@ -330,7 +335,7 @@ class VoiceBroadcastPlayer @Inject constructor(
330335
// We'll not receive new chunks anymore so we can stop the live listening
331336
stop()
332337
} else {
333-
state = State.BUFFERING
338+
playingState = State.BUFFERING
334339
}
335340
}
336341

@@ -339,15 +344,4 @@ class VoiceBroadcastPlayer @Inject constructor(
339344
return true
340345
}
341346
}
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-
}
353347
}

vector/src/main/java/im/vector/app/features/voicebroadcast/VoiceBroadcastRecorder.kt renamed to vector/src/main/java/im/vector/app/features/voicebroadcast/recording/VoiceBroadcastRecorder.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
package im.vector.app.features.voicebroadcast
17+
package im.vector.app.features.voicebroadcast.recording
1818

1919
import androidx.annotation.IntRange
2020
import im.vector.app.features.voice.VoiceRecorder

0 commit comments

Comments
 (0)