Skip to content

Commit

Permalink
v1.0.6 - text captions
Browse files Browse the repository at this point in the history
* ability to sideload an external subtitles text file with video
* button on controls overlay that opens a dialog
  - tabbed UI: video tracks, audio tracks, text tracks
    * can select one of the available options, or disable
* HTTP endpoint to toggle captions on/off
* SPA provides easy access to all HTTP endpoint functionality
  • Loading branch information
warren-bank committed Feb 28, 2020
1 parent fe3363e commit e52903c
Show file tree
Hide file tree
Showing 17 changed files with 820 additions and 180 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ dependencies {
compileOnly 'androidx.annotation:annotation:' + project.ext.libVersionAndroidX // ( 27 KB) https://mvnrepository.com/artifact/androidx.annotation/annotation
annotationProcessor 'androidx.annotation:annotation:' + project.ext.libVersionAndroidX

implementation 'androidx.appcompat:appcompat:' + project.ext.libVersionAndroidX // (1.0 MB) https://mvnrepository.com/artifact/androidx.appcompat/appcompat

implementation 'com.google.android.material:material:' + project.ext.libVersionMaterial // (567 KB) https://mvnrepository.com/artifact/com.google.android.material/material

implementation 'com.google.android.exoplayer:exoplayer-core:' + project.ext.libVersionExoPlayer // (1.3 MB) https://mvnrepository.com/artifact/com.google.android.exoplayer/exoplayer-core?repo=bt-google-exoplayer
implementation 'com.google.android.exoplayer:exoplayer-dash:' + project.ext.libVersionExoPlayer // (107 KB) https://mvnrepository.com/artifact/com.google.android.exoplayer/exoplayer-dash?repo=bt-google-exoplayer
implementation 'com.google.android.exoplayer:exoplayer-hls:' + project.ext.libVersionExoPlayer // ( 98 KB) https://mvnrepository.com/artifact/com.google.android.exoplayer/exoplayer-hls?repo=bt-google-exoplayer
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
-keep class com.github.warren_bank.exoplayer_airplay_receiver.** { *; }

-keep class com.google.android.exoplayer.** { *; }
-keep class com.google.android.exoplayer2.** { *; }

-keep class javax.jmdns.** { *; }

-dontwarn com.google.android.exoplayer2.**
-dontwarn javax.jmdns.test.**
-dontwarn org.apache.**
-dontwarn org.slf4j.**
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@

<activity
android:name=".ui.VideoPlayerActivity"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:theme="@style/VideoPlayerTheme"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout|smallestScreenSize|uiMode"
android:launchMode="singleTask" />

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ public class Constant {
public static final String Need_sendReverse = "SendReverse";
public static final String ReverseMsg = "ReverseMsg";
public static final String PlayURL = "playUrl";
public static final String CaptionURL = "textUrl";
public static final String RefererURL = "referUrl";
public static final String Start_Pos = "startPos";

Expand Down Expand Up @@ -160,39 +161,41 @@ public interface Register {
}

public interface Msg {
public static final int Msg_Photo = 1;
public static final int Msg_Stop = 2;
public static final int Msg_Video_Play = 3;
public static final int Msg_Video_Seek = 4;
public static final int Msg_Video_Rate = 5;

public static final int Msg_Video_Queue = 6;
public static final int Msg_Video_Next = 7;
public static final int Msg_Video_Prev = 8;
public static final int Msg_Audio_Volume = 9;
public static final int Msg_Photo = 1;
public static final int Msg_Stop = 2;
public static final int Msg_Video_Play = 3;
public static final int Msg_Video_Seek = 4;
public static final int Msg_Video_Rate = 5;

public static final int Msg_Video_Queue = 6;
public static final int Msg_Video_Next = 7;
public static final int Msg_Video_Prev = 8;
public static final int Msg_Audio_Volume = 9;
public static final int Msg_Text_Captions = 10;
}

public interface Target {
public static final String REVERSE = "/reverse";
public static final String PHOTO = "/photo";
public static final String SERVER_INFO = "/server-info";
public static final String STOP = "/stop";
public static final String PLAY = "/play";
public static final String SCRUB = "/scrub";
public static final String RATE = "/rate";
public static final String PLAYBACK_INFO = "/playback-info";

public static final String QUEUE = "/queue";
public static final String NEXT = "/next";
public static final String PREVIOUS = "/previous";
public static final String VOLUME = "/volume";
public static final String REVERSE = "/reverse";
public static final String PHOTO = "/photo";
public static final String SERVER_INFO = "/server-info";
public static final String STOP = "/stop";
public static final String PLAY = "/play";
public static final String SCRUB = "/scrub";
public static final String RATE = "/rate";
public static final String PLAYBACK_INFO = "/playback-info";

public static final String QUEUE = "/queue";
public static final String NEXT = "/next";
public static final String PREVIOUS = "/previous";
public static final String VOLUME = "/volume";
public static final String CAPTIONS = "/captions";
}

public interface Status {
public static final String Status_play = "playing";
public static final String Status_stop = "stopped";
public static final String Status_pause = "paused";
public static final String Status_load = "loading";
public static final String Status_play = "playing";
public static final String Status_stop = "stopped";
public static final String Status_pause = "paused";
public static final String Status_load = "loading";
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -411,59 +411,25 @@ else if ("displayCached".equals(assetAction)) {
}
}
}
else if (target.equals(Constant.Target.PLAY) && (entityContent != null)) { //Pushed videos
String playUrl = "";
Double startPos = 0.0;

requestBody = new String(entityContent);
requestBody = StringUtils.convertEscapedLinefeeds(requestBody); //Not necessary; courtesy to curl users.
Log.d(tag, " airplay play action request content = " + requestBody);
//a video from iPhone
if (contentType.equalsIgnoreCase("application/x-apple-binary-plist")) {
//<BINARY PLIST DATA>
HashMap map = BplistParser.parse(entityContent);
playUrl = (String) map.get("Content-Location");
startPos = (Double) map.get("Start-Position");
}
else {
//iTunes pushed videos or Youku
playUrl = StringUtils.getRequestBodyValue(requestBody, "Content-Location:");
String v = StringUtils.getRequestBodyValue(requestBody, "Start-Position:");
startPos = (v.isEmpty()) ? 0.0 : Double.valueOf(v);
}

if (playUrl.isEmpty()) {
Log.d(tag, "airplay video URL missing");

setCommonHeaders(httpResponse, HttpStatus.SC_BAD_REQUEST);
}
else {
Log.d(tag, "airplay playUrl = " + playUrl + "; start Pos = " + startPos);

Message msg = Message.obtain();
HashMap<String, String> map = new HashMap<String, String>();
map.put(Constant.PlayURL, playUrl);
map.put(Constant.Start_Pos, Double.toString(startPos));
msg.what = Constant.Msg.Msg_Video_Play;
msg.obj = map;
MainApp.broadcastMessage(msg);

setCommonHeaders(httpResponse, HttpStatus.SC_OK);
}
}
else if (target.startsWith(Constant.Target.SCRUB)) { //POST is the seek operation. GET returns the position and duration of the play.
StringEntity returnBody = new StringEntity("");

String position = StringUtils.getQueryStringValue(target, "?position=");
if (!position.isEmpty()) {
//post method
float pos = new Float(position);
Log.d(tag, "airplay seek position = " + pos); //unit is seconds

Message msg = Message.obtain();
msg.what = Constant.Msg.Msg_Video_Seek;
msg.obj = pos;
MainApp.broadcastMessage(msg);
try {
float pos = Float.parseFloat(position);
Log.d(tag, "airplay seek position = " + pos); //unit is seconds

Message msg = Message.obtain();
msg.what = Constant.Msg.Msg_Video_Seek;
msg.obj = pos;
MainApp.broadcastMessage(msg);
}
catch (NumberFormatException e) {
setCommonHeaders(httpResponse, HttpStatus.SC_BAD_REQUEST);
return;
}
}
else {
//get method to get the duration and position of the playback
Expand Down Expand Up @@ -500,13 +466,19 @@ else if (target.startsWith(Constant.Target.SCRUB)) { //POST is the seek operatio
else if (target.startsWith(Constant.Target.RATE)) { //Set playback rate (special case: 0 is pause)
String value = StringUtils.getQueryStringValue(target, "?value=");
if (!value.isEmpty()) {
float rate = new Float(value);
Log.d(tag, "airplay rate = " + rate);

Message msg = Message.obtain();
msg.what = Constant.Msg.Msg_Video_Rate;
msg.obj = rate;
MainApp.broadcastMessage(msg);
try {
float rate = Float.parseFloat(value);
Log.d(tag, "airplay rate = " + rate);

Message msg = Message.obtain();
msg.what = Constant.Msg.Msg_Video_Rate;
msg.obj = rate;
MainApp.broadcastMessage(msg);
}
catch (NumberFormatException e) {
setCommonHeaders(httpResponse, HttpStatus.SC_BAD_REQUEST);
return;
}
}

setCommonHeaders(httpResponse, HttpStatus.SC_OK);
Expand Down Expand Up @@ -557,8 +529,14 @@ else if (target.equals("/fp-setup")) {
// =======================================================================
// non-standard extended API methods:
// =======================================================================
else if (target.equals(Constant.Target.QUEUE) && (entityContent != null)) { //Add video to end of queue
else if (
(entityContent != null) && (
target.equals(Constant.Target.PLAY) || //Clear queue and add new video
target.equals(Constant.Target.QUEUE) //Add video to end of queue
)
) {
String playUrl = "";
String textUrl = "";
String referUrl = "";
Double startPos = 0.0;

Expand All @@ -570,12 +548,14 @@ else if (target.equals(Constant.Target.QUEUE) && (entityContent != null)) { //Ad
//<BINARY PLIST DATA>
HashMap map = BplistParser.parse(entityContent);
playUrl = (String) map.get("Content-Location");
textUrl = (String) map.get("Caption-Location");
referUrl = (String) map.get("Referer");
startPos = (Double) map.get("Start-Position");
}
else {
//iTunes pushed videos or Youku
playUrl = StringUtils.getRequestBodyValue(requestBody, "Content-Location:");
textUrl = StringUtils.getRequestBodyValue(requestBody, "Caption-Location:");
referUrl = StringUtils.getRequestBodyValue(requestBody, "Referer:");
String v = StringUtils.getRequestBodyValue(requestBody, "Start-Position:");
startPos = (v.isEmpty()) ? 0.0 : Double.valueOf(v);
Expand All @@ -587,14 +567,17 @@ else if (target.equals(Constant.Target.QUEUE) && (entityContent != null)) { //Ad
setCommonHeaders(httpResponse, HttpStatus.SC_BAD_REQUEST);
}
else {
Log.d(tag, "airplay playUrl = " + playUrl + "; start Pos = " + startPos + "; referer = " + referUrl);
Log.d(tag, "airplay playUrl = " + playUrl + "; start Pos = " + startPos + "; captions = " + textUrl + "; referer = " + referUrl);

Message msg = Message.obtain();
HashMap<String, String> map = new HashMap<String, String>();
map.put(Constant.PlayURL, playUrl);
map.put(Constant.CaptionURL, textUrl);
map.put(Constant.RefererURL, referUrl);
map.put(Constant.Start_Pos, Double.toString(startPos));
msg.what = Constant.Msg.Msg_Video_Queue;
msg.what = target.equals(Constant.Target.PLAY)
? Constant.Msg.Msg_Video_Play
: Constant.Msg.Msg_Video_Queue;
msg.obj = map;
MainApp.broadcastMessage(msg);

Expand All @@ -618,17 +601,42 @@ else if (target.equals(Constant.Target.PREVIOUS)) { //skip backward to previous
else if (target.startsWith(Constant.Target.VOLUME)) { //set audio volume (special case: 0 is mute)
String value = StringUtils.getQueryStringValue(target, "?value=");
if (!value.isEmpty()) {
float audioVolume = new Float(value);
Log.d(tag, "airplay volume = " + audioVolume);

Message msg = Message.obtain();
msg.what = Constant.Msg.Msg_Audio_Volume;
msg.obj = audioVolume;
MainApp.broadcastMessage(msg);
try {
float audioVolume = Float.parseFloat(value);
Log.d(tag, "airplay volume = " + audioVolume);

Message msg = Message.obtain();
msg.what = Constant.Msg.Msg_Audio_Volume;
msg.obj = audioVolume;
MainApp.broadcastMessage(msg);
}
catch (NumberFormatException e) {
setCommonHeaders(httpResponse, HttpStatus.SC_BAD_REQUEST);
return;
}
}

setCommonHeaders(httpResponse, HttpStatus.SC_OK);
}
else if (target.startsWith(Constant.Target.CAPTIONS)) { //toggle text captions on/off
String value = StringUtils.getQueryStringValue(target, "?toggle=");
if (!value.isEmpty()) {
try {
int toggleValue = Integer.parseInt(value, 10);
Log.d(tag, "airplay captions = " + toggleValue);

Message msg = Message.obtain();
msg.what = Constant.Msg.Msg_Text_Captions;
msg.obj = (toggleValue != 0); //boolean whether to "show"
MainApp.broadcastMessage(msg);
}
catch (NumberFormatException e) {
setCommonHeaders(httpResponse, HttpStatus.SC_BAD_REQUEST);
return;
}
}
setCommonHeaders(httpResponse, HttpStatus.SC_OK);
}

// =======================================================================
else {
Log.d(tag, "airplay default not process");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -368,28 +368,18 @@ public void handleMessage(Message msg) {
service.startActivity(intent);
break;
}
case Constant.Msg.Msg_Video_Play : {
HashMap<String, String> map = (HashMap) msg.obj;
String playUrl = map.get(Constant.PlayURL);
String startPos = map.get(Constant.Start_Pos);

Intent intent = new Intent(service, VideoPlayerActivity.class);
intent.putExtra("mode", "play");
intent.putExtra("uri", playUrl);
intent.putExtra("startPosition", Double.valueOf(startPos));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
service.startActivity(intent);
break;
}
case Constant.Msg.Msg_Video_Play :
case Constant.Msg.Msg_Video_Queue : {
HashMap<String, String> map = (HashMap) msg.obj;
String playUrl = map.get(Constant.PlayURL);
String textUrl = map.get(Constant.CaptionURL);
String referUrl = map.get(Constant.RefererURL);
String startPos = map.get(Constant.Start_Pos);

Intent intent = new Intent(service, VideoPlayerActivity.class);
intent.putExtra("mode", "queue");
intent.putExtra("mode", ((msg.what == Constant.Msg.Msg_Video_Play) ? "play" : "queue"));
intent.putExtra("uri", playUrl);
intent.putExtra("caption", textUrl);
intent.putExtra("referer", referUrl);
intent.putExtra("startPosition", Double.valueOf(startPos));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ public void handleMessage(Message msg) {
float audioVolume = (float) msg.obj;
activity.playerManager.AirPlay_volume(audioVolume);
break;
case Constant.Msg.Msg_Text_Captions :
boolean showCaptions = (boolean) msg.obj;
activity.playerManager.AirPlay_captions(showCaptions);
break;
}

}
Expand Down
Loading

0 comments on commit e52903c

Please sign in to comment.