Skip to content
This repository has been archived by the owner on Feb 1, 2025. It is now read-only.

Commit

Permalink
Implement official ExoPlayer metadata feature - see #225
Browse files Browse the repository at this point in the history
  • Loading branch information
y20k committed Jun 30, 2019
1 parent eed82e6 commit 1ee0975
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 1,029 deletions.
121 changes: 50 additions & 71 deletions app/src/main/java/org/y20k/transistor/PlayerService.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.media.audiofx.AudioEffect;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
Expand Down Expand Up @@ -65,10 +64,13 @@
import com.google.android.exoplayer2.audio.AudioAttributes;
import com.google.android.exoplayer2.metadata.Metadata;
import com.google.android.exoplayer2.metadata.MetadataOutput;
import com.google.android.exoplayer2.metadata.icy.IcyHeaders;
import com.google.android.exoplayer2.metadata.icy.IcyInfo;
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.source.hls.HlsMediaSource;
import com.google.android.exoplayer2.source.hls.HlsTrackMetadataEntry;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.trackselection.TrackSelector;
Expand All @@ -81,11 +83,9 @@
import org.y20k.transistor.helpers.AudioFocusAwarePlayer;
import org.y20k.transistor.helpers.AudioFocusHelper;
import org.y20k.transistor.helpers.AudioFocusRequestCompat;
import org.y20k.transistor.helpers.IcyDataSourceFactory;
import org.y20k.transistor.helpers.LogHelper;
import org.y20k.transistor.helpers.NotificationHelper;
import org.y20k.transistor.helpers.PackageValidator;
import org.y20k.transistor.helpers.PlayerCallback;
import org.y20k.transistor.helpers.StationListProvider;
import org.y20k.transistor.helpers.TransistorKeys;

Expand Down Expand Up @@ -244,7 +244,22 @@ else if (intent.getAction().equals(ACTION_DISMISS)) {

@Override
public void onMetadata(Metadata metadata) {
LogHelper.v(LOG_TAG, "Got new metadata: " + metadata.toString());
for (int i = 0; i < metadata.length(); i++) {
final Metadata.Entry entry = metadata.get(i);
// extract IceCast metadata
if (entry instanceof IcyInfo) {
final IcyInfo icyInfo = ((IcyInfo) entry);
updateMetadata(icyInfo.title);
} else if (entry instanceof IcyHeaders) {
final IcyHeaders icyHeaders = ((IcyHeaders) entry);
LogHelper.i(LOG_TAG, "icyHeaders:" + icyHeaders.name + " - " + icyHeaders.genre);
} else if (entry instanceof HlsTrackMetadataEntry) {
final HlsTrackMetadataEntry hlsTrackMetadataEntry = ((HlsTrackMetadataEntry) entry);
}
// TODO implement HLS metadata extraction
// https://exoplayer.dev/doc/reference/com/google/android/exoplayer2/metadata/Metadata.Entry.html
// https://exoplayer.dev/doc/reference/com/google/android/exoplayer2/source/hls/HlsTrackMetadataEntry.html
}
}


Expand Down Expand Up @@ -728,6 +743,9 @@ private void createPlayer() {

// start listening for audio session id
mPlayer.addAnalyticsListener(this);

// start listening for stream metadata
mPlayer.addMetadataOutput(this);
}


Expand All @@ -741,20 +759,20 @@ private DefaultLoadControl createDefaultLoadControl(int factor) {

/* Add a media source to player */
private void preparePlayer(int connectionType) {
// create MediaSource
MediaSource mediaSource;
// create DataSource.Factory - produces DataSource instances through which media data is loaded
DataSource.Factory dataSourceFactory;
dataSourceFactory = new DefaultDataSourceFactory(this, Util.getUserAgent(this, mUserAgent));

// create MediaSource
MediaSource mediaSource;
if (connectionType == CONNECTION_TYPE_HLS) {
// TODO HLS does not work reliable
Toast.makeText(this, this.getString(R.string.toastmessage_stream_may_not_work), Toast.LENGTH_LONG).show();
dataSourceFactory = new DefaultDataSourceFactory(this, Util.getUserAgent(this, mUserAgent));
mediaSource = new HlsMediaSource.Factory(dataSourceFactory).createMediaSource(mStation.getStreamUri());
} else {
dataSourceFactory = new IcyDataSourceFactory(this, Util.getUserAgent(this, mUserAgent), true, playerCallback);
mediaSource = new ProgressiveMediaSource.Factory(dataSourceFactory).setContinueLoadingCheckIntervalBytes(32).createMediaSource(mStation.getStreamUri());
}

// prepare player with source.
mPlayer.prepare(mediaSource);
}
Expand Down Expand Up @@ -898,6 +916,30 @@ private boolean isCarUiMode() {
}


/* Updates metadata info and broadcasts the change to the user interface */
private void updateMetadata(String metadata) {
if (metadata == null || metadata.length() > 0 ) {
mStation.setMetadata(metadata);
} else {
mStation.setMetadata(mStation.getStationName());
}
mStationMetadataReceived = true;

// send local broadcast
Intent i = new Intent();
i.setAction(ACTION_METADATA_CHANGED);
i.putExtra(EXTRA_STATION, mStation);
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(i);
LogHelper.v(LOG_TAG, "LocalBroadcast: ACTION_METADATA_CHANGED -> EXTRA_STATION");

// update media session metadata
mSession.setMetadata(getSessionMetadata(getApplicationContext(), mStation));

// update notification
NotificationHelper.update(PlayerService.this, mStation, mSession);
}


/* Saves state of playback */
private void saveAppState() {
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(getApplication());
Expand Down Expand Up @@ -1115,67 +1157,4 @@ protected void onPostExecute(Integer connectionType) {
* End of inner class
*/


/**
* Callback: Callback from IcyInputStream reacting to new metadata
*/
final PlayerCallback playerCallback = new PlayerCallback() {

@Override
public void playerStarted() {
LogHelper.v(LOG_TAG, "PlayerCallback: playerStarted" );
}

@Override
public void playerPCMFeedBuffer(boolean isPlaying, int audioBufferSizeMs, int audioBufferCapacityMs) {
LogHelper.v(LOG_TAG, "PlayerCallback: playerPCMFeedBuffer" );
}

@Override
public void playerStopped(int perf) {
LogHelper.v(LOG_TAG, "PlayerCallback: playerStopped" );
}

@Override
public void playerException(Throwable t) {
LogHelper.v(LOG_TAG, "PlayerCallback: playerException" );
}

@Override
public void playerMetadata(String key, String value) {
if (key.equals(SHOUTCAST_STREAM_TITLE_HEADER)) {
LogHelper.v(LOG_TAG, "PlayerCallback: playerMetadata " + key + " : " + value);

if (value.length() > 0) {
mStation.setMetadata(value);
} else {
mStation.setMetadata(mStation.getStationName());
}
mStationMetadataReceived = true;

// send local broadcast
Intent i = new Intent();
i.setAction(ACTION_METADATA_CHANGED);
i.putExtra(EXTRA_STATION, mStation);
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(i);
LogHelper.v(LOG_TAG, "LocalBroadcast: ACTION_METADATA_CHANGED -> EXTRA_STATION");

// update media session metadata
mSession.setMetadata(getSessionMetadata(getApplicationContext(), mStation));

// update notification
NotificationHelper.update(PlayerService.this, mStation, mSession);

}
}

@Override
public void playerAudioTrackCreated(AudioTrack audioTrack) {
LogHelper.v(LOG_TAG, "PlayerCallback: playerMetadata" );
}
};
/**
* End of inner callback
*/

}
151 changes: 0 additions & 151 deletions app/src/main/java/org/y20k/transistor/helpers/IcyDataSource.java

This file was deleted.

Loading

0 comments on commit 1ee0975

Please sign in to comment.