Create VoiceBroadcast model with roomId and eventId
This commit is contained in:
parent
20d62b14de
commit
6d850b3030
@ -20,6 +20,7 @@ import android.net.Uri
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import im.vector.app.core.platform.VectorViewModelAction
|
import im.vector.app.core.platform.VectorViewModelAction
|
||||||
import im.vector.app.features.call.conference.ConferenceEvent
|
import im.vector.app.features.call.conference.ConferenceEvent
|
||||||
|
import im.vector.app.features.voicebroadcast.model.VoiceBroadcast
|
||||||
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
|
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageStickerContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageStickerContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageWithAttachmentContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageWithAttachmentContent
|
||||||
@ -129,10 +130,10 @@ sealed class RoomDetailAction : VectorViewModelAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sealed class Listening : VoiceBroadcastAction() {
|
sealed class Listening : VoiceBroadcastAction() {
|
||||||
data class PlayOrResume(val voiceBroadcastId: String) : Listening()
|
data class PlayOrResume(val voiceBroadcast: VoiceBroadcast) : Listening()
|
||||||
object Pause : Listening()
|
object Pause : Listening()
|
||||||
object Stop : Listening()
|
object Stop : Listening()
|
||||||
data class SeekTo(val voiceBroadcastId: String, val positionMillis: Int) : Listening()
|
data class SeekTo(val voiceBroadcast: VoiceBroadcast, val positionMillis: Int) : Listening()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -634,10 +634,10 @@ class TimelineViewModel @AssistedInject constructor(
|
|||||||
VoiceBroadcastAction.Recording.Pause -> voiceBroadcastHelper.pauseVoiceBroadcast(room.roomId)
|
VoiceBroadcastAction.Recording.Pause -> voiceBroadcastHelper.pauseVoiceBroadcast(room.roomId)
|
||||||
VoiceBroadcastAction.Recording.Resume -> voiceBroadcastHelper.resumeVoiceBroadcast(room.roomId)
|
VoiceBroadcastAction.Recording.Resume -> voiceBroadcastHelper.resumeVoiceBroadcast(room.roomId)
|
||||||
VoiceBroadcastAction.Recording.Stop -> voiceBroadcastHelper.stopVoiceBroadcast(room.roomId)
|
VoiceBroadcastAction.Recording.Stop -> voiceBroadcastHelper.stopVoiceBroadcast(room.roomId)
|
||||||
is VoiceBroadcastAction.Listening.PlayOrResume -> voiceBroadcastHelper.playOrResumePlayback(room.roomId, action.voiceBroadcastId)
|
is VoiceBroadcastAction.Listening.PlayOrResume -> voiceBroadcastHelper.playOrResumePlayback(action.voiceBroadcast)
|
||||||
VoiceBroadcastAction.Listening.Pause -> voiceBroadcastHelper.pausePlayback()
|
VoiceBroadcastAction.Listening.Pause -> voiceBroadcastHelper.pausePlayback()
|
||||||
VoiceBroadcastAction.Listening.Stop -> voiceBroadcastHelper.stopPlayback()
|
VoiceBroadcastAction.Listening.Stop -> voiceBroadcastHelper.stopPlayback()
|
||||||
is VoiceBroadcastAction.Listening.SeekTo -> voiceBroadcastHelper.seekTo(action.voiceBroadcastId, action.positionMillis)
|
is VoiceBroadcastAction.Listening.SeekTo -> voiceBroadcastHelper.seekTo(action.voiceBroadcast, action.positionMillis)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ import im.vector.app.features.home.room.detail.timeline.item.MessageVoiceBroadca
|
|||||||
import im.vector.app.features.home.room.detail.timeline.item.MessageVoiceBroadcastRecordingItem_
|
import im.vector.app.features.home.room.detail.timeline.item.MessageVoiceBroadcastRecordingItem_
|
||||||
import im.vector.app.features.voicebroadcast.listening.VoiceBroadcastPlayer
|
import im.vector.app.features.voicebroadcast.listening.VoiceBroadcastPlayer
|
||||||
import im.vector.app.features.voicebroadcast.model.MessageVoiceBroadcastInfoContent
|
import im.vector.app.features.voicebroadcast.model.MessageVoiceBroadcastInfoContent
|
||||||
|
import im.vector.app.features.voicebroadcast.model.VoiceBroadcast
|
||||||
import im.vector.app.features.voicebroadcast.model.VoiceBroadcastState
|
import im.vector.app.features.voicebroadcast.model.VoiceBroadcastState
|
||||||
import im.vector.app.features.voicebroadcast.model.asVoiceBroadcastEvent
|
import im.vector.app.features.voicebroadcast.model.asVoiceBroadcastEvent
|
||||||
import im.vector.app.features.voicebroadcast.recording.VoiceBroadcastRecorder
|
import im.vector.app.features.voicebroadcast.recording.VoiceBroadcastRecorder
|
||||||
@ -60,14 +61,14 @@ class VoiceBroadcastItemFactory @Inject constructor(
|
|||||||
val voiceBroadcastEventsGroup = params.eventsGroup?.let { VoiceBroadcastEventsGroup(it) } ?: return null
|
val voiceBroadcastEventsGroup = params.eventsGroup?.let { VoiceBroadcastEventsGroup(it) } ?: return null
|
||||||
val voiceBroadcastEvent = voiceBroadcastEventsGroup.getLastDisplayableEvent().root.asVoiceBroadcastEvent() ?: return null
|
val voiceBroadcastEvent = voiceBroadcastEventsGroup.getLastDisplayableEvent().root.asVoiceBroadcastEvent() ?: return null
|
||||||
val voiceBroadcastContent = voiceBroadcastEvent.content ?: return null
|
val voiceBroadcastContent = voiceBroadcastEvent.content ?: return null
|
||||||
val voiceBroadcastId = voiceBroadcastEventsGroup.voiceBroadcastId
|
val voiceBroadcast = VoiceBroadcast(voiceBroadcastId = voiceBroadcastEventsGroup.voiceBroadcastId, roomId = params.event.roomId)
|
||||||
|
|
||||||
val isRecording = voiceBroadcastContent.voiceBroadcastState != VoiceBroadcastState.STOPPED &&
|
val isRecording = voiceBroadcastContent.voiceBroadcastState != VoiceBroadcastState.STOPPED &&
|
||||||
voiceBroadcastEvent.root.stateKey == session.myUserId &&
|
voiceBroadcastEvent.root.stateKey == session.myUserId &&
|
||||||
messageContent.deviceId == session.sessionParams.deviceId
|
messageContent.deviceId == session.sessionParams.deviceId
|
||||||
|
|
||||||
val voiceBroadcastAttributes = AbsMessageVoiceBroadcastItem.Attributes(
|
val voiceBroadcastAttributes = AbsMessageVoiceBroadcastItem.Attributes(
|
||||||
voiceBroadcastId = voiceBroadcastId,
|
voiceBroadcast = voiceBroadcast,
|
||||||
voiceBroadcastState = voiceBroadcastContent.voiceBroadcastState,
|
voiceBroadcastState = voiceBroadcastContent.voiceBroadcastState,
|
||||||
duration = voiceBroadcastEventsGroup.getDuration(),
|
duration = voiceBroadcastEventsGroup.getDuration(),
|
||||||
recorderName = params.event.root.stateKey?.let { session.getUserOrDefault(it) }?.toMatrixItem()?.getBestName().orEmpty(),
|
recorderName = params.event.root.stateKey?.let { session.getUserOrDefault(it) }?.toMatrixItem()?.getBestName().orEmpty(),
|
||||||
@ -92,7 +93,7 @@ class VoiceBroadcastItemFactory @Inject constructor(
|
|||||||
voiceBroadcastAttributes: AbsMessageVoiceBroadcastItem.Attributes,
|
voiceBroadcastAttributes: AbsMessageVoiceBroadcastItem.Attributes,
|
||||||
): MessageVoiceBroadcastRecordingItem {
|
): MessageVoiceBroadcastRecordingItem {
|
||||||
return MessageVoiceBroadcastRecordingItem_()
|
return MessageVoiceBroadcastRecordingItem_()
|
||||||
.id("voice_broadcast_${voiceBroadcastAttributes.voiceBroadcastId}")
|
.id("voice_broadcast_${voiceBroadcastAttributes.voiceBroadcast.voiceBroadcastId}")
|
||||||
.attributes(attributes)
|
.attributes(attributes)
|
||||||
.voiceBroadcastAttributes(voiceBroadcastAttributes)
|
.voiceBroadcastAttributes(voiceBroadcastAttributes)
|
||||||
.highlighted(highlight)
|
.highlighted(highlight)
|
||||||
@ -105,7 +106,7 @@ class VoiceBroadcastItemFactory @Inject constructor(
|
|||||||
voiceBroadcastAttributes: AbsMessageVoiceBroadcastItem.Attributes,
|
voiceBroadcastAttributes: AbsMessageVoiceBroadcastItem.Attributes,
|
||||||
): MessageVoiceBroadcastListeningItem {
|
): MessageVoiceBroadcastListeningItem {
|
||||||
return MessageVoiceBroadcastListeningItem_()
|
return MessageVoiceBroadcastListeningItem_()
|
||||||
.id("voice_broadcast_${voiceBroadcastAttributes.voiceBroadcastId}")
|
.id("voice_broadcast_${voiceBroadcastAttributes.voiceBroadcast.voiceBroadcastId}")
|
||||||
.attributes(attributes)
|
.attributes(attributes)
|
||||||
.voiceBroadcastAttributes(voiceBroadcastAttributes)
|
.voiceBroadcastAttributes(voiceBroadcastAttributes)
|
||||||
.highlighted(highlight)
|
.highlighted(highlight)
|
||||||
|
@ -27,6 +27,7 @@ import im.vector.app.core.resources.ColorProvider
|
|||||||
import im.vector.app.core.resources.DrawableProvider
|
import im.vector.app.core.resources.DrawableProvider
|
||||||
import im.vector.app.features.home.room.detail.timeline.helper.AudioMessagePlaybackTracker
|
import im.vector.app.features.home.room.detail.timeline.helper.AudioMessagePlaybackTracker
|
||||||
import im.vector.app.features.voicebroadcast.listening.VoiceBroadcastPlayer
|
import im.vector.app.features.voicebroadcast.listening.VoiceBroadcastPlayer
|
||||||
|
import im.vector.app.features.voicebroadcast.model.VoiceBroadcast
|
||||||
import im.vector.app.features.voicebroadcast.model.VoiceBroadcastState
|
import im.vector.app.features.voicebroadcast.model.VoiceBroadcastState
|
||||||
import im.vector.app.features.voicebroadcast.recording.VoiceBroadcastRecorder
|
import im.vector.app.features.voicebroadcast.recording.VoiceBroadcastRecorder
|
||||||
import org.matrix.android.sdk.api.util.MatrixItem
|
import org.matrix.android.sdk.api.util.MatrixItem
|
||||||
@ -36,7 +37,7 @@ abstract class AbsMessageVoiceBroadcastItem<H : AbsMessageVoiceBroadcastItem.Hol
|
|||||||
@EpoxyAttribute
|
@EpoxyAttribute
|
||||||
lateinit var voiceBroadcastAttributes: Attributes
|
lateinit var voiceBroadcastAttributes: Attributes
|
||||||
|
|
||||||
protected val voiceBroadcastId get() = voiceBroadcastAttributes.voiceBroadcastId
|
protected val voiceBroadcast get() = voiceBroadcastAttributes.voiceBroadcast
|
||||||
protected val voiceBroadcastState get() = voiceBroadcastAttributes.voiceBroadcastState
|
protected val voiceBroadcastState get() = voiceBroadcastAttributes.voiceBroadcastState
|
||||||
protected val recorderName get() = voiceBroadcastAttributes.recorderName
|
protected val recorderName get() = voiceBroadcastAttributes.recorderName
|
||||||
protected val recorder get() = voiceBroadcastAttributes.recorder
|
protected val recorder get() = voiceBroadcastAttributes.recorder
|
||||||
@ -95,7 +96,7 @@ abstract class AbsMessageVoiceBroadcastItem<H : AbsMessageVoiceBroadcastItem.Hol
|
|||||||
}
|
}
|
||||||
|
|
||||||
data class Attributes(
|
data class Attributes(
|
||||||
val voiceBroadcastId: String,
|
val voiceBroadcast: VoiceBroadcast,
|
||||||
val voiceBroadcastState: VoiceBroadcastState?,
|
val voiceBroadcastState: VoiceBroadcastState?,
|
||||||
val duration: Int,
|
val duration: Int,
|
||||||
val recorderName: String,
|
val recorderName: String,
|
||||||
|
@ -46,7 +46,7 @@ abstract class MessageVoiceBroadcastListeningItem : AbsMessageVoiceBroadcastItem
|
|||||||
playerListener = VoiceBroadcastPlayer.Listener { state ->
|
playerListener = VoiceBroadcastPlayer.Listener { state ->
|
||||||
renderPlayingState(holder, state)
|
renderPlayingState(holder, state)
|
||||||
}
|
}
|
||||||
player.addListener(voiceBroadcastId, playerListener)
|
player.addListener(voiceBroadcast, playerListener)
|
||||||
bindSeekBar(holder)
|
bindSeekBar(holder)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ abstract class MessageVoiceBroadcastListeningItem : AbsMessageVoiceBroadcastItem
|
|||||||
VoiceBroadcastPlayer.State.PAUSED -> {
|
VoiceBroadcastPlayer.State.PAUSED -> {
|
||||||
playPauseButton.setImageResource(R.drawable.ic_play_pause_play)
|
playPauseButton.setImageResource(R.drawable.ic_play_pause_play)
|
||||||
playPauseButton.contentDescription = view.resources.getString(R.string.a11y_play_voice_broadcast)
|
playPauseButton.contentDescription = view.resources.getString(R.string.a11y_play_voice_broadcast)
|
||||||
playPauseButton.onClick { callback?.onTimelineItemAction(VoiceBroadcastAction.Listening.PlayOrResume(voiceBroadcastId)) }
|
playPauseButton.onClick { callback?.onTimelineItemAction(VoiceBroadcastAction.Listening.PlayOrResume(voiceBroadcast)) }
|
||||||
seekBar.isEnabled = false
|
seekBar.isEnabled = false
|
||||||
}
|
}
|
||||||
VoiceBroadcastPlayer.State.BUFFERING -> {
|
VoiceBroadcastPlayer.State.BUFFERING -> {
|
||||||
@ -98,11 +98,11 @@ abstract class MessageVoiceBroadcastListeningItem : AbsMessageVoiceBroadcastItem
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onStopTrackingTouch(seekBar: SeekBar) {
|
override fun onStopTrackingTouch(seekBar: SeekBar) {
|
||||||
callback?.onTimelineItemAction(VoiceBroadcastAction.Listening.SeekTo(voiceBroadcastId, seekBar.progress))
|
callback?.onTimelineItemAction(VoiceBroadcastAction.Listening.SeekTo(voiceBroadcast, seekBar.progress))
|
||||||
isUserSeeking = false
|
isUserSeeking = false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
playbackTracker.track(voiceBroadcastId, object : AudioMessagePlaybackTracker.Listener {
|
playbackTracker.track(voiceBroadcast.voiceBroadcastId, object : AudioMessagePlaybackTracker.Listener {
|
||||||
override fun onUpdate(state: AudioMessagePlaybackTracker.Listener.State) {
|
override fun onUpdate(state: AudioMessagePlaybackTracker.Listener.State) {
|
||||||
when (state) {
|
when (state) {
|
||||||
is AudioMessagePlaybackTracker.Listener.State.Paused -> {
|
is AudioMessagePlaybackTracker.Listener.State.Paused -> {
|
||||||
@ -126,9 +126,9 @@ abstract class MessageVoiceBroadcastListeningItem : AbsMessageVoiceBroadcastItem
|
|||||||
|
|
||||||
override fun unbind(holder: Holder) {
|
override fun unbind(holder: Holder) {
|
||||||
super.unbind(holder)
|
super.unbind(holder)
|
||||||
player.removeListener(voiceBroadcastId, playerListener)
|
player.removeListener(voiceBroadcast, playerListener)
|
||||||
holder.seekBar.setOnSeekBarChangeListener(null)
|
holder.seekBar.setOnSeekBarChangeListener(null)
|
||||||
playbackTracker.untrack(voiceBroadcastId)
|
playbackTracker.untrack(voiceBroadcast.voiceBroadcastId)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getViewStubId() = STUB_ID
|
override fun getViewStubId() = STUB_ID
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package im.vector.app.features.voicebroadcast
|
package im.vector.app.features.voicebroadcast
|
||||||
|
|
||||||
import im.vector.app.features.voicebroadcast.listening.VoiceBroadcastPlayer
|
import im.vector.app.features.voicebroadcast.listening.VoiceBroadcastPlayer
|
||||||
|
import im.vector.app.features.voicebroadcast.model.VoiceBroadcast
|
||||||
import im.vector.app.features.voicebroadcast.recording.usecase.PauseVoiceBroadcastUseCase
|
import im.vector.app.features.voicebroadcast.recording.usecase.PauseVoiceBroadcastUseCase
|
||||||
import im.vector.app.features.voicebroadcast.recording.usecase.ResumeVoiceBroadcastUseCase
|
import im.vector.app.features.voicebroadcast.recording.usecase.ResumeVoiceBroadcastUseCase
|
||||||
import im.vector.app.features.voicebroadcast.recording.usecase.StartVoiceBroadcastUseCase
|
import im.vector.app.features.voicebroadcast.recording.usecase.StartVoiceBroadcastUseCase
|
||||||
@ -41,14 +42,14 @@ class VoiceBroadcastHelper @Inject constructor(
|
|||||||
|
|
||||||
suspend fun stopVoiceBroadcast(roomId: String) = stopVoiceBroadcastUseCase.execute(roomId)
|
suspend fun stopVoiceBroadcast(roomId: String) = stopVoiceBroadcastUseCase.execute(roomId)
|
||||||
|
|
||||||
fun playOrResumePlayback(roomId: String, voiceBroadcastId: String) = voiceBroadcastPlayer.playOrResume(roomId, voiceBroadcastId)
|
fun playOrResumePlayback(voiceBroadcast: VoiceBroadcast) = voiceBroadcastPlayer.playOrResume(voiceBroadcast)
|
||||||
|
|
||||||
fun pausePlayback() = voiceBroadcastPlayer.pause()
|
fun pausePlayback() = voiceBroadcastPlayer.pause()
|
||||||
|
|
||||||
fun stopPlayback() = voiceBroadcastPlayer.stop()
|
fun stopPlayback() = voiceBroadcastPlayer.stop()
|
||||||
|
|
||||||
fun seekTo(voiceBroadcastId: String, positionMillis: Int) {
|
fun seekTo(voiceBroadcast: VoiceBroadcast, positionMillis: Int) {
|
||||||
if (voiceBroadcastPlayer.currentVoiceBroadcastId == voiceBroadcastId) {
|
if (voiceBroadcastPlayer.currentVoiceBroadcast == voiceBroadcast) {
|
||||||
voiceBroadcastPlayer.seekTo(positionMillis)
|
voiceBroadcastPlayer.seekTo(positionMillis)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,12 +16,14 @@
|
|||||||
|
|
||||||
package im.vector.app.features.voicebroadcast.listening
|
package im.vector.app.features.voicebroadcast.listening
|
||||||
|
|
||||||
|
import im.vector.app.features.voicebroadcast.model.VoiceBroadcast
|
||||||
|
|
||||||
interface VoiceBroadcastPlayer {
|
interface VoiceBroadcastPlayer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current playing voice broadcast identifier, if any.
|
* The current playing voice broadcast, if any.
|
||||||
*/
|
*/
|
||||||
val currentVoiceBroadcastId: String?
|
val currentVoiceBroadcast: VoiceBroadcast?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current playing [State], [State.IDLE] by default.
|
* The current playing [State], [State.IDLE] by default.
|
||||||
@ -31,7 +33,7 @@ interface VoiceBroadcastPlayer {
|
|||||||
/**
|
/**
|
||||||
* Start playback of the given voice broadcast.
|
* Start playback of the given voice broadcast.
|
||||||
*/
|
*/
|
||||||
fun playOrResume(roomId: String, voiceBroadcastId: String)
|
fun playOrResume(voiceBroadcast: VoiceBroadcast)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pause playback of the current voice broadcast, if any.
|
* Pause playback of the current voice broadcast, if any.
|
||||||
@ -49,14 +51,14 @@ interface VoiceBroadcastPlayer {
|
|||||||
fun seekTo(positionMillis: Int)
|
fun seekTo(positionMillis: Int)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a [Listener] to the given voice broadcast id.
|
* Add a [Listener] to the given voice broadcast.
|
||||||
*/
|
*/
|
||||||
fun addListener(voiceBroadcastId: String, listener: Listener)
|
fun addListener(voiceBroadcast: VoiceBroadcast, listener: Listener)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a [Listener] from the given voice broadcast id.
|
* Remove a [Listener] from the given voice broadcast.
|
||||||
*/
|
*/
|
||||||
fun removeListener(voiceBroadcastId: String, listener: Listener)
|
fun removeListener(voiceBroadcast: VoiceBroadcast, listener: Listener)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Player states.
|
* Player states.
|
||||||
|
@ -26,9 +26,10 @@ import im.vector.app.features.voicebroadcast.duration
|
|||||||
import im.vector.app.features.voicebroadcast.listening.VoiceBroadcastPlayer.Listener
|
import im.vector.app.features.voicebroadcast.listening.VoiceBroadcastPlayer.Listener
|
||||||
import im.vector.app.features.voicebroadcast.listening.VoiceBroadcastPlayer.State
|
import im.vector.app.features.voicebroadcast.listening.VoiceBroadcastPlayer.State
|
||||||
import im.vector.app.features.voicebroadcast.listening.usecase.GetLiveVoiceBroadcastChunksUseCase
|
import im.vector.app.features.voicebroadcast.listening.usecase.GetLiveVoiceBroadcastChunksUseCase
|
||||||
|
import im.vector.app.features.voicebroadcast.model.VoiceBroadcast
|
||||||
import im.vector.app.features.voicebroadcast.model.VoiceBroadcastState
|
import im.vector.app.features.voicebroadcast.model.VoiceBroadcastState
|
||||||
import im.vector.app.features.voicebroadcast.sequence
|
import im.vector.app.features.voicebroadcast.sequence
|
||||||
import im.vector.app.features.voicebroadcast.usecase.GetVoiceBroadcastUseCase
|
import im.vector.app.features.voicebroadcast.usecase.GetVoiceBroadcastEventUseCase
|
||||||
import im.vector.lib.core.utils.timer.CountUpTimer
|
import im.vector.lib.core.utils.timer.CountUpTimer
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@ -51,7 +52,7 @@ import javax.inject.Singleton
|
|||||||
class VoiceBroadcastPlayerImpl @Inject constructor(
|
class VoiceBroadcastPlayerImpl @Inject constructor(
|
||||||
private val sessionHolder: ActiveSessionHolder,
|
private val sessionHolder: ActiveSessionHolder,
|
||||||
private val playbackTracker: AudioMessagePlaybackTracker,
|
private val playbackTracker: AudioMessagePlaybackTracker,
|
||||||
private val getVoiceBroadcastUseCase: GetVoiceBroadcastUseCase,
|
private val getVoiceBroadcastEventUseCase: GetVoiceBroadcastEventUseCase,
|
||||||
private val getLiveVoiceBroadcastChunksUseCase: GetLiveVoiceBroadcastChunksUseCase
|
private val getLiveVoiceBroadcastChunksUseCase: GetLiveVoiceBroadcastChunksUseCase
|
||||||
) : VoiceBroadcastPlayer {
|
) : VoiceBroadcastPlayer {
|
||||||
|
|
||||||
@ -73,7 +74,7 @@ class VoiceBroadcastPlayerImpl @Inject constructor(
|
|||||||
|
|
||||||
private var isLive: Boolean = false
|
private var isLive: Boolean = false
|
||||||
|
|
||||||
override var currentVoiceBroadcastId: String? = null
|
override var currentVoiceBroadcast: VoiceBroadcast? = null
|
||||||
|
|
||||||
override var playingState = State.IDLE
|
override var playingState = State.IDLE
|
||||||
@MainThread
|
@MainThread
|
||||||
@ -81,7 +82,7 @@ class VoiceBroadcastPlayerImpl @Inject constructor(
|
|||||||
Timber.w("## VoiceBroadcastPlayer state: $field -> $value")
|
Timber.w("## VoiceBroadcastPlayer state: $field -> $value")
|
||||||
field = value
|
field = value
|
||||||
// Notify state change to all the listeners attached to the current voice broadcast id
|
// Notify state change to all the listeners attached to the current voice broadcast id
|
||||||
currentVoiceBroadcastId?.let { voiceBroadcastId ->
|
currentVoiceBroadcast?.voiceBroadcastId?.let { voiceBroadcastId ->
|
||||||
when (value) {
|
when (value) {
|
||||||
State.PLAYING -> {
|
State.PLAYING -> {
|
||||||
playbackTracker.startPlayback(voiceBroadcastId)
|
playbackTracker.startPlayback(voiceBroadcastId)
|
||||||
@ -103,17 +104,16 @@ class VoiceBroadcastPlayerImpl @Inject constructor(
|
|||||||
listeners[voiceBroadcastId]?.forEach { listener -> listener.onStateChanged(value) }
|
listeners[voiceBroadcastId]?.forEach { listener -> listener.onStateChanged(value) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private var currentRoomId: String? = null
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map voiceBroadcastId to listeners.
|
* Map voiceBroadcastId to listeners.
|
||||||
*/
|
*/
|
||||||
private val listeners: MutableMap<String, CopyOnWriteArrayList<Listener>> = mutableMapOf()
|
private val listeners: MutableMap<String, CopyOnWriteArrayList<Listener>> = mutableMapOf()
|
||||||
|
|
||||||
override fun playOrResume(roomId: String, voiceBroadcastId: String) {
|
override fun playOrResume(voiceBroadcast: VoiceBroadcast) {
|
||||||
val hasChanged = currentVoiceBroadcastId != voiceBroadcastId
|
val hasChanged = currentVoiceBroadcast != voiceBroadcast
|
||||||
when {
|
when {
|
||||||
hasChanged -> startPlayback(roomId, voiceBroadcastId)
|
hasChanged -> startPlayback(voiceBroadcast)
|
||||||
playingState == State.PAUSED -> resumePlayback()
|
playingState == State.PAUSED -> resumePlayback()
|
||||||
else -> Unit
|
else -> Unit
|
||||||
}
|
}
|
||||||
@ -152,37 +152,35 @@ class VoiceBroadcastPlayerImpl @Inject constructor(
|
|||||||
playlist = emptyList()
|
playlist = emptyList()
|
||||||
currentSequence = null
|
currentSequence = null
|
||||||
|
|
||||||
currentRoomId = null
|
currentVoiceBroadcast = null
|
||||||
currentVoiceBroadcastId = null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun addListener(voiceBroadcastId: String, listener: Listener) {
|
override fun addListener(voiceBroadcast: VoiceBroadcast, listener: Listener) {
|
||||||
listeners[voiceBroadcastId]?.add(listener) ?: run {
|
listeners[voiceBroadcast.voiceBroadcastId]?.add(listener) ?: run {
|
||||||
listeners[voiceBroadcastId] = CopyOnWriteArrayList<Listener>().apply { add(listener) }
|
listeners[voiceBroadcast.voiceBroadcastId] = CopyOnWriteArrayList<Listener>().apply { add(listener) }
|
||||||
}
|
}
|
||||||
if (voiceBroadcastId == currentVoiceBroadcastId) listener.onStateChanged(playingState) else listener.onStateChanged(State.IDLE)
|
listener.onStateChanged(if (voiceBroadcast == currentVoiceBroadcast) playingState else State.IDLE)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun removeListener(voiceBroadcastId: String, listener: Listener) {
|
override fun removeListener(voiceBroadcast: VoiceBroadcast, listener: Listener) {
|
||||||
listeners[voiceBroadcastId]?.remove(listener)
|
listeners[voiceBroadcast.voiceBroadcastId]?.remove(listener)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startPlayback(roomId: String, eventId: String) {
|
private fun startPlayback(voiceBroadcast: VoiceBroadcast) {
|
||||||
// Stop listening previous voice broadcast if any
|
// Stop listening previous voice broadcast if any
|
||||||
if (playingState != State.IDLE) stop()
|
if (playingState != State.IDLE) stop()
|
||||||
|
|
||||||
currentRoomId = roomId
|
currentVoiceBroadcast = voiceBroadcast
|
||||||
currentVoiceBroadcastId = eventId
|
|
||||||
|
|
||||||
playingState = State.BUFFERING
|
playingState = State.BUFFERING
|
||||||
|
|
||||||
val voiceBroadcastState = getVoiceBroadcastUseCase.execute(roomId, eventId)?.content?.voiceBroadcastState
|
val voiceBroadcastState = getVoiceBroadcastEventUseCase.execute(voiceBroadcast)?.content?.voiceBroadcastState
|
||||||
isLive = voiceBroadcastState != null && voiceBroadcastState != VoiceBroadcastState.STOPPED
|
isLive = voiceBroadcastState != null && voiceBroadcastState != VoiceBroadcastState.STOPPED
|
||||||
fetchPlaylistAndStartPlayback(roomId, eventId)
|
fetchPlaylistAndStartPlayback(voiceBroadcast)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun fetchPlaylistAndStartPlayback(roomId: String, voiceBroadcastId: String) {
|
private fun fetchPlaylistAndStartPlayback(voiceBroadcast: VoiceBroadcast) {
|
||||||
fetchPlaylistJob = getLiveVoiceBroadcastChunksUseCase.execute(roomId, voiceBroadcastId)
|
fetchPlaylistJob = getLiveVoiceBroadcastChunksUseCase.execute(voiceBroadcast)
|
||||||
.onEach(this::updatePlaylist)
|
.onEach(this::updatePlaylist)
|
||||||
.launchIn(coroutineScope)
|
.launchIn(coroutineScope)
|
||||||
}
|
}
|
||||||
@ -347,9 +345,8 @@ class VoiceBroadcastPlayerImpl @Inject constructor(
|
|||||||
|
|
||||||
override fun onCompletion(mp: MediaPlayer) {
|
override fun onCompletion(mp: MediaPlayer) {
|
||||||
if (nextMediaPlayer != null) return
|
if (nextMediaPlayer != null) return
|
||||||
val roomId = currentRoomId ?: return
|
val voiceBroadcast = currentVoiceBroadcast ?: return
|
||||||
val voiceBroadcastId = currentVoiceBroadcastId ?: return
|
val voiceBroadcastEventContent = getVoiceBroadcastEventUseCase.execute(voiceBroadcast)?.content ?: return
|
||||||
val voiceBroadcastEventContent = getVoiceBroadcastUseCase.execute(roomId, voiceBroadcastId)?.content ?: return
|
|
||||||
isLive = voiceBroadcastEventContent.voiceBroadcastState != null && voiceBroadcastEventContent.voiceBroadcastState != VoiceBroadcastState.STOPPED
|
isLive = voiceBroadcastEventContent.voiceBroadcastState != null && voiceBroadcastEventContent.voiceBroadcastState != VoiceBroadcastState.STOPPED
|
||||||
|
|
||||||
if (!isLive && voiceBroadcastEventContent.lastChunkSequence == currentSequence) {
|
if (!isLive && voiceBroadcastEventContent.lastChunkSequence == currentSequence) {
|
||||||
|
@ -19,11 +19,12 @@ package im.vector.app.features.voicebroadcast.listening.usecase
|
|||||||
import im.vector.app.core.di.ActiveSessionHolder
|
import im.vector.app.core.di.ActiveSessionHolder
|
||||||
import im.vector.app.features.voicebroadcast.getVoiceBroadcastEventId
|
import im.vector.app.features.voicebroadcast.getVoiceBroadcastEventId
|
||||||
import im.vector.app.features.voicebroadcast.isVoiceBroadcast
|
import im.vector.app.features.voicebroadcast.isVoiceBroadcast
|
||||||
|
import im.vector.app.features.voicebroadcast.model.VoiceBroadcast
|
||||||
import im.vector.app.features.voicebroadcast.model.VoiceBroadcastEvent
|
import im.vector.app.features.voicebroadcast.model.VoiceBroadcastEvent
|
||||||
import im.vector.app.features.voicebroadcast.model.VoiceBroadcastState
|
import im.vector.app.features.voicebroadcast.model.VoiceBroadcastState
|
||||||
import im.vector.app.features.voicebroadcast.model.asVoiceBroadcastEvent
|
import im.vector.app.features.voicebroadcast.model.asVoiceBroadcastEvent
|
||||||
import im.vector.app.features.voicebroadcast.sequence
|
import im.vector.app.features.voicebroadcast.sequence
|
||||||
import im.vector.app.features.voicebroadcast.usecase.GetVoiceBroadcastUseCase
|
import im.vector.app.features.voicebroadcast.usecase.GetVoiceBroadcastEventUseCase
|
||||||
import kotlinx.coroutines.channels.awaitClose
|
import kotlinx.coroutines.channels.awaitClose
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.callbackFlow
|
import kotlinx.coroutines.flow.callbackFlow
|
||||||
@ -44,19 +45,19 @@ import javax.inject.Inject
|
|||||||
*/
|
*/
|
||||||
class GetLiveVoiceBroadcastChunksUseCase @Inject constructor(
|
class GetLiveVoiceBroadcastChunksUseCase @Inject constructor(
|
||||||
private val activeSessionHolder: ActiveSessionHolder,
|
private val activeSessionHolder: ActiveSessionHolder,
|
||||||
private val getVoiceBroadcastUseCase: GetVoiceBroadcastUseCase,
|
private val getVoiceBroadcastEventUseCase: GetVoiceBroadcastEventUseCase,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun execute(roomId: String, voiceBroadcastId: String): Flow<List<MessageAudioEvent>> {
|
fun execute(voiceBroadcast: VoiceBroadcast): Flow<List<MessageAudioEvent>> {
|
||||||
val session = activeSessionHolder.getSafeActiveSession() ?: return emptyFlow()
|
val session = activeSessionHolder.getSafeActiveSession() ?: return emptyFlow()
|
||||||
val room = session.roomService().getRoom(roomId) ?: return emptyFlow()
|
val room = session.roomService().getRoom(voiceBroadcast.roomId) ?: return emptyFlow()
|
||||||
val timeline = room.timelineService().createTimeline(null, TimelineSettings(5))
|
val timeline = room.timelineService().createTimeline(null, TimelineSettings(5))
|
||||||
|
|
||||||
// Get initial chunks
|
// Get initial chunks
|
||||||
val existingChunks = room.timelineService().getTimelineEventsRelatedTo(RelationType.REFERENCE, voiceBroadcastId)
|
val existingChunks = room.timelineService().getTimelineEventsRelatedTo(RelationType.REFERENCE, voiceBroadcast.voiceBroadcastId)
|
||||||
.mapNotNull { timelineEvent -> timelineEvent.root.asMessageAudioEvent().takeIf { it.isVoiceBroadcast() } }
|
.mapNotNull { timelineEvent -> timelineEvent.root.asMessageAudioEvent().takeIf { it.isVoiceBroadcast() } }
|
||||||
|
|
||||||
val voiceBroadcastEvent = getVoiceBroadcastUseCase.execute(roomId, voiceBroadcastId)
|
val voiceBroadcastEvent = getVoiceBroadcastEventUseCase.execute(voiceBroadcast)
|
||||||
val voiceBroadcastState = voiceBroadcastEvent?.content?.voiceBroadcastState
|
val voiceBroadcastState = voiceBroadcastEvent?.content?.voiceBroadcastState
|
||||||
|
|
||||||
return if (voiceBroadcastState == null || voiceBroadcastState == VoiceBroadcastState.STOPPED) {
|
return if (voiceBroadcastState == null || voiceBroadcastState == VoiceBroadcastState.STOPPED) {
|
||||||
@ -82,7 +83,7 @@ class GetLiveVoiceBroadcastChunksUseCase @Inject constructor(
|
|||||||
lastSequence = stopEvent.content?.lastChunkSequence
|
lastSequence = stopEvent.content?.lastChunkSequence
|
||||||
}
|
}
|
||||||
|
|
||||||
val newChunks = newEvents.mapToChunkEvents(voiceBroadcastId, voiceBroadcastEvent.root.senderId)
|
val newChunks = newEvents.mapToChunkEvents(voiceBroadcast.voiceBroadcastId, voiceBroadcastEvent.root.senderId)
|
||||||
|
|
||||||
// Notify about new chunks
|
// Notify about new chunks
|
||||||
if (newChunks.isNotEmpty()) {
|
if (newChunks.isNotEmpty()) {
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.app.features.voicebroadcast.model
|
||||||
|
|
||||||
|
data class VoiceBroadcast(
|
||||||
|
val voiceBroadcastId: String,
|
||||||
|
val roomId: String,
|
||||||
|
)
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package im.vector.app.features.voicebroadcast.usecase
|
package im.vector.app.features.voicebroadcast.usecase
|
||||||
|
|
||||||
|
import im.vector.app.features.voicebroadcast.model.VoiceBroadcast
|
||||||
import im.vector.app.features.voicebroadcast.model.VoiceBroadcastEvent
|
import im.vector.app.features.voicebroadcast.model.VoiceBroadcastEvent
|
||||||
import im.vector.app.features.voicebroadcast.model.asVoiceBroadcastEvent
|
import im.vector.app.features.voicebroadcast.model.asVoiceBroadcastEvent
|
||||||
import org.matrix.android.sdk.api.session.Session
|
import org.matrix.android.sdk.api.session.Session
|
||||||
@ -24,17 +25,18 @@ import org.matrix.android.sdk.api.session.getRoom
|
|||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class GetVoiceBroadcastUseCase @Inject constructor(
|
class GetVoiceBroadcastEventUseCase @Inject constructor(
|
||||||
private val session: Session,
|
private val session: Session,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun execute(roomId: String, eventId: String): VoiceBroadcastEvent? {
|
fun execute(voiceBroadcast: VoiceBroadcast): VoiceBroadcastEvent? {
|
||||||
val room = session.getRoom(roomId) ?: error("Unknown roomId: $roomId")
|
val room = session.getRoom(voiceBroadcast.roomId) ?: error("Unknown roomId: ${voiceBroadcast.roomId}")
|
||||||
|
|
||||||
Timber.d("## GetVoiceBroadcastUseCase: get voice broadcast $eventId")
|
Timber.d("## GetVoiceBroadcastUseCase: get voice broadcast $voiceBroadcast")
|
||||||
|
|
||||||
val initialEvent = room.timelineService().getTimelineEvent(eventId)?.root?.asVoiceBroadcastEvent() // Fallback to initial event
|
val initialEvent = room.timelineService().getTimelineEvent(voiceBroadcast.voiceBroadcastId)?.root?.asVoiceBroadcastEvent()
|
||||||
val relatedEvents = room.timelineService().getTimelineEventsRelatedTo(RelationType.REFERENCE, eventId).sortedBy { it.root.originServerTs }
|
val relatedEvents = room.timelineService().getTimelineEventsRelatedTo(RelationType.REFERENCE, voiceBroadcast.voiceBroadcastId)
|
||||||
|
.sortedBy { it.root.originServerTs }
|
||||||
return relatedEvents.mapNotNull { it.root.asVoiceBroadcastEvent() }.lastOrNull() ?: initialEvent
|
return relatedEvents.mapNotNull { it.root.asVoiceBroadcastEvent() }.lastOrNull() ?: initialEvent
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user