diff options
author | H. Lehmann <ByteHamster@users.noreply.github.com> | 2020-04-04 11:56:47 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-04 11:56:47 +0200 |
commit | 77efea895af62f71a02dad668b10a405b2d4c6b2 (patch) | |
tree | 9d098d4bbeedf03007927c69f2ee38908c446f6f /core | |
parent | eebdd07c92ed5208da7d1db0071c07425929daac (diff) | |
parent | 94c69e31cdd6bb393de6b337b6be1d486b273c42 (diff) | |
download | AntennaPod-77efea895af62f71a02dad668b10a405b2d4c6b2.zip |
Merge pull request #4001 from ByteHamster/select-audio-tracks
Allow to select audio track
Diffstat (limited to 'core')
9 files changed, 277 insertions, 91 deletions
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java index b177f9b92..42a193f0e 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java @@ -9,6 +9,7 @@ import com.google.android.exoplayer2.DefaultLoadControl; import com.google.android.exoplayer2.DefaultRenderersFactory; import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlayerFactory; +import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.SeekParameters; @@ -17,7 +18,13 @@ import com.google.android.exoplayer2.audio.AudioAttributes; import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory; import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.ProgressiveMediaSource; +import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; +import com.google.android.exoplayer2.trackselection.MappingTrackSelector; +import com.google.android.exoplayer2.trackselection.TrackSelection; +import com.google.android.exoplayer2.trackselection.TrackSelectionArray; +import com.google.android.exoplayer2.ui.DefaultTrackNameProvider; +import com.google.android.exoplayer2.ui.TrackNameProvider; import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory; import com.google.android.exoplayer2.upstream.DefaultHttpDataSource; @@ -30,6 +37,9 @@ import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; import org.antennapod.audio.MediaPlayer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.concurrent.TimeUnit; public class ExoPlayerWrapper implements IPlayer { @@ -45,11 +55,11 @@ public class ExoPlayerWrapper implements IPlayer { private MediaPlayer.OnBufferingUpdateListener bufferingUpdateListener; private PlaybackParameters playbackParameters; private MediaPlayer.OnInfoListener infoListener; - + private DefaultTrackSelector trackSelector; ExoPlayerWrapper(Context context) { this.context = context; - exoPlayer = createPlayer(); + createPlayer(); playbackParameters = exoPlayer.getPlaybackParameters(); bufferingUpdateDisposable = Observable.interval(2, TimeUnit.SECONDS) .observeOn(AndroidSchedulers.mainThread()) @@ -60,16 +70,17 @@ public class ExoPlayerWrapper implements IPlayer { }); } - private SimpleExoPlayer createPlayer() { + private void createPlayer() { DefaultLoadControl.Builder loadControl = new DefaultLoadControl.Builder(); loadControl.setBufferDurationsMs(30000, 120000, DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_MS, DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS); loadControl.setBackBuffer(UserPreferences.getRewindSecs() * 1000 + 500, true); - SimpleExoPlayer p = ExoPlayerFactory.newSimpleInstance(context, new DefaultRenderersFactory(context), - new DefaultTrackSelector(), loadControl.createDefaultLoadControl()); - p.setSeekParameters(SeekParameters.EXACT); - p.addListener(new Player.EventListener() { + trackSelector = new DefaultTrackSelector(); + exoPlayer = ExoPlayerFactory.newSimpleInstance(context, new DefaultRenderersFactory(context), + trackSelector, loadControl.createDefaultLoadControl()); + exoPlayer.setSeekParameters(SeekParameters.EXACT); + exoPlayer.addListener(new Player.EventListener() { @Override public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { if (audioCompletionListener != null && playbackState == Player.STATE_ENDED) { @@ -93,7 +104,6 @@ public class ExoPlayerWrapper implements IPlayer { audioSeekCompleteListener.onSeekComplete(null); } }); - return p; } @Override @@ -154,7 +164,7 @@ public class ExoPlayerWrapper implements IPlayer { @Override public void reset() { exoPlayer.release(); - exoPlayer = createPlayer(); + createPlayer(); } @Override @@ -226,6 +236,67 @@ public class ExoPlayerWrapper implements IPlayer { exoPlayer.stop(); } + @Override + public List<String> getAudioTracks() { + List<String> trackNames = new ArrayList<>(); + TrackNameProvider trackNameProvider = new DefaultTrackNameProvider(context.getResources()); + for (Format format : getFormats()) { + trackNames.add(trackNameProvider.getTrackName(format)); + } + return trackNames; + } + + private List<Format> getFormats() { + List<Format> formats = new ArrayList<>(); + MappingTrackSelector.MappedTrackInfo trackInfo = trackSelector.getCurrentMappedTrackInfo(); + if (trackInfo == null) { + return Collections.emptyList(); + } + TrackGroupArray trackGroups = trackInfo.getTrackGroups(getAudioRendererIndex()); + for (int i = 0; i < trackGroups.length; i++) { + formats.add(trackGroups.get(i).getFormat(0)); + } + return formats; + } + + @Override + public void setAudioTrack(int track) { + MappingTrackSelector.MappedTrackInfo trackInfo = trackSelector.getCurrentMappedTrackInfo(); + if (trackInfo == null) { + return; + } + TrackGroupArray trackGroups = trackInfo.getTrackGroups(getAudioRendererIndex()); + DefaultTrackSelector.SelectionOverride override = new DefaultTrackSelector.SelectionOverride(track, 0); + DefaultTrackSelector.ParametersBuilder params = trackSelector.buildUponParameters() + .setSelectionOverride(getAudioRendererIndex(), trackGroups, override); + trackSelector.setParameters(params); + } + + private int getAudioRendererIndex() { + for (int i = 0; i < exoPlayer.getRendererCount(); i++) { + if (exoPlayer.getRendererType(i) == C.TRACK_TYPE_AUDIO) { + return i; + } + } + return -1; + } + + @Override + public int getSelectedAudioTrack() { + TrackSelectionArray trackSelections = exoPlayer.getCurrentTrackSelections(); + List<Format> availableFormats = getFormats(); + for (int i = 0; i < trackSelections.length; i++) { + TrackSelection track = trackSelections.get(i); + if (track == null) { + continue; + } + if (availableFormats.contains(track.getSelectedFormat())) { + return availableFormats.indexOf(track.getSelectedFormat()); + } + } + return -1; + } + void setOnCompletionListener(MediaPlayer.OnCompletionListener audioCompletionListener) { this.audioCompletionListener = audioCompletionListener; } diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java index 019893778..fbdc9a52b 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java @@ -17,6 +17,7 @@ import org.antennapod.audio.MediaPlayer; import java.io.File; import java.io.IOException; import java.util.EnumSet; +import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Future; import java.util.concurrent.FutureTask; @@ -828,6 +829,18 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer { media = playable; } + public List<String> getAudioTracks() { + return mediaPlayer.getAudioTracks(); + } + + public void setAudioTrack(int track) { + mediaPlayer.setAudioTrack(track); + } + + public int getSelectedAudioTrack() { + return mediaPlayer.getSelectedAudioTrack(); + } + private void createMediaPlayer() { if (mediaPlayer != null) { mediaPlayer.release(); diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java index 781791721..bd0315298 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java @@ -42,6 +42,7 @@ import com.bumptech.glide.request.RequestOptions; import com.bumptech.glide.request.target.Target; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.concurrent.TimeUnit; @@ -1582,6 +1583,26 @@ public class PlaybackService extends MediaBrowserServiceCompat { return mediaPlayer.getPosition(); } + public List<String> getAudioTracks() { + if (mediaPlayer == null) { + return Collections.emptyList(); + } + return mediaPlayer.getAudioTracks(); + } + + public int getSelectedAudioTrack() { + if (mediaPlayer == null) { + return -1; + } + return mediaPlayer.getSelectedAudioTrack(); + } + + public void setAudioTrack(int track) { + if (mediaPlayer != null) { + mediaPlayer.setAudioTrack(track); + } + } + public boolean isStreaming() { return mediaPlayer.isStreaming(); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java index bc009e2bc..1f047ceee 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java @@ -8,6 +8,7 @@ import android.util.Log; import android.util.Pair; import android.view.SurfaceHolder; +import java.util.List; import java.util.concurrent.Future; import de.danoeh.antennapod.core.feed.MediaType; @@ -230,6 +231,12 @@ public abstract class PlaybackServiceMediaPlayer { protected abstract void setPlayable(Playable playable); + public abstract List<String> getAudioTracks(); + + public abstract void setAudioTrack(int track); + + public abstract int getSelectedAudioTrack(); + public void skip() { endPlayback(false, true, true, true); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/AudioPlayer.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/AudioPlayer.java index 2b3f38841..4b3ffa389 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/AudioPlayer.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/AudioPlayer.java @@ -10,45 +10,58 @@ import org.antennapod.audio.MediaPlayer; import de.danoeh.antennapod.core.preferences.UserPreferences; +import java.util.Collections; +import java.util.List; + public class AudioPlayer extends MediaPlayer implements IPlayer { - private static final String TAG = "AudioPlayer"; - - public AudioPlayer(Context context) { - super(context); - PreferenceManager.getDefaultSharedPreferences(context) - .registerOnSharedPreferenceChangeListener(sonicListener); - } - - private final SharedPreferences.OnSharedPreferenceChangeListener sonicListener = - (sharedPreferences, key) -> { - if (key.equals(UserPreferences.PREF_MEDIA_PLAYER)) { - checkMpi(); - } - }; - - @Override - public void setDisplay(SurfaceHolder sh) { - if (sh != null) { - Log.e(TAG, "Setting display not supported in Audio Player"); - throw new UnsupportedOperationException("Setting display not supported in Audio Player"); - } - } - - @Override - public void setPlaybackParams(float speed, boolean skipSilence) { - if(canSetSpeed()) { - setPlaybackSpeed(speed); - } - //Default player does not support silence skipping - } - - @Override - protected boolean useSonic() { - return UserPreferences.useSonic(); - } - - @Override - protected boolean downmix() { - return UserPreferences.stereoToMono(); - } + private static final String TAG = "AudioPlayer"; + + public AudioPlayer(Context context) { + super(context); + PreferenceManager.getDefaultSharedPreferences(context) + .registerOnSharedPreferenceChangeListener((sharedPreferences, key) -> { + if (key.equals(UserPreferences.PREF_MEDIA_PLAYER)) { + checkMpi(); + } + }); + } + + @Override + public void setDisplay(SurfaceHolder sh) { + if (sh != null) { + Log.e(TAG, "Setting display not supported in Audio Player"); + throw new UnsupportedOperationException("Setting display not supported in Audio Player"); + } + } + + @Override + public void setPlaybackParams(float speed, boolean skipSilence) { + if (canSetSpeed()) { + setPlaybackSpeed(speed); + } + //Default player does not support silence skipping + } + + @Override + protected boolean useSonic() { + return UserPreferences.useSonic(); + } + + @Override + protected boolean downmix() { + return UserPreferences.stereoToMono(); + } + + public List<String> getAudioTracks() { + return Collections.emptyList(); + } + + @Override + public void setAudioTrack(int track) { + } + + @Override + public int getSelectedAudioTrack() { + return -1; + } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/IPlayer.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/IPlayer.java index c2b768ea8..363004709 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/IPlayer.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/IPlayer.java @@ -4,48 +4,54 @@ import android.content.Context; import android.view.SurfaceHolder; import java.io.IOException; +import java.util.List; public interface IPlayer { - boolean canSetSpeed(); + boolean canSetSpeed(); - boolean canDownmix(); + boolean canDownmix(); + int getCurrentPosition(); - int getCurrentPosition(); + float getCurrentSpeedMultiplier(); - float getCurrentSpeedMultiplier(); + int getDuration(); - int getDuration(); + boolean isPlaying(); - boolean isPlaying(); + void pause(); - void pause(); + void prepare() throws IllegalStateException, IOException; - void prepare() throws IllegalStateException, IOException; + void release(); - void release(); + void reset(); - void reset(); + void seekTo(int msec); - void seekTo(int msec); + void setAudioStreamType(int streamtype); - void setAudioStreamType(int streamtype); - - void setDataSource(String path) throws IllegalStateException, IOException, + void setDataSource(String path) throws IllegalStateException, IOException, IllegalArgumentException, SecurityException; - void setDisplay(SurfaceHolder sh); + void setDisplay(SurfaceHolder sh); - void setPlaybackParams(float speed, boolean skipSilence); + void setPlaybackParams(float speed, boolean skipSilence); - void setDownmix(boolean enable); + void setDownmix(boolean enable); - void setVolume(float left, float right); + void setVolume(float left, float right); - void start(); + void start(); - void stop(); + void stop(); void setWakeMode(Context context, int mode); + + List<String> getAudioTracks(); + + void setAudioTrack(int track); + + int getSelectedAudioTrack(); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java index 8ea08f463..8f7e5dc33 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java @@ -44,6 +44,9 @@ import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; +import java.util.Collections; +import java.util.List; + /** * Communicates with the playback service. GUI classes should use this class to * control playback instead of communicating with the PlaybackService directly. @@ -627,6 +630,26 @@ public class PlaybackController { } } + public List<String> getAudioTracks() { + if (playbackService == null) { + return Collections.emptyList(); + } + return playbackService.getAudioTracks(); + } + + public int getSelectedAudioTrack() { + if (playbackService == null) { + return -1; + } + return playbackService.getSelectedAudioTrack(); + } + + public void setAudioTrack(int track) { + if (playbackService != null) { + playbackService.setAudioTrack(track); + } + } + public boolean isPlayingVideoLocally() { if (PlaybackService.isCasting()) { return false; diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/VideoPlayer.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/VideoPlayer.java index f3c1c4f59..d18801870 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/VideoPlayer.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/VideoPlayer.java @@ -3,37 +3,53 @@ package de.danoeh.antennapod.core.util.playback; import android.media.MediaPlayer; import android.util.Log; +import java.util.Collections; +import java.util.List; + public class VideoPlayer extends MediaPlayer implements IPlayer { - private static final String TAG = "VideoPlayer"; + private static final String TAG = "VideoPlayer"; - @Override - public boolean canSetSpeed() { - return false; - } + @Override + public boolean canSetSpeed() { + return false; + } - @Override - public boolean canDownmix() { - return false; - } + @Override + public boolean canDownmix() { + return false; + } - @Override - public float getCurrentSpeedMultiplier() { - return 1; - } + @Override + public float getCurrentSpeedMultiplier() { + return 1; + } - @Override - public void setPlaybackParams(float speed, boolean skipSilence) { - //Ignore this for non ExoPlayer implementations - } + @Override + public void setPlaybackParams(float speed, boolean skipSilence) { + //Ignore this for non ExoPlayer implementations + } - @Override - public void setDownmix(boolean b) { - Log.e(TAG, "Setting downmix unsupported in video player"); - throw new UnsupportedOperationException("Setting downmix unsupported in video player"); - } + @Override + public void setDownmix(boolean b) { + Log.e(TAG, "Setting downmix unsupported in video player"); + throw new UnsupportedOperationException("Setting downmix unsupported in video player"); + } @Override public void setVideoScalingMode(int mode) { super.setVideoScalingMode(mode); } + + public List<String> getAudioTracks() { + return Collections.emptyList(); + } + + @Override + public void setAudioTrack(int track) { + } + + @Override + public int getSelectedAudioTrack() { + return -1; + } } diff --git a/core/src/play/java/de/danoeh/antennapod/core/service/playback/RemotePSMP.java b/core/src/play/java/de/danoeh/antennapod/core/service/playback/RemotePSMP.java index 2a75f30a2..f629793e2 100644 --- a/core/src/play/java/de/danoeh/antennapod/core/service/playback/RemotePSMP.java +++ b/core/src/play/java/de/danoeh/antennapod/core/service/playback/RemotePSMP.java @@ -16,6 +16,9 @@ import com.google.android.libraries.cast.companionlibrary.cast.exceptions.NoConn import com.google.android.libraries.cast.companionlibrary.cast.exceptions.TransientNetworkDisconnectionException; import de.danoeh.antennapod.core.cast.MediaInfoCreator; + +import java.util.Collections; +import java.util.List; import java.util.concurrent.Future; import java.util.concurrent.FutureTask; import java.util.concurrent.atomic.AtomicBoolean; @@ -603,6 +606,19 @@ public class RemotePSMP extends PlaybackServiceMediaPlayer { } @Override + public List<String> getAudioTracks() { + return Collections.emptyList(); + } + + public void setAudioTrack(int track) { + + } + + public int getSelectedAudioTrack() { + return -1; + } + + @Override protected Future<?> endPlayback(boolean hasEnded, boolean wasSkipped, boolean shouldContinue, boolean toStoppedState) { Log.d(TAG, "endPlayback() called"); |