Commit da62d0ae authored by Geoffrey Métais's avatar Geoffrey Métais
Browse files

Manage renderer with LiveData

parent 8a2bf953
......@@ -45,6 +45,12 @@ import androidx.core.app.NotificationManagerCompat
import androidx.core.app.ServiceCompat
import androidx.core.content.ContextCompat
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.ObsoleteCoroutinesApi
import androidx.lifecycle.Observer
import androidx.lifecycle.ServiceLifecycleDispatcher
import androidx.media.MediaBrowserServiceCompat
import kotlinx.coroutines.*
......@@ -495,6 +501,7 @@ class PlaybackService : MediaBrowserServiceCompat(), CoroutineScope, LifecycleOw
registerReceiver(receiver, filter)
keyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
renderer.observe(this, Observer { setRenderer(it) })
}
private fun updateHasWidget() {
......@@ -1324,6 +1331,7 @@ class PlaybackService : MediaBrowserServiceCompat(), CoroutineScope, LifecycleOw
companion object {
var renderer = MutableLiveData<RendererItem>()
private const val SHOW_TOAST = 1
private const val END_MEDIASESSION = 2
......@@ -1338,6 +1346,8 @@ class PlaybackService : MediaBrowserServiceCompat(), CoroutineScope, LifecycleOw
ContextCompat.startForegroundService(context, i)
}
fun hasRenderer() = renderer.value != null
private const val PLAYBACK_BASE_ACTIONS = (PlaybackStateCompat.ACTION_PLAY_FROM_SEARCH
or PlaybackStateCompat.ACTION_PLAY_FROM_MEDIA_ID or PlaybackStateCompat.ACTION_PLAY_FROM_URI
or PlaybackStateCompat.ACTION_PLAY_PAUSE)
......
......@@ -19,8 +19,6 @@
*/
package org.videolan.vlc
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
......@@ -39,7 +37,6 @@ object RendererDelegate : RendererDiscoverer.EventListener {
val renderers : LiveDataset<RendererItem> = LiveDataset()
@Volatile private var started = false
val selectedRenderer: LiveData<RendererItem> = MutableLiveData()
init {
ExternalMonitor.connected.observeForever { AppScope.launch { if (it == true) start() else stop() } }
......@@ -68,7 +65,7 @@ object RendererDelegate : RendererDiscoverer.EventListener {
private fun clear() {
discoverers.clear()
renderers.clear()
(selectedRenderer as MutableLiveData).value = null
PlaybackService.renderer.value = null
}
override fun onEvent(event: RendererDiscoverer.Event?) {
......@@ -77,10 +74,4 @@ object RendererDelegate : RendererDiscoverer.EventListener {
RendererDiscoverer.Event.ItemDeleted -> { renderers.remove(event.item); event.item.release() }
}
}
fun selectRenderer(item: RendererItem?) {
(selectedRenderer as MutableLiveData).value = item
}
fun hasRenderer() = selectedRenderer.value !== null
}
......@@ -33,6 +33,7 @@ import android.view.MenuItem;
import android.view.View;
import org.videolan.libvlc.RendererItem;
import org.videolan.vlc.PlaybackService;
import org.videolan.vlc.R;
import org.videolan.vlc.RendererDelegate;
import org.videolan.vlc.gui.audio.AudioBrowserFragment;
......@@ -66,13 +67,13 @@ public class ContentActivity extends AudioPlayerContainerActivity implements Sea
super.initAudioPlayerContainerActivity();
if (!AndroidDevices.isChromeBook && !AndroidDevices.isAndroidTv
&& Settings.INSTANCE.getInstance(this).getBoolean("enable_casting", true)) {
RendererDelegate.INSTANCE.getSelectedRenderer().observe(this, new Observer<RendererItem>() {
PlaybackService.Companion.getRenderer().observe(this, new Observer<RendererItem>() {
@Override
public void onChanged(@Nullable RendererItem rendererItem) {
final MenuItem item = mToolbar.getMenu().findItem(R.id.ml_menu_renderers);
if (item == null) return;
item.setVisible(showRenderers);
item.setIcon(!RendererDelegate.INSTANCE.hasRenderer() ? R.drawable.ic_am_renderer_normal_w : R.drawable.ic_am_renderer_on_w);
item.setIcon(!PlaybackService.Companion.hasRenderer() ? R.drawable.ic_am_renderer_normal_w : R.drawable.ic_am_renderer_on_w);
}
});
RendererDelegate.INSTANCE.getRenderers().observe(this, new Observer<List<RendererItem>>() {
......@@ -123,7 +124,7 @@ public class ContentActivity extends AudioPlayerContainerActivity implements Sea
}
} else menu.findItem(R.id.ml_menu_filter).setVisible(false);
menu.findItem(R.id.ml_menu_renderers).setVisible(showRenderers && Settings.INSTANCE.getInstance(this).getBoolean("enable_casting", true));
menu.findItem(R.id.ml_menu_renderers).setIcon(!RendererDelegate.INSTANCE.hasRenderer() ? R.drawable.ic_am_renderer_normal_w : R.drawable.ic_am_renderer_on_w);
menu.findItem(R.id.ml_menu_renderers).setIcon(!PlaybackService.Companion.hasRenderer() ? R.drawable.ic_am_renderer_normal_w : R.drawable.ic_am_renderer_on_w);
return super.onCreateOptionsMenu(menu);
}
......@@ -139,10 +140,10 @@ public class ContentActivity extends AudioPlayerContainerActivity implements Sea
startActivity(new Intent(Intent.ACTION_SEARCH, null, this, SearchActivity.class));
return true;
case R.id.ml_menu_renderers:
if (!RendererDelegate.INSTANCE.hasRenderer()
if (!PlaybackService.Companion.hasRenderer()
&& RendererDelegate.INSTANCE.getRenderers().getValue().size() == 1) {
final RendererItem renderer = RendererDelegate.INSTANCE.getRenderers().getValue().get(0);
RendererDelegate.INSTANCE.selectRenderer(renderer);
PlaybackService.Companion.getRenderer().setValue(renderer);
final View v = findViewById(R.id.audio_player_container);
if (v != null) UiTools.snacker(v, getString(R.string.casting_connected_renderer, renderer.displayName));
} else if (getSupportFragmentManager().findFragmentByTag("renderers") == null)
......
......@@ -53,8 +53,8 @@ import kotlinx.coroutines.channels.actor
import org.videolan.medialibrary.Tools
import org.videolan.medialibrary.media.MediaWrapper
import org.videolan.tools.coroutineScope
import org.videolan.vlc.PlaybackService
import org.videolan.vlc.R
import org.videolan.vlc.RendererDelegate.hasRenderer
import org.videolan.vlc.VLCApplication
import org.videolan.vlc.databinding.AudioPlayerBinding
import org.videolan.vlc.gui.AudioPlayerContainerActivity
......@@ -344,7 +344,7 @@ class AudioPlayer : androidx.fragment.app.Fragment(), PlaylistAdapter.IPlayer, T
fun onResumeToVideoClick(v: View) {
playlistModel.currentMediaWrapper?.let {
if (hasRenderer()) VideoPlayerActivity.startOpened(v.context,
if (PlaybackService.hasRenderer()) VideoPlayerActivity.startOpened(v.context,
it.uri, playlistModel.currentMediaPosition)
else if (hasMedia()) {
it.removeFlags(MediaWrapper.MEDIA_FORCE_AUDIO)
......
......@@ -20,15 +20,15 @@
package org.videolan.vlc.gui.dialogs
import android.app.Dialog
import androidx.lifecycle.Observer
import android.os.Bundle
import androidx.fragment.app.DialogFragment
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.LinearLayoutManager
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.Window
import androidx.core.content.ContextCompat
import androidx.lifecycle.Observer
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.ObsoleteCoroutinesApi
import org.videolan.libvlc.RendererItem
import org.videolan.vlc.PlaybackService
import org.videolan.vlc.R
......@@ -42,6 +42,8 @@ import org.videolan.vlc.gui.helpers.UiTools
const private val TAG = "VLC/RenderersDialog"
@ObsoleteCoroutinesApi
@ExperimentalCoroutinesApi
class RenderersDialog : androidx.fragment.app.DialogFragment(), PlaybackService.Client.Callback {
private var renderers = RendererDelegate.renderers.value
private lateinit var mBinding: DialogRenderersBinding
......@@ -62,9 +64,9 @@ class RenderersDialog : androidx.fragment.app.DialogFragment(), PlaybackService.
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val inflater = LayoutInflater.from(context)
val inflater = LayoutInflater.from(requireContext())
mBinding = DialogRenderersBinding.inflate(inflater, null)
val dialog = Dialog(context)
val dialog = Dialog(requireContext())
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
dialog.setContentView(mBinding.root)
return dialog
......@@ -80,8 +82,8 @@ class RenderersDialog : androidx.fragment.app.DialogFragment(), PlaybackService.
mBinding.holder = mClickHandler;
mBinding.renderersList.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(view.context)
mBinding.renderersList.adapter = mAdapter
mBinding.renderersDisconnect.isEnabled = RendererDelegate.hasRenderer()
mBinding.renderersDisconnect.setTextColor(ContextCompat.getColor(view.context, if (RendererDelegate.hasRenderer()) R.color.orange800 else R.color.grey400))
mBinding.renderersDisconnect.isEnabled = PlaybackService.hasRenderer()
mBinding.renderersDisconnect.setTextColor(ContextCompat.getColor(view.context, if (PlaybackService.hasRenderer()) R.color.orange800 else R.color.grey400))
mAdapter.update(renderers)
}
......@@ -113,7 +115,7 @@ class RenderersDialog : androidx.fragment.app.DialogFragment(), PlaybackService.
override fun onBindViewHolder(holder: SelectorViewHolder<ItemRendererBinding>, position: Int) {
holder.binding.renderer = renderers[position]
if (renderers[position] == RendererDelegate.selectedRenderer.value)
if (renderers[position] == PlaybackService.renderer.value)
holder.binding.rendererName.setTextColor(ContextCompat.getColor(holder.itemView.context, R.color.orange800))
}
......@@ -124,11 +126,12 @@ class RenderersDialog : androidx.fragment.app.DialogFragment(), PlaybackService.
inner class RendererClickhandler {
fun connect(item: RendererItem?) {
mService?.setRenderer(item)
PlaybackService.renderer.value = item
dismissAllowingStateLoss()
RendererDelegate.selectRenderer(item)
if (item !== null) activity?.window?.findViewById<View>(R.id.audio_player_container)?.let {
UiTools.snacker(it, getString(R.string.casting_connected_renderer, item.displayName))
item?.run {
activity?.window?.findViewById<View>(R.id.audio_player_container)?.let {
UiTools.snacker(it, getString(R.string.casting_connected_renderer, displayName))
}
}
}
}
......
......@@ -297,7 +297,7 @@ public class VideoPlayerActivity extends AppCompatActivity implements IPlaybackS
audioBoostEnabled = mSettings.getBoolean("audio_boost", false);
mEnableCloneMode = mSettings.getBoolean("enable_clone_mode", false);
mDisplayManager = new DisplayManager(this, AndroidDevices.isChromeBook ? RendererDelegate.INSTANCE.getSelectedRenderer() : null, false, mEnableCloneMode, mIsBenchmark);
mDisplayManager = new DisplayManager(this, AndroidDevices.isChromeBook ? PlaybackService.Companion.getRenderer() : null, false, mEnableCloneMode, mIsBenchmark);
setContentView(mDisplayManager.isPrimary() ? R.layout.player : R.layout.player_remote_control);
/** initialize Views an their Events */
......@@ -2228,7 +2228,7 @@ public class VideoPlayerActivity extends AppCompatActivity implements IPlaybackS
if (!AndroidDevices.isChromeBook && !mIsTv
&& Settings.INSTANCE.getInstance(this).getBoolean("enable_casting", true)) {
mRendererBtn = findViewById(R.id.video_renderer);
RendererDelegate.INSTANCE.getSelectedRenderer().observe(this, new Observer<RendererItem>() {
PlaybackService.Companion.getRenderer().observe(this, new Observer<RendererItem>() {
@Override
public void onChanged(@androidx.annotation.Nullable RendererItem rendererItem) {
if (mRendererBtn != null) mRendererBtn.setImageResource(rendererItem == null ? R.drawable.ic_renderer_circle : R.drawable.ic_renderer_on_circle);
......
......@@ -12,7 +12,7 @@ import kotlinx.coroutines.channels.actor
import org.videolan.libvlc.*
import org.videolan.medialibrary.media.MediaWrapper
import org.videolan.vlc.BuildConfig
import org.videolan.vlc.RendererDelegate
import org.videolan.vlc.PlaybackService
import org.videolan.vlc.gui.preferences.PreferencesActivity
import org.videolan.vlc.repository.SlaveRepository
import org.videolan.vlc.util.Settings
......@@ -211,7 +211,7 @@ class PlayerController(val context: Context) : IVLCVout.Callback, MediaPlayer.Ev
return MediaPlayer(VLCInstance.get()).apply {
setAudioDigitalOutputEnabled(VLCOptions.isAudioDigitalOutputEnabled(settings))
VLCOptions.getAout(settings)?.let { setAudioOutput(it) }
setRenderer(RendererDelegate.selectedRenderer.value)
setRenderer(PlaybackService.Companion.renderer.value)
this.vlcVout.addCallback(this@PlayerController)
}
}
......
......@@ -24,7 +24,6 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.media.AudioManager;
import android.os.Build;
import androidx.annotation.MainThread;
import android.text.TextUtils;
import android.util.Log;
......@@ -34,14 +33,16 @@ import org.videolan.libvlc.util.AndroidUtil;
import org.videolan.libvlc.util.HWDecoderUtil;
import org.videolan.libvlc.util.VLCUtil;
import org.videolan.medialibrary.media.MediaWrapper;
import org.videolan.vlc.PlaybackService;
import org.videolan.vlc.R;
import org.videolan.vlc.RendererDelegate;
import org.videolan.vlc.VLCApplication;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import androidx.annotation.MainThread;
public class VLCOptions {
private static final String TAG = "VLCConfig";
......@@ -235,7 +236,7 @@ public class VLCOptions {
if (!prefs.getBoolean("subtitles_autoload", true)) media.addOption(":sub-language=none");
if (!benchmark && prefs.getBoolean("media_fast_seek", true)) media.addOption(":input-fast-seek");
if (RendererDelegate.INSTANCE.hasRenderer()) {
if (PlaybackService.Companion.hasRenderer()) {
media.addOption(":sout-chromecast-audio-passthrough="+prefs.getBoolean("casting_passthrough", true));
media.addOption(":sout-chromecast-conversion-quality="+prefs.getString("casting_quality", "2"));
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment