diff --git a/core/build.gradle b/core/build.gradle index 8e448982..469739a1 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -7,7 +7,7 @@ android { buildToolsVersion "25.0.0" defaultConfig { - minSdkVersion 15 + minSdkVersion 16 targetSdkVersion 24 testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } diff --git a/core/src/main/java/com/novoda/noplayer/Player.java b/core/src/main/java/com/novoda/noplayer/Player.java index 3d9c4615..eafa53ab 100644 --- a/core/src/main/java/com/novoda/noplayer/Player.java +++ b/core/src/main/java/com/novoda/noplayer/Player.java @@ -5,6 +5,8 @@ import com.novoda.noplayer.exoplayer.Bitrate; import com.novoda.noplayer.player.PlayerInformation; +import java.util.List; + public interface Player extends PlayerState, PlayerListeners { void play(); @@ -27,6 +29,10 @@ public interface Player extends PlayerState, PlayerListeners { void attach(PlayerView playerView); + void selectAudioTrack(int audioTrackIndex); + + List getAudioTracks(); + interface PreReleaseListener { PreReleaseListener NULL_IMPL = new PreReleaseListener() { diff --git a/core/src/main/java/com/novoda/noplayer/PlayerAudioTrack.java b/core/src/main/java/com/novoda/noplayer/PlayerAudioTrack.java new file mode 100644 index 00000000..0e28d998 --- /dev/null +++ b/core/src/main/java/com/novoda/noplayer/PlayerAudioTrack.java @@ -0,0 +1,75 @@ +package com.novoda.noplayer; + +public class PlayerAudioTrack { + + private final String trackId; + private final String language; + private final String mimeType; + private final int numberOfChannels; + private final int frequency; + + public PlayerAudioTrack(String trackId, String language, String mimeType, int numberOfChannels, int frequency) { + this.trackId = trackId; + this.language = language; + this.mimeType = mimeType; + this.numberOfChannels = numberOfChannels; + this.frequency = frequency; + } + + public String trackId() { + return trackId; + } + + public String language() { + return language; + } + + public String mimeType() { + return mimeType; + } + + public int numberOfChannels() { + return numberOfChannels; + } + + public int frequency() { + return frequency; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + PlayerAudioTrack that = (PlayerAudioTrack) o; + + if (numberOfChannels != that.numberOfChannels) { + return false; + } + if (frequency != that.frequency) { + return false; + } + if (trackId != null ? !trackId.equals(that.trackId) : that.trackId != null) { + return false; + } + if (language != null ? !language.equals(that.language) : that.language != null) { + return false; + } + return mimeType != null ? mimeType.equals(that.mimeType) : that.mimeType == null; + + } + + @Override + public int hashCode() { + int result = trackId != null ? trackId.hashCode() : 0; + result = 31 * result + (language != null ? language.hashCode() : 0); + result = 31 * result + (mimeType != null ? mimeType.hashCode() : 0); + result = 31 * result + numberOfChannels; + result = 31 * result + frequency; + return result; + } +} diff --git a/core/src/main/java/com/novoda/noplayer/exoplayer/ExoPlayerFacade.java b/core/src/main/java/com/novoda/noplayer/exoplayer/ExoPlayerFacade.java index affb39bf..d88e91ed 100644 --- a/core/src/main/java/com/novoda/noplayer/exoplayer/ExoPlayerFacade.java +++ b/core/src/main/java/com/novoda/noplayer/exoplayer/ExoPlayerFacade.java @@ -11,6 +11,7 @@ import com.google.android.exoplayer.MediaCodecAudioTrackRenderer; import com.google.android.exoplayer.MediaCodecTrackRenderer.DecoderInitializationException; import com.google.android.exoplayer.MediaCodecVideoTrackRenderer; +import com.google.android.exoplayer.MediaFormat; import com.google.android.exoplayer.TimeRange; import com.google.android.exoplayer.TrackRenderer; import com.google.android.exoplayer.audio.AudioTrack; @@ -24,11 +25,13 @@ import com.google.android.exoplayer.text.TextRenderer; import com.google.android.exoplayer.upstream.BandwidthMeter; import com.novoda.noplayer.ContentType; +import com.novoda.noplayer.PlayerAudioTrack; import com.novoda.noplayer.SurfaceHolderRequester; import com.novoda.notils.exception.DeveloperError; import com.novoda.notils.logger.simple.Log; import java.io.IOException; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; @@ -435,6 +438,37 @@ public void onUpstreamDiscarded(int sourceId, long mediaStartTimeMs, long mediaE // Do nothing. } + public void selectAudioTrack(int audioTrackIndex) { + int trackCount = player.getTrackCount(Renderers.AUDIO_RENDERER_ID); + if (audioTrackIndex < 0 || audioTrackIndex > trackCount - 1) { + Log.e(String.format( + "Attempt to %s has been ignored because an invalid position was specified: %s, total: %s", + "selectAudioTrack()", + audioTrackIndex, + trackCount + ) + ); + return; + } + player.setSelectedTrack(Renderers.AUDIO_RENDERER_ID, audioTrackIndex); + } + + public List getAudioTracks() { + List tracks = new ArrayList<>(); + for (int i = 0; i < player.getTrackCount(Renderers.AUDIO_RENDERER_ID); i++) { + MediaFormat track = player.getTrackFormat(Renderers.AUDIO_RENDERER_ID, i); + PlayerAudioTrack playerAudioTrack = new PlayerAudioTrack( + track.trackId, + track.language, + track.mimeType, + track.channelCount, + track.bitrate + ); + tracks.add(playerAudioTrack); + } + return tracks; + } + public void setSubtitleLayout(SubtitleLayout subtitleLayout) { this.subtitleLayout = subtitleLayout; } diff --git a/core/src/main/java/com/novoda/noplayer/exoplayer/ExoPlayerImpl.java b/core/src/main/java/com/novoda/noplayer/exoplayer/ExoPlayerImpl.java index 7d4d2d4b..e49bed68 100644 --- a/core/src/main/java/com/novoda/noplayer/exoplayer/ExoPlayerImpl.java +++ b/core/src/main/java/com/novoda/noplayer/exoplayer/ExoPlayerImpl.java @@ -5,6 +5,7 @@ import com.novoda.noplayer.ContentType; import com.novoda.noplayer.Heart; import com.novoda.noplayer.Player; +import com.novoda.noplayer.PlayerAudioTrack; import com.novoda.noplayer.PlayerListenersHolder; import com.novoda.noplayer.PlayerView; import com.novoda.noplayer.Timeout; @@ -13,6 +14,8 @@ import com.novoda.noplayer.VideoPosition; import com.novoda.noplayer.player.PlayerInformation; +import java.util.List; + public class ExoPlayerImpl extends PlayerListenersHolder implements Player { private static final ExoPlayerInformation EXO_PLAYER_INFORMATION = new ExoPlayerInformation(); @@ -178,4 +181,14 @@ public void attach(PlayerView playerView) { public ExoPlayerFacade getInternalExoPlayer() { return exoPlayer; } + + @Override + public void selectAudioTrack(int audioTrackIndex) { + exoPlayer.selectAudioTrack(audioTrackIndex); + } + + @Override + public List getAudioTracks() { + return exoPlayer.getAudioTracks(); + } } diff --git a/core/src/main/java/com/novoda/noplayer/exoplayer/Renderers.java b/core/src/main/java/com/novoda/noplayer/exoplayer/Renderers.java index 958515fb..28f05747 100644 --- a/core/src/main/java/com/novoda/noplayer/exoplayer/Renderers.java +++ b/core/src/main/java/com/novoda/noplayer/exoplayer/Renderers.java @@ -36,6 +36,10 @@ public TrackRenderer getVideoRenderer() { return renderers[VIDEO_RENDERER_INDEX]; } + public TrackRenderer getAudioRenderer() { + return renderers[AUDIO_RENDERER_INDEX]; + } + public TrackRenderer[] asArray() { return Arrays.copyOf(renderers, renderers.length); } diff --git a/core/src/main/java/com/novoda/noplayer/mediaplayer/AndroidMediaPlayerFacade.java b/core/src/main/java/com/novoda/noplayer/mediaplayer/AndroidMediaPlayerFacade.java index a66af34a..ccff55ad 100644 --- a/core/src/main/java/com/novoda/noplayer/mediaplayer/AndroidMediaPlayerFacade.java +++ b/core/src/main/java/com/novoda/noplayer/mediaplayer/AndroidMediaPlayerFacade.java @@ -6,10 +6,13 @@ import android.net.Uri; import android.view.SurfaceHolder; +import com.novoda.noplayer.PlayerAudioTrack; import com.novoda.noplayer.SurfaceHolderRequester; import com.novoda.notils.logger.simple.Log; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import java.util.Map; public class AndroidMediaPlayerFacade { @@ -73,7 +76,6 @@ private void requestAudioFocus() { private MediaPlayer createMediaPlayer(SurfaceHolder surfaceHolder, Uri videoUri) throws IOException { MediaPlayer mediaPlayer = new MediaPlayer(); - mediaPlayer.setOnPreparedListener(internalPeparedListener); mediaPlayer.setOnVideoSizeChangedListener(internalSizeChangedListener); mediaPlayer.setOnCompletionListener(internalCompletionListener); @@ -236,4 +238,35 @@ private boolean isInPlaybackState() { && currentState != STATE_IDLE && currentState != STATE_PREPARING; } + + public List getAudioTracks() { + ArrayList audioTracks = new ArrayList<>(); + for (MediaPlayer.TrackInfo trackInfo : mediaPlayer.getTrackInfo()) { + if (trackInfo.getTrackType() == MediaPlayer.TrackInfo.MEDIA_TRACK_TYPE_AUDIO) { + audioTracks.add(new PlayerAudioTrack(String.valueOf(trackInfo.hashCode()), trackInfo.getLanguage(), "", -1, -1)); + } + } + return audioTracks; + } + + public void setAudioTrack(int audioTrackIndex) { + int index = 0; + MediaPlayer.TrackInfo[] trackInfos = mediaPlayer.getTrackInfo(); + + for (int i = 0; i < trackInfos.length; i++) { + MediaPlayer.TrackInfo trackInfo = trackInfos[i]; + if (trackInfo.getTrackType() == MediaPlayer.TrackInfo.MEDIA_TRACK_TYPE_AUDIO && index == audioTrackIndex) { + mediaPlayer.selectTrack(i); + } else if (trackInfo.getTrackType() == MediaPlayer.TrackInfo.MEDIA_TRACK_TYPE_AUDIO) { + index++; + } + } + Log.e(String.format( + "Attempt to %s has been ignored because an invalid position was specified: %s, total: %s", + "selectAudioTrack()", + audioTrackIndex, + index + ) + ); + } } diff --git a/core/src/main/java/com/novoda/noplayer/mediaplayer/AndroidMediaPlayerImpl.java b/core/src/main/java/com/novoda/noplayer/mediaplayer/AndroidMediaPlayerImpl.java index 3d0e4179..ca015d28 100644 --- a/core/src/main/java/com/novoda/noplayer/mediaplayer/AndroidMediaPlayerImpl.java +++ b/core/src/main/java/com/novoda/noplayer/mediaplayer/AndroidMediaPlayerImpl.java @@ -8,6 +8,7 @@ import com.novoda.noplayer.ContentType; import com.novoda.noplayer.Heart; import com.novoda.noplayer.Player; +import com.novoda.noplayer.PlayerAudioTrack; import com.novoda.noplayer.PlayerListenersHolder; import com.novoda.noplayer.PlayerView; import com.novoda.noplayer.SystemClock; @@ -18,6 +19,8 @@ import com.novoda.noplayer.player.PlayerInformation; import com.novoda.notils.logger.simple.Log; +import java.util.List; + public class AndroidMediaPlayerImpl extends PlayerListenersHolder implements Player { private static final VideoPosition NO_SEEK_TO_POSITION = VideoPosition.INVALID; @@ -301,4 +304,15 @@ public void release() { getStateChangedListeners().onVideoReleased(); videoContainer.hide(); } + + @Override + public void selectAudioTrack(int audioTrackIndex) { + mediaPlayer.setAudioTrack(audioTrackIndex); + + } + + @Override + public List getAudioTracks() { + return mediaPlayer.getAudioTracks(); + } }