mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2025-05-29 21:10:24 +02:00
Fixed notification implementation.
This commit is contained in:
parent
3b8d256bad
commit
0ab52e8f4d
@ -175,13 +175,13 @@ dependencies {
|
|||||||
implementation 'androidx.media3:media3-exoplayer:1.2.0'
|
implementation 'androidx.media3:media3-exoplayer:1.2.0'
|
||||||
implementation 'androidx.media3:media3-exoplayer-dash:1.2.0'
|
implementation 'androidx.media3:media3-exoplayer-dash:1.2.0'
|
||||||
implementation 'androidx.media3:media3-ui:1.2.0'
|
implementation 'androidx.media3:media3-ui:1.2.0'
|
||||||
implementation 'androidx.media3:media3-session:1.2.0'
|
|
||||||
implementation 'androidx.media3:media3-exoplayer-hls:1.2.0'
|
implementation 'androidx.media3:media3-exoplayer-hls:1.2.0'
|
||||||
implementation 'androidx.media3:media3-exoplayer-rtsp:1.2.0'
|
implementation 'androidx.media3:media3-exoplayer-rtsp:1.2.0'
|
||||||
implementation 'androidx.media3:media3-exoplayer-smoothstreaming:1.2.0'
|
implementation 'androidx.media3:media3-exoplayer-smoothstreaming:1.2.0'
|
||||||
implementation 'androidx.media3:media3-transformer:1.2.0'
|
implementation 'androidx.media3:media3-transformer:1.2.0'
|
||||||
implementation 'androidx.navigation:navigation-fragment-ktx:2.7.5'
|
implementation 'androidx.navigation:navigation-fragment-ktx:2.7.5'
|
||||||
implementation 'androidx.navigation:navigation-ui-ktx:2.7.5'
|
implementation 'androidx.navigation:navigation-ui-ktx:2.7.5'
|
||||||
|
implementation 'androidx.media:media:1.7.0'
|
||||||
|
|
||||||
//Other
|
//Other
|
||||||
implementation 'org.jmdns:jmdns:3.5.1'
|
implementation 'org.jmdns:jmdns:3.5.1'
|
||||||
|
@ -67,7 +67,7 @@ class VideoDownload {
|
|||||||
val videoEither: IPlatformVideo get() = videoDetails ?: video ?: throw IllegalStateException("Missing video?");
|
val videoEither: IPlatformVideo get() = videoDetails ?: video ?: throw IllegalStateException("Missing video?");
|
||||||
val id: PlatformID get() = videoEither.id
|
val id: PlatformID get() = videoEither.id
|
||||||
val name: String get() = videoEither.name;
|
val name: String get() = videoEither.name;
|
||||||
val thumbnail: String? get() = videoDetails?.thumbnails?.getHQThumbnail() ?: video?.thumbnails?.getHQThumbnail();
|
val thumbnail: String? get() = videoDetails?.thumbnails?.getHQThumbnail();
|
||||||
|
|
||||||
var targetPixelCount: Long? = null;
|
var targetPixelCount: Long? = null;
|
||||||
var targetBitrate: Long? = null;
|
var targetBitrate: Long? = null;
|
||||||
|
@ -12,6 +12,7 @@ import android.graphics.drawable.BitmapDrawable
|
|||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.graphics.drawable.Icon
|
import android.graphics.drawable.Icon
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import android.support.v4.media.session.PlaybackStateCompat
|
||||||
import android.text.Spanned
|
import android.text.Spanned
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
@ -571,9 +572,9 @@ class VideoDetailView : ConstraintLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_playerProgress.player = _player.exoPlayer?.player;
|
_playerProgress.player = _player.exoPlayer?.player;
|
||||||
_playerProgress.setProgressUpdateListener { _, _ ->
|
_playerProgress.setProgressUpdateListener { position, _ ->
|
||||||
StatePlayer.instance.updateMediaSessionPlaybackState();
|
StatePlayer.instance.updateMediaSessionPlaybackState(_player.exoPlayer?.getPlaybackStateCompat() ?: PlaybackStateCompat.STATE_NONE, position);
|
||||||
}
|
};
|
||||||
|
|
||||||
StatePlayer.instance.onQueueChanged.subscribe(this) {
|
StatePlayer.instance.onQueueChanged.subscribe(this) {
|
||||||
if(!_destroyed) {
|
if(!_destroyed) {
|
||||||
@ -1358,11 +1359,9 @@ class VideoDetailView : ConstraintLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
StatePlayer.instance.startOrUpdateMediaSession(context, video);
|
StatePlayer.instance.startOrUpdateMediaSession(context, video);
|
||||||
StatePlayer.instance.setCurrentlyPlaying(video);
|
StatePlayer.instance.setCurrentlyPlaying(video);
|
||||||
|
|
||||||
|
|
||||||
if(video.isLive && video.live != null) {
|
if(video.isLive && video.live != null) {
|
||||||
loadLiveChat(video);
|
loadLiveChat(video);
|
||||||
}
|
}
|
||||||
@ -1791,7 +1790,7 @@ class VideoDetailView : ConstraintLayout {
|
|||||||
_cast.setIsPlaying(playing);
|
_cast.setIsPlaying(playing);
|
||||||
} else {
|
} else {
|
||||||
StatePlayer.instance.updateMediaSession( null);
|
StatePlayer.instance.updateMediaSession( null);
|
||||||
StatePlayer.instance.updateMediaSessionPlaybackState();
|
StatePlayer.instance.updateMediaSessionPlaybackState(_player.exoPlayer?.getPlaybackStateCompat() ?: PlaybackStateCompat.STATE_NONE, _player.exoPlayer?.player?.currentPosition ?: 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(playing) {
|
if(playing) {
|
||||||
|
@ -2,6 +2,13 @@ package com.futo.platformplayer.helpers
|
|||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.annotation.OptIn
|
import androidx.annotation.OptIn
|
||||||
|
import androidx.media3.common.MediaItem
|
||||||
|
import androidx.media3.common.MediaMetadata
|
||||||
|
import androidx.media3.common.util.UnstableApi
|
||||||
|
import androidx.media3.datasource.ResolvingDataSource
|
||||||
|
import androidx.media3.exoplayer.dash.DashMediaSource
|
||||||
|
import androidx.media3.exoplayer.dash.manifest.DashManifestParser
|
||||||
|
import androidx.media3.exoplayer.source.MediaSource
|
||||||
import com.futo.platformplayer.api.media.models.streams.IVideoSourceDescriptor
|
import com.futo.platformplayer.api.media.models.streams.IVideoSourceDescriptor
|
||||||
import com.futo.platformplayer.api.media.models.streams.VideoUnMuxedSourceDescriptor
|
import com.futo.platformplayer.api.media.models.streams.VideoUnMuxedSourceDescriptor
|
||||||
import com.futo.platformplayer.api.media.models.streams.sources.IAudioSource
|
import com.futo.platformplayer.api.media.models.streams.sources.IAudioSource
|
||||||
@ -14,12 +21,6 @@ import com.futo.platformplayer.api.media.models.video.IPlatformVideoDetails
|
|||||||
import com.futo.platformplayer.api.media.platforms.js.models.sources.JSAudioUrlRangeSource
|
import com.futo.platformplayer.api.media.platforms.js.models.sources.JSAudioUrlRangeSource
|
||||||
import com.futo.platformplayer.api.media.platforms.js.models.sources.JSVideoUrlRangeSource
|
import com.futo.platformplayer.api.media.platforms.js.models.sources.JSVideoUrlRangeSource
|
||||||
import com.futo.platformplayer.logging.Logger
|
import com.futo.platformplayer.logging.Logger
|
||||||
import androidx.media3.common.MediaItem
|
|
||||||
import androidx.media3.common.util.UnstableApi
|
|
||||||
import androidx.media3.datasource.ResolvingDataSource
|
|
||||||
import androidx.media3.exoplayer.dash.DashMediaSource
|
|
||||||
import androidx.media3.exoplayer.dash.manifest.DashManifestParser
|
|
||||||
import androidx.media3.exoplayer.source.MediaSource
|
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
|
||||||
class VideoHelper {
|
class VideoHelper {
|
||||||
@ -146,6 +147,18 @@ class VideoHelper {
|
|||||||
})).createMediaSource(manifest, MediaItem.Builder().setUri(Uri.parse(videoSource.getVideoUrl())).build())
|
})).createMediaSource(manifest, MediaItem.Builder().setUri(Uri.parse(videoSource.getVideoUrl())).build())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getMediaMetadata(media: IPlatformVideoDetails): MediaMetadata {
|
||||||
|
val builder = MediaMetadata.Builder()
|
||||||
|
.setArtist(media.author.name)
|
||||||
|
.setTitle(media.name)
|
||||||
|
|
||||||
|
media.thumbnails.getHQThumbnail()?.let {
|
||||||
|
builder.setArtworkUri(Uri.parse(it))
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.build()
|
||||||
|
}
|
||||||
|
|
||||||
@OptIn(UnstableApi::class)
|
@OptIn(UnstableApi::class)
|
||||||
fun convertItagSourceToChunkedDashSource(audioSource: JSAudioUrlRangeSource) : MediaSource {
|
fun convertItagSourceToChunkedDashSource(audioSource: JSAudioUrlRangeSource) : MediaSource {
|
||||||
val manifestConfig = ProgressiveDashManifestCreator.fromAudioProgressiveStreamingUrl(audioSource.getAudioUrl(),
|
val manifestConfig = ProgressiveDashManifestCreator.fromAudioProgressiveStreamingUrl(audioSource.getAudioUrl(),
|
||||||
|
@ -13,14 +13,15 @@ import android.graphics.drawable.Drawable
|
|||||||
import android.media.AudioFocusRequest
|
import android.media.AudioFocusRequest
|
||||||
import android.media.AudioManager
|
import android.media.AudioManager
|
||||||
import android.media.AudioManager.OnAudioFocusChangeListener
|
import android.media.AudioManager.OnAudioFocusChangeListener
|
||||||
|
import android.media.MediaMetadata
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
|
import android.os.SystemClock
|
||||||
|
import android.support.v4.media.MediaMetadataCompat
|
||||||
|
import android.support.v4.media.session.MediaSessionCompat
|
||||||
|
import android.support.v4.media.session.PlaybackStateCompat
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.annotation.OptIn
|
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.media3.common.util.UnstableApi
|
|
||||||
import androidx.media3.session.MediaSession
|
|
||||||
import androidx.media3.session.MediaStyleNotificationHelper
|
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import com.bumptech.glide.request.target.CustomTarget
|
import com.bumptech.glide.request.target.CustomTarget
|
||||||
import com.bumptech.glide.request.transition.Transition
|
import com.bumptech.glide.request.transition.Transition
|
||||||
@ -50,7 +51,7 @@ class MediaPlaybackService : Service() {
|
|||||||
private var _audioManager: AudioManager? = null;
|
private var _audioManager: AudioManager? = null;
|
||||||
private var _notificationManager: NotificationManager? = null;
|
private var _notificationManager: NotificationManager? = null;
|
||||||
private var _notificationChannel: NotificationChannel? = null;
|
private var _notificationChannel: NotificationChannel? = null;
|
||||||
private var _mediaSession: MediaSession? = null;
|
private var _mediaSession: MediaSessionCompat? = null;
|
||||||
private var _hasFocus: Boolean = false;
|
private var _hasFocus: Boolean = false;
|
||||||
private var _focusRequest: AudioFocusRequest? = null;
|
private var _focusRequest: AudioFocusRequest? = null;
|
||||||
private var _audioFocusLossTime_ms: Long? = null
|
private var _audioFocusLossTime_ms: Long? = null
|
||||||
@ -81,7 +82,6 @@ class MediaPlaybackService : Service() {
|
|||||||
|
|
||||||
return START_STICKY;
|
return START_STICKY;
|
||||||
}
|
}
|
||||||
@OptIn(UnstableApi::class)
|
|
||||||
fun setupNotificationRequirements() {
|
fun setupNotificationRequirements() {
|
||||||
_audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager;
|
_audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager;
|
||||||
_notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager;
|
_notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager;
|
||||||
@ -91,54 +91,47 @@ class MediaPlaybackService : Service() {
|
|||||||
};
|
};
|
||||||
_notificationManager!!.createNotificationChannel(_notificationChannel!!);
|
_notificationManager!!.createNotificationChannel(_notificationChannel!!);
|
||||||
|
|
||||||
_mediaSession = MediaSession.Builder(this, StatePlayer.instance.getPlayerOrCreate(this).player)
|
_mediaSession = MediaSessionCompat(this, "PlayerState");
|
||||||
|
_mediaSession?.setPlaybackState(PlaybackStateCompat.Builder()
|
||||||
.setCallback(object: MediaSession.Callback {
|
|
||||||
override fun onMediaButtonEvent(session: MediaSession, controllerInfo: MediaSession.ControllerInfo, intent: Intent): Boolean {
|
|
||||||
//TODO: Reimplement
|
|
||||||
return super.onMediaButtonEvent(session, controllerInfo, intent)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*override fun onSeekTo(pos: Long) {
|
|
||||||
super.onSeekTo(pos)
|
|
||||||
Logger.i(TAG, "Media session callback onSeekTo(pos = $pos)");
|
|
||||||
MediaControlReceiver.onSeekToReceived.emit(pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPlay() {
|
|
||||||
super.onPlay();
|
|
||||||
Logger.i(TAG, "Media session callback onPlay()");
|
|
||||||
MediaControlReceiver.onPlayReceived.emit();
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPause() {
|
|
||||||
super.onPause();
|
|
||||||
Logger.i(TAG, "Media session callback onPause()");
|
|
||||||
MediaControlReceiver.onPauseReceived.emit();
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onStop() {
|
|
||||||
super.onStop();
|
|
||||||
Logger.i(TAG, "Media session callback onStop()");
|
|
||||||
MediaControlReceiver.onCloseReceived.emit();
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onSkipToPrevious() {
|
|
||||||
super.onSkipToPrevious();
|
|
||||||
Logger.i(TAG, "Media session callback onSkipToPrevious()");
|
|
||||||
MediaControlReceiver.onPreviousReceived.emit();
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onSkipToNext() {
|
|
||||||
super.onSkipToNext()
|
|
||||||
Logger.i(TAG, "Media session callback onSkipToNext()");
|
|
||||||
MediaControlReceiver.onNextReceived.emit();
|
|
||||||
}*/
|
|
||||||
})
|
|
||||||
.build();
|
|
||||||
/*_mediaSession?.setPlaybackState(PlaybackStateCompat.Builder()
|
|
||||||
.setState(PlaybackStateCompat.STATE_PLAYING, 0, 1f)
|
.setState(PlaybackStateCompat.STATE_PLAYING, 0, 1f)
|
||||||
.build());*/
|
.build());
|
||||||
|
_mediaSession?.setCallback(object: MediaSessionCompat.Callback() {
|
||||||
|
override fun onSeekTo(pos: Long) {
|
||||||
|
super.onSeekTo(pos)
|
||||||
|
Logger.i(TAG, "Media session callback onSeekTo(pos = $pos)");
|
||||||
|
MediaControlReceiver.onSeekToReceived.emit(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPlay() {
|
||||||
|
super.onPlay();
|
||||||
|
Logger.i(TAG, "Media session callback onPlay()");
|
||||||
|
MediaControlReceiver.onPlayReceived.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
super.onPause();
|
||||||
|
Logger.i(TAG, "Media session callback onPause()");
|
||||||
|
MediaControlReceiver.onPauseReceived.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStop() {
|
||||||
|
super.onStop();
|
||||||
|
Logger.i(TAG, "Media session callback onStop()");
|
||||||
|
MediaControlReceiver.onCloseReceived.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSkipToPrevious() {
|
||||||
|
super.onSkipToPrevious();
|
||||||
|
Logger.i(TAG, "Media session callback onSkipToPrevious()");
|
||||||
|
MediaControlReceiver.onPreviousReceived.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSkipToNext() {
|
||||||
|
super.onSkipToNext()
|
||||||
|
Logger.i(TAG, "Media session callback onSkipToNext()");
|
||||||
|
MediaControlReceiver.onNextReceived.emit();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
@ -193,7 +186,15 @@ class MediaPlaybackService : Service() {
|
|||||||
if(_notificationChannel == null || _mediaSession == null)
|
if(_notificationChannel == null || _mediaSession == null)
|
||||||
setupNotificationRequirements();
|
setupNotificationRequirements();
|
||||||
|
|
||||||
|
_mediaSession?.setMetadata(
|
||||||
|
MediaMetadataCompat.Builder()
|
||||||
|
.putString(MediaMetadata.METADATA_KEY_ARTIST, video.author.name)
|
||||||
|
.putString(MediaMetadata.METADATA_KEY_TITLE, video.name)
|
||||||
|
.putLong(MediaMetadata.METADATA_KEY_DURATION, video.duration * 1000)
|
||||||
|
.build());
|
||||||
|
|
||||||
val thumbnail = video.thumbnails.getHQThumbnail();
|
val thumbnail = video.thumbnails.getHQThumbnail();
|
||||||
|
|
||||||
_notif_last_video = video;
|
_notif_last_video = video;
|
||||||
|
|
||||||
if(isUpdating)
|
if(isUpdating)
|
||||||
@ -220,7 +221,6 @@ class MediaPlaybackService : Service() {
|
|||||||
private fun generateMediaAction(icon: Int, title: String, intent: PendingIntent) : NotificationCompat.Action {
|
private fun generateMediaAction(icon: Int, title: String, intent: PendingIntent) : NotificationCompat.Action {
|
||||||
return NotificationCompat.Action.Builder(icon, title, intent).build();
|
return NotificationCompat.Action.Builder(icon, title, intent).build();
|
||||||
}
|
}
|
||||||
@OptIn(UnstableApi::class)
|
|
||||||
private fun notifyMediaSession(video: IPlatformVideo?, desiredBitmap: Bitmap?) {
|
private fun notifyMediaSession(video: IPlatformVideo?, desiredBitmap: Bitmap?) {
|
||||||
val channel = _notificationChannel ?: return;
|
val channel = _notificationChannel ?: return;
|
||||||
val session = _mediaSession ?: return;
|
val session = _mediaSession ?: return;
|
||||||
@ -249,9 +249,14 @@ class MediaPlaybackService : Service() {
|
|||||||
.setOngoing(true)
|
.setOngoing(true)
|
||||||
.setSilent(true)
|
.setSilent(true)
|
||||||
.setContentIntent(PendingIntent.getActivity(this, 5, bringUpIntent, PendingIntent.FLAG_IMMUTABLE))
|
.setContentIntent(PendingIntent.getActivity(this, 5, bringUpIntent, PendingIntent.FLAG_IMMUTABLE))
|
||||||
.setStyle(
|
.setStyle(if(hasQueue)
|
||||||
if(hasQueue) MediaStyleNotificationHelper.MediaStyle(session)//.setShowActionsInCompactView(0, 1, 2)
|
androidx.media.app.NotificationCompat.MediaStyle()
|
||||||
else MediaStyleNotificationHelper.MediaStyle(session))//.setShowActionsInCompactView(0))
|
.setMediaSession(session.sessionToken)
|
||||||
|
.setShowActionsInCompactView(0, 1, 2)
|
||||||
|
else
|
||||||
|
androidx.media.app.NotificationCompat.MediaStyle()
|
||||||
|
.setMediaSession(session.sessionToken)
|
||||||
|
.setShowActionsInCompactView(0))
|
||||||
.setDeleteIntent(deleteIntent)
|
.setDeleteIntent(deleteIntent)
|
||||||
.setChannelId(channel.id)
|
.setChannelId(channel.id)
|
||||||
|
|
||||||
@ -298,7 +303,7 @@ class MediaPlaybackService : Service() {
|
|||||||
val notif = builder.build();
|
val notif = builder.build();
|
||||||
notif.flags = notif.flags or NotificationCompat.FLAG_ONGOING_EVENT or NotificationCompat.FLAG_NO_CLEAR;
|
notif.flags = notif.flags or NotificationCompat.FLAG_ONGOING_EVENT or NotificationCompat.FLAG_NO_CLEAR;
|
||||||
|
|
||||||
Logger.i(TAG, "Updating notification bitmap=${if (bitmap != null) "yes" else "no."} channelId=${channel.id} icon=${icon} video=${video?.name ?: ""} playWhenReady=${playWhenReady} session.sessionToken=${session.token}");
|
Logger.i(TAG, "Updating notification bitmap=${if (bitmap != null) "yes" else "no."} channelId=${channel.id} icon=${icon} video=${video?.name ?: ""} playWhenReady=${playWhenReady} session.sessionToken=${session.sessionToken}");
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
// For API 29 and above
|
// For API 29 and above
|
||||||
@ -311,7 +316,20 @@ class MediaPlaybackService : Service() {
|
|||||||
_notif_last_bitmap = bitmap;
|
_notif_last_bitmap = bitmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateMediaSessionPlaybackState() {
|
fun updateMediaSessionPlaybackState(state: Int, pos: Long) {
|
||||||
|
_mediaSession?.setPlaybackState(
|
||||||
|
PlaybackStateCompat.Builder()
|
||||||
|
.setActions(
|
||||||
|
PlaybackStateCompat.ACTION_SEEK_TO or
|
||||||
|
PlaybackStateCompat.ACTION_PLAY or
|
||||||
|
PlaybackStateCompat.ACTION_PAUSE or
|
||||||
|
PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS or
|
||||||
|
PlaybackStateCompat.ACTION_SKIP_TO_NEXT or
|
||||||
|
PlaybackStateCompat.ACTION_PLAY_PAUSE
|
||||||
|
)
|
||||||
|
.setState(state, pos, 1f, SystemClock.elapsedRealtime())
|
||||||
|
.build());
|
||||||
|
|
||||||
if(_focusRequest == null)
|
if(_focusRequest == null)
|
||||||
setAudioFocus();
|
setAudioFocus();
|
||||||
}
|
}
|
||||||
|
@ -107,8 +107,8 @@ class StatePlayer {
|
|||||||
fun updateMediaSession(videoUpdated: IPlatformVideoDetails?) {
|
fun updateMediaSession(videoUpdated: IPlatformVideoDetails?) {
|
||||||
MediaPlaybackService.getService()?.updateMediaSession(videoUpdated);
|
MediaPlaybackService.getService()?.updateMediaSession(videoUpdated);
|
||||||
}
|
}
|
||||||
fun updateMediaSessionPlaybackState() {
|
fun updateMediaSessionPlaybackState(state: Int, pos: Long) {
|
||||||
MediaPlaybackService.getService()?.updateMediaSessionPlaybackState();
|
MediaPlaybackService.getService()?.updateMediaSessionPlaybackState(state, pos);
|
||||||
}
|
}
|
||||||
fun closeMediaSession() {
|
fun closeMediaSession() {
|
||||||
MediaPlaybackService.getService()?.closeMediaSession();
|
MediaPlaybackService.getService()?.closeMediaSession();
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package com.futo.platformplayer.video
|
package com.futo.platformplayer.video
|
||||||
|
|
||||||
|
import android.media.session.PlaybackState
|
||||||
|
import android.support.v4.media.session.PlaybackStateCompat
|
||||||
import androidx.media3.common.Player
|
import androidx.media3.common.Player
|
||||||
import androidx.media3.exoplayer.ExoPlayer
|
import androidx.media3.exoplayer.ExoPlayer
|
||||||
import androidx.media3.ui.PlayerView
|
import androidx.media3.ui.PlayerView
|
||||||
@ -21,6 +23,15 @@ class PlayerManager {
|
|||||||
this.player = exoPlayer;
|
this.player = exoPlayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun getPlaybackStateCompat() : Int {
|
||||||
|
return when(player.playbackState) {
|
||||||
|
ExoPlayer.STATE_READY -> if(player.playWhenReady) PlaybackStateCompat.STATE_PLAYING else PlaybackStateCompat.STATE_PAUSED;
|
||||||
|
ExoPlayer.STATE_BUFFERING -> PlaybackState.STATE_BUFFERING;
|
||||||
|
else -> PlaybackState.STATE_NONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
fun attach(view: PlayerView, stateName: String) {
|
fun attach(view: PlayerView, stateName: String) {
|
||||||
if(view != _currentView) {
|
if(view != _currentView) {
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package com.futo.platformplayer.views.casting
|
package com.futo.platformplayer.views.casting
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.media.session.PlaybackState
|
||||||
|
import android.support.v4.media.session.PlaybackStateCompat
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.util.TypedValue
|
import android.util.TypedValue
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
@ -147,9 +149,10 @@ class CastView : ConstraintLayout {
|
|||||||
_buttonPlay.visibility = View.VISIBLE;
|
_buttonPlay.visibility = View.VISIBLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val position = StateCasting.instance.activeDevice?.expectedCurrentTime?.times(1000.0)?.toLong();
|
||||||
if(StatePlayer.instance.hasMediaSession()) {
|
if(StatePlayer.instance.hasMediaSession()) {
|
||||||
StatePlayer.instance.updateMediaSession(null);
|
StatePlayer.instance.updateMediaSession(null);
|
||||||
StatePlayer.instance.updateMediaSessionPlaybackState();
|
StatePlayer.instance.updateMediaSessionPlaybackState(getPlaybackStateCompat(), (position ?: 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,7 +198,7 @@ class CastView : ConstraintLayout {
|
|||||||
fun setTime(ms: Long) {
|
fun setTime(ms: Long) {
|
||||||
_textPosition.text = ms.toHumanTime(true);
|
_textPosition.text = ms.toHumanTime(true);
|
||||||
_timeBar.setPosition(ms / 1000);
|
_timeBar.setPosition(ms / 1000);
|
||||||
StatePlayer.instance.updateMediaSessionPlaybackState();
|
StatePlayer.instance.updateMediaSessionPlaybackState(getPlaybackStateCompat(), ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
fun cleanup() {
|
fun cleanup() {
|
||||||
@ -205,4 +208,13 @@ class CastView : ConstraintLayout {
|
|||||||
_updateTimeJob = null;
|
_updateTimeJob = null;
|
||||||
_scope.cancel();
|
_scope.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getPlaybackStateCompat(): Int {
|
||||||
|
val d = StateCasting.instance.activeDevice ?: return PlaybackState.STATE_NONE;
|
||||||
|
|
||||||
|
return when(d.isPlaying) {
|
||||||
|
true -> PlaybackStateCompat.STATE_PLAYING;
|
||||||
|
else -> PlaybackStateCompat.STATE_PAUSED;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -39,7 +39,7 @@
|
|||||||
android:elevation="4dp"
|
android:elevation="4dp"
|
||||||
android:layout_marginBottom="6dp" />
|
android:layout_marginBottom="6dp" />
|
||||||
|
|
||||||
<com.google.android.exoplayer2.ui.PlayerControlView
|
<androidx.media3.ui.PlayerControlView
|
||||||
android:id="@+id/videodetail_progress"
|
android:id="@+id/videodetail_progress"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="12dp"
|
android:layout_height="12dp"
|
||||||
|
@ -103,7 +103,7 @@
|
|||||||
android:textStyle="normal" />
|
android:textStyle="normal" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<com.google.android.exoplayer2.ui.DefaultTimeBar
|
<androidx.media3.ui.DefaultTimeBar
|
||||||
android:id="@id/exo_progress"
|
android:id="@id/exo_progress"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="16dp"
|
android:layout_height="16dp"
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="@color/transparent"
|
android:background="@color/transparent"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
<com.google.android.exoplayer2.ui.PlayerView
|
<androidx.media3.ui.PlayerView
|
||||||
android:id="@+id/video_player"
|
android:id="@+id/video_player"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
@ -15,7 +15,7 @@
|
|||||||
app:resize_mode="fit"
|
app:resize_mode="fit"
|
||||||
app:show_buffering="when_playing"
|
app:show_buffering="when_playing"
|
||||||
android:layout_marginBottom="6dp" />
|
android:layout_marginBottom="6dp" />
|
||||||
<com.google.android.exoplayer2.ui.PlayerControlView
|
<androidx.media3.ui.PlayerControlView
|
||||||
android:id="@+id/video_player_controller"
|
android:id="@+id/video_player_controller"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
@ -198,12 +198,12 @@
|
|||||||
</TextView>
|
</TextView>
|
||||||
|
|
||||||
|
|
||||||
<com.google.android.exoplayer2.ui.SubtitleView
|
<androidx.media3.ui.SubtitleView
|
||||||
android:id="@id/exo_subtitles"
|
android:id="@id/exo_subtitles"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent" />
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
<com.google.android.exoplayer2.ui.DefaultTimeBar
|
<androidx.media3.ui.DefaultTimeBar
|
||||||
android:id="@id/exo_progress"
|
android:id="@id/exo_progress"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="16dp"
|
android:layout_height="16dp"
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
app:layout_constraintLeft_toLeftOf="parent"
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
app:layout_constraintRight_toRightOf="parent">
|
app:layout_constraintRight_toRightOf="parent">
|
||||||
|
|
||||||
<com.google.android.exoplayer2.ui.DefaultTimeBar
|
<androidx.media3.ui.DefaultTimeBar
|
||||||
android:id="@id/exo_progress"
|
android:id="@id/exo_progress"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="12dp"
|
android:layout_height="12dp"
|
||||||
|
@ -227,7 +227,7 @@
|
|||||||
|
|
||||||
</TextView>
|
</TextView>
|
||||||
|
|
||||||
<com.google.android.exoplayer2.ui.DefaultTimeBar
|
<androidx.media3.ui.DefaultTimeBar
|
||||||
android:id="@id/exo_progress"
|
android:id="@id/exo_progress"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="12dp"
|
android:layout_height="12dp"
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
android:id="@+id/videoview_root"
|
android:id="@+id/videoview_root"
|
||||||
android:background="@color/transparent"
|
android:background="@color/transparent"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
<com.google.android.exoplayer2.ui.PlayerView
|
<androidx.media3.ui.PlayerView
|
||||||
android:id="@+id/video_player"
|
android:id="@+id/video_player"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
@ -16,7 +16,7 @@
|
|||||||
app:show_buffering="always"
|
app:show_buffering="always"
|
||||||
android:layout_marginBottom="6dp" />
|
android:layout_marginBottom="6dp" />
|
||||||
<!--
|
<!--
|
||||||
<com.google.android.exoplayer2.ui.PlayerControlView
|
<androidx.media3.ui.PlayerControlView
|
||||||
android:id="@+id/video_player_bar"
|
android:id="@+id/video_player_bar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
@ -48,7 +48,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<com.google.android.exoplayer2.ui.PlayerControlView
|
<androidx.media3.ui.PlayerControlView
|
||||||
android:id="@+id/video_player_controller"
|
android:id="@+id/video_player_controller"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
@ -56,7 +56,7 @@
|
|||||||
android:layout_marginRight="-6dp"
|
android:layout_marginRight="-6dp"
|
||||||
app:show_timeout="-1"
|
app:show_timeout="-1"
|
||||||
app:controller_layout_id="@layout/video_player_ui" />
|
app:controller_layout_id="@layout/video_player_ui" />
|
||||||
<com.google.android.exoplayer2.ui.PlayerControlView
|
<androidx.media3.ui.PlayerControlView
|
||||||
android:id="@+id/video_player_controller_fullscreen"
|
android:id="@+id/video_player_controller_fullscreen"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
@ -143,7 +143,7 @@
|
|||||||
app:layout_constraintTop_toTopOf="@id/text_position"
|
app:layout_constraintTop_toTopOf="@id/text_position"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/text_position"/>
|
app:layout_constraintBottom_toBottomOf="@id/text_position"/>
|
||||||
|
|
||||||
<com.google.android.exoplayer2.ui.DefaultTimeBar
|
<androidx.media3.ui.DefaultTimeBar
|
||||||
android:id="@+id/time_progress"
|
android:id="@+id/time_progress"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="16dp"
|
android:layout_height="16dp"
|
||||||
|
@ -712,6 +712,7 @@
|
|||||||
<string name="fcast_technical_documentation">FCast Technical Documentation</string>
|
<string name="fcast_technical_documentation">FCast Technical Documentation</string>
|
||||||
<string name="login_to_view_your_comments">Login to view your comments</string>
|
<string name="login_to_view_your_comments">Login to view your comments</string>
|
||||||
<string name="polycentric_is_disabled">Polycentric is disabled</string>
|
<string name="polycentric_is_disabled">Polycentric is disabled</string>
|
||||||
|
<string name="play_pause">Play Pause</string>
|
||||||
<string-array name="home_screen_array">
|
<string-array name="home_screen_array">
|
||||||
<item>Recommendations</item>
|
<item>Recommendations</item>
|
||||||
<item>Subscriptions</item>
|
<item>Subscriptions</item>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user