Chore/refactor in api folder (#3285)

* feat: add prop to allow controlling of debug log level

* fix: move props parsing to safeGetters

* chore: fix typing

* chore: fix types and lintter

* chore: move file VideoEventEmitter

* fix: make VideoEventEmitter player agnostic

And create a dedicated API data for that

* chore: move generic file in API folder

---------

Co-authored-by: olivier <olivier.bouillet@ifeelsmart.com>
This commit is contained in:
Olivier Bouillet 2023-10-13 17:27:55 +02:00 committed by GitHub
parent ad581ea2dc
commit ab0398d7dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 186 additions and 191 deletions

View File

@ -0,0 +1,54 @@
package com.brentvatne.common.API
import androidx.annotation.IntDef
import java.lang.annotation.Retention
import java.lang.annotation.RetentionPolicy
internal object ResizeMode {
/**
* Either the width or height is decreased to obtain the desired aspect ratio.
*/
const val RESIZE_MODE_FIT = 0
/**
* The width is fixed and the height is increased or decreased to obtain the desired aspect ratio.
*/
const val RESIZE_MODE_FIXED_WIDTH = 1
/**
* The height is fixed and the width is increased or decreased to obtain the desired aspect ratio.
*/
const val RESIZE_MODE_FIXED_HEIGHT = 2
/**
* The height and the width is increased or decreased to fit the size of the view.
*/
const val RESIZE_MODE_FILL = 3
/**
* Keeps the aspect ratio but takes up the view's size.
*/
const val RESIZE_MODE_CENTER_CROP = 4
@JvmStatic
@Mode
fun toResizeMode(ordinal: Int): Int {
return when (ordinal) {
RESIZE_MODE_FIXED_WIDTH -> RESIZE_MODE_FIXED_WIDTH
RESIZE_MODE_FIXED_HEIGHT -> RESIZE_MODE_FIXED_HEIGHT
RESIZE_MODE_FILL -> RESIZE_MODE_FILL
RESIZE_MODE_CENTER_CROP -> RESIZE_MODE_CENTER_CROP
RESIZE_MODE_FIT -> RESIZE_MODE_FIT
else -> RESIZE_MODE_FIT
}
}
@Retention(RetentionPolicy.SOURCE)
@IntDef(
RESIZE_MODE_FIT,
RESIZE_MODE_FIXED_WIDTH,
RESIZE_MODE_FIXED_HEIGHT,
RESIZE_MODE_FILL,
RESIZE_MODE_CENTER_CROP
)
annotation class Mode
}

View File

@ -0,0 +1,38 @@
package com.brentvatne.common.API
import com.brentvatne.ReactBridgeUtils
import com.facebook.react.bridge.ReadableMap
/**
* Helper file to parse SubtitleStyle prop and build a dedicated class
*/
class SubtitleStyle private constructor() {
var fontSize = -1
private set
var paddingLeft = 0
private set
var paddingRight = 0
private set
var paddingTop = 0
private set
var paddingBottom = 0
private set
companion object {
private const val PROP_FONT_SIZE_TRACK = "fontSize"
private const val PROP_PADDING_BOTTOM = "paddingBottom"
private const val PROP_PADDING_TOP = "paddingTop"
private const val PROP_PADDING_LEFT = "paddingLeft"
private const val PROP_PADDING_RIGHT = "paddingRight"
@JvmStatic
fun parse(src: ReadableMap?): SubtitleStyle {
val subtitleStyle = SubtitleStyle()
subtitleStyle.fontSize = ReactBridgeUtils.safeGetInt(src, PROP_FONT_SIZE_TRACK, -1)
subtitleStyle.paddingBottom = ReactBridgeUtils.safeGetInt(src, PROP_PADDING_BOTTOM, 0)
subtitleStyle.paddingTop = ReactBridgeUtils.safeGetInt(src, PROP_PADDING_TOP, 0)
subtitleStyle.paddingLeft = ReactBridgeUtils.safeGetInt(src, PROP_PADDING_LEFT, 0)
subtitleStyle.paddingRight = ReactBridgeUtils.safeGetInt(src, PROP_PADDING_RIGHT, 0)
return subtitleStyle
}
}
}

View File

@ -1,8 +1,10 @@
package com.brentvatne.common.API package com.brentvatne.common.API
class TimedMetadata { /*
@kotlin.jvm.JvmField * class to handle timedEvent retrieved from the stream
var m_Identifier: String? = null */
@kotlin.jvm.JvmField
var m_Value: String? = null class TimedMetadata(_identifier: String? = null, _value: String? = null) {
var identifier: String? = _identifier
var value: String? = _value
} }

View File

@ -0,0 +1,14 @@
package com.brentvatne.common.API
/*
* internal representation of audio & text tracks
*/
class Track {
var title: String? = null
var mimeType: String? = null
var language: String? = null
var isSelected = false
// in bps available only on audio tracks
var bitrate = 0
var index = 0
}

View File

@ -0,0 +1,15 @@
package com.brentvatne.common.API
/*
* internal representation of audio & text tracks
*/
class VideoTrack {
var width = 0
var height = 0
var bitrate = 0
var codecs = ""
var id = -1
var trackId = ""
var isSelected = false
}

View File

@ -1,13 +0,0 @@
package com.brentvatne.common;
import android.net.Uri;
public class Track
{
public String m_title;
public Uri m_uri;
public String m_mimeType;
public String m_language;
public boolean m_isSelected;
public int m_bitrate;
public int m_index;
}

View File

@ -1,12 +0,0 @@
package com.brentvatne.common;
public class VideoTrack
{
public int m_width = 0;
public int m_height = 0;
public int m_bitrate = 0;
public String m_codecs = "";
public int m_id = -1;
public String m_trackId = "";
public boolean m_isSelected = false;
}

View File

@ -4,8 +4,8 @@ import androidx.annotation.StringDef;
import android.view.View; import android.view.View;
import com.brentvatne.common.API.TimedMetadata; import com.brentvatne.common.API.TimedMetadata;
import com.brentvatne.common.Track; import com.brentvatne.common.API.Track;
import com.brentvatne.common.VideoTrack; import com.brentvatne.common.API.VideoTrack;
import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.WritableArray; import com.facebook.react.bridge.WritableArray;
@ -55,7 +55,7 @@ public class VideoEventEmitter {
private static final String EVENT_VIDEO_TRACKS = "onVideoTracks"; private static final String EVENT_VIDEO_TRACKS = "onVideoTracks";
private static final String EVENT_ON_RECEIVE_AD_EVENT = "onReceiveAdEvent"; private static final String EVENT_ON_RECEIVE_AD_EVENT = "onReceiveAdEvent";
public static final String[] Events = { static public final String[] Events = {
EVENT_LOAD_START, EVENT_LOAD_START,
EVENT_LOAD, EVENT_LOAD,
EVENT_ERROR, EVENT_ERROR,
@ -182,11 +182,11 @@ public class VideoEventEmitter {
Track format = audioTracks.get(i); Track format = audioTracks.get(i);
WritableMap audioTrack = Arguments.createMap(); WritableMap audioTrack = Arguments.createMap();
audioTrack.putInt("index", i); audioTrack.putInt("index", i);
audioTrack.putString("title", format.m_title != null ? format.m_title : ""); audioTrack.putString("title", format.getTitle());
audioTrack.putString("type", format.m_mimeType != null ? format.m_mimeType : ""); audioTrack.putString("type", format.getMimeType());
audioTrack.putString("language", format.m_language != null ? format.m_language : ""); audioTrack.putString("language", format.getLanguage());
audioTrack.putInt("bitrate", format.m_bitrate); audioTrack.putInt("bitrate", format.getBitrate());
audioTrack.putBoolean("selected", format.m_isSelected); audioTrack.putBoolean("selected", format.isSelected());
waAudioTracks.pushMap(audioTrack); waAudioTracks.pushMap(audioTrack);
} }
} }
@ -199,12 +199,12 @@ public class VideoEventEmitter {
for (int i = 0; i < videoTracks.size(); ++i) { for (int i = 0; i < videoTracks.size(); ++i) {
VideoTrack vTrack = videoTracks.get(i); VideoTrack vTrack = videoTracks.get(i);
WritableMap videoTrack = Arguments.createMap(); WritableMap videoTrack = Arguments.createMap();
videoTrack.putInt("width", vTrack.m_width); videoTrack.putInt("width", vTrack.getWidth());
videoTrack.putInt("height",vTrack.m_height); videoTrack.putInt("height",vTrack.getHeight());
videoTrack.putInt("bitrate", vTrack.m_bitrate); videoTrack.putInt("bitrate", vTrack.getBitrate());
videoTrack.putString("codecs", vTrack.m_codecs); videoTrack.putString("codecs", vTrack.getCodecs());
videoTrack.putInt("trackId",vTrack.m_id); videoTrack.putInt("trackId",vTrack.getId());
videoTrack.putBoolean("selected", vTrack.m_isSelected); videoTrack.putBoolean("selected", vTrack.isSelected());
waVideoTracks.pushMap(videoTrack); waVideoTracks.pushMap(videoTrack);
} }
} }
@ -218,10 +218,10 @@ public class VideoEventEmitter {
Track format = textTracks.get(i); Track format = textTracks.get(i);
WritableMap textTrack = Arguments.createMap(); WritableMap textTrack = Arguments.createMap();
textTrack.putInt("index", i); textTrack.putInt("index", i);
textTrack.putString("title", format.m_title != null ? format.m_title : ""); textTrack.putString("title", format.getTitle());
textTrack.putString("type", format.m_mimeType != null ? format.m_mimeType : ""); textTrack.putString("type", format.getMimeType());
textTrack.putString("language", format.m_language != null ? format.m_language : ""); textTrack.putString("language", format.getLanguage());
textTrack.putBoolean("selected", format.m_isSelected); textTrack.putBoolean("selected", format.isSelected());
waTextTracks.pushMap(textTrack); waTextTracks.pushMap(textTrack);
} }
} }
@ -388,8 +388,8 @@ public class VideoEventEmitter {
for (int i = 0; i < _metadataArrayList.size(); i++) { for (int i = 0; i < _metadataArrayList.size(); i++) {
WritableMap map = Arguments.createMap(); WritableMap map = Arguments.createMap();
map.putString("identifier", _metadataArrayList.get(i).m_Identifier); map.putString("identifier", _metadataArrayList.get(i).getIdentifier());
map.putString("value", _metadataArrayList.get(i).m_Value); map.putString("value", _metadataArrayList.get(i).getValue());
metadataArray.pushMap(map); metadataArray.pushMap(map);
} }

View File

@ -19,6 +19,8 @@ import android.content.Context;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import com.brentvatne.common.API.ResizeMode;
/** /**
* A {@link FrameLayout} that resizes itself to match a specified aspect ratio. * A {@link FrameLayout} that resizes itself to match a specified aspect ratio.
*/ */

View File

@ -11,6 +11,8 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import com.brentvatne.common.API.ResizeMode;
import com.brentvatne.common.API.SubtitleStyle;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.PlaybackException; import com.google.android.exoplayer2.PlaybackException;
import com.google.android.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.PlaybackParameters;

View File

@ -26,12 +26,13 @@ import androidx.annotation.NonNull;
import androidx.annotation.WorkerThread; import androidx.annotation.WorkerThread;
import androidx.activity.OnBackPressedCallback; import androidx.activity.OnBackPressedCallback;
import com.brentvatne.common.API.ResizeMode;
import com.brentvatne.common.API.SubtitleStyle;
import com.brentvatne.common.API.TimedMetadata; import com.brentvatne.common.API.TimedMetadata;
import com.brentvatne.common.Track; import com.brentvatne.common.API.Track;
import com.brentvatne.common.VideoTrack; import com.brentvatne.common.API.VideoTrack;
import com.brentvatne.common.react.VideoEventEmitter; import com.brentvatne.common.react.VideoEventEmitter;
import com.brentvatne.common.toolbox.DebugLog; import com.brentvatne.common.toolbox.DebugLog;
import com.brentvatne.exoplayer.AudioOutput;
import com.brentvatne.react.R; import com.brentvatne.react.R;
import com.brentvatne.receiver.AudioBecomingNoisyReceiver; import com.brentvatne.receiver.AudioBecomingNoisyReceiver;
import com.brentvatne.receiver.BecomingNoisyListener; import com.brentvatne.receiver.BecomingNoisyListener;
@ -1209,18 +1210,23 @@ public class ReactExoplayerView extends FrameLayout implements
for (int i = 0; i < groups.length; ++i) { for (int i = 0; i < groups.length; ++i) {
TrackGroup group = groups.get(i); TrackGroup group = groups.get(i);
Format format = group.getFormat(0); Format format = group.getFormat(0);
Track audioTrack = new Track(); Track audioTrack = exoplayerTrackToGenericTrack(format, i, selection, group);
audioTrack.m_index = i; audioTrack.setBitrate(format.bitrate == Format.NO_VALUE ? 0 : format.bitrate);
audioTrack.m_title = format.id != null ? format.id : "";
audioTrack.m_mimeType = format.sampleMimeType;
audioTrack.m_language = format.language != null ? format.language : "";
audioTrack.m_bitrate = format.bitrate == Format.NO_VALUE ? 0 : format.bitrate;
audioTrack.m_isSelected = isTrackSelected(selection, group, 0 );
audioTracks.add(audioTrack); audioTracks.add(audioTrack);
} }
return audioTracks; return audioTracks;
} }
private VideoTrack exoplayerVideoTrackToGenericVideoTrack(Format format, int trackIndex) {
VideoTrack videoTrack = new VideoTrack();
videoTrack.setWidth(format.width == Format.NO_VALUE ? 0 : format.width);
videoTrack.setHeight(format.height == Format.NO_VALUE ? 0 : format.height);
videoTrack.setBitrate(format.bitrate == Format.NO_VALUE ? 0 : format.bitrate);
if (format.codecs != null) videoTrack.setCodecs(format.codecs);
videoTrack.setTrackId(format.id == null ? String.valueOf(trackIndex) : format.id);;
return videoTrack;
}
private ArrayList<VideoTrack> getVideoTrackInfo() { private ArrayList<VideoTrack> getVideoTrackInfo() {
ArrayList<VideoTrack> videoTracks = new ArrayList<>(); ArrayList<VideoTrack> videoTracks = new ArrayList<>();
if (trackSelector == null) { if (trackSelector == null) {
@ -1240,12 +1246,7 @@ public class ReactExoplayerView extends FrameLayout implements
for (int trackIndex = 0; trackIndex < group.length; trackIndex++) { for (int trackIndex = 0; trackIndex < group.length; trackIndex++) {
Format format = group.getFormat(trackIndex); Format format = group.getFormat(trackIndex);
if (isFormatSupported(format)) { if (isFormatSupported(format)) {
VideoTrack videoTrack = new VideoTrack(); VideoTrack videoTrack = exoplayerVideoTrackToGenericVideoTrack(format, trackIndex);
videoTrack.m_width = format.width == Format.NO_VALUE ? 0 : format.width;
videoTrack.m_height = format.height == Format.NO_VALUE ? 0 : format.height;
videoTrack.m_bitrate = format.bitrate == Format.NO_VALUE ? 0 : format.bitrate;
videoTrack.m_codecs = format.codecs != null ? format.codecs : "";
videoTrack.m_trackId = format.id == null ? String.valueOf(trackIndex) : format.id;
videoTracks.add(videoTrack); videoTracks.add(videoTrack);
} }
} }
@ -1291,12 +1292,7 @@ public class ReactExoplayerView extends FrameLayout implements
break; break;
} }
hasFoundContentPeriod = true; hasFoundContentPeriod = true;
VideoTrack videoTrack = new VideoTrack(); VideoTrack videoTrack = exoplayerVideoTrackToGenericVideoTrack(format, representationIndex);
videoTrack.m_width = format.width == Format.NO_VALUE ? 0 : format.width;
videoTrack.m_height = format.height == Format.NO_VALUE ? 0 : format.height;
videoTrack.m_bitrate = format.bitrate == Format.NO_VALUE ? 0 : format.bitrate;
videoTrack.m_codecs = format.codecs != null ? format.codecs : "";
videoTrack.m_trackId = format.id == null ? String.valueOf(representationIndex) : format.id;
videoTracks.add(videoTrack); videoTracks.add(videoTrack);
} }
} }
@ -1326,6 +1322,17 @@ public class ReactExoplayerView extends FrameLayout implements
return null; return null;
} }
private Track exoplayerTrackToGenericTrack(Format format, int trackIndex, TrackSelection selection, TrackGroup group) {
Track track = new Track();
track.setIndex(trackIndex);
if (format.sampleMimeType != null) track.setMimeType(format.sampleMimeType);
if (format.language != null) track.setLanguage(format.language);
if (format.id != null) track.setTitle(format.id);
track.setSelected(isTrackSelected(selection, group, 0));
return track;
}
private ArrayList<Track> getTextTrackInfo() { private ArrayList<Track> getTextTrackInfo() {
ArrayList<Track> textTracks = new ArrayList<>(); ArrayList<Track> textTracks = new ArrayList<>();
if (trackSelector == null) { if (trackSelector == null) {
@ -1343,13 +1350,7 @@ public class ReactExoplayerView extends FrameLayout implements
for (int i = 0; i < groups.length; ++i) { for (int i = 0; i < groups.length; ++i) {
TrackGroup group = groups.get(i); TrackGroup group = groups.get(i);
Format format = group.getFormat(0); Format format = group.getFormat(0);
Track textTrack = exoplayerTrackToGenericTrack(format, i, selection, group);
Track textTrack = new Track();
textTrack.m_index = i;
textTrack.m_title = format.id != null ? format.id : "";
textTrack.m_mimeType = format.sampleMimeType;
textTrack.m_language = format.language != null ? format.language : "";
textTrack.m_isSelected = isTrackSelected(selection, group, 0 );
textTracks.add(textTrack); textTracks.add(textTrack);
} }
return textTracks; return textTracks;
@ -1494,19 +1495,11 @@ public class ReactExoplayerView extends FrameLayout implements
TextInformationFrame txxxFrame = (TextInformationFrame) frame; TextInformationFrame txxxFrame = (TextInformationFrame) frame;
value = txxxFrame.value; value = txxxFrame.value;
} }
TimedMetadata timedMetadata = new TimedMetadata(frame.id, value);
String identifier = frame.id;
TimedMetadata timedMetadata = new TimedMetadata();
timedMetadata.m_Identifier = identifier;
timedMetadata.m_Value = value;
metadataArray.add(timedMetadata); metadataArray.add(timedMetadata);
} else if (entry instanceof EventMessage) { } else if (entry instanceof EventMessage) {
EventMessage eventMessage = (EventMessage) entry; EventMessage eventMessage = (EventMessage) entry;
TimedMetadata timedMetadata = new TimedMetadata(); TimedMetadata timedMetadata = new TimedMetadata(eventMessage.schemeIdUri, eventMessage.value);
timedMetadata.m_Identifier = eventMessage.schemeIdUri;
timedMetadata.m_Value = eventMessage.value;
metadataArray.add(timedMetadata); metadataArray.add(timedMetadata);
} else { } else {
DebugLog.d(TAG, "unhandled metadata " + entry.toString()); DebugLog.d(TAG, "unhandled metadata " + entry.toString());

View File

@ -6,10 +6,11 @@ import android.net.Uri;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import com.brentvatne.common.API.ResizeMode;
import com.brentvatne.common.API.SubtitleStyle;
import com.brentvatne.common.react.VideoEventEmitter; import com.brentvatne.common.react.VideoEventEmitter;
import com.brentvatne.common.toolbox.DebugLog; import com.brentvatne.common.toolbox.DebugLog;
import com.brentvatne.common.toolbox.ReactBridgeUtils; import com.brentvatne.common.toolbox.ReactBridgeUtils;
import com.brentvatne.exoplayer.AudioOutput;
import com.facebook.react.bridge.Dynamic; import com.facebook.react.bridge.Dynamic;
import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.ReadableMap;

View File

@ -1,63 +0,0 @@
package com.brentvatne.exoplayer;
import androidx.annotation.IntDef;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.SOURCE;
class ResizeMode {
/**
* Either the width or height is decreased to obtain the desired aspect ratio.
*/
static final int RESIZE_MODE_FIT = 0;
/**
* The width is fixed and the height is increased or decreased to obtain the desired aspect ratio.
*/
static final int RESIZE_MODE_FIXED_WIDTH = 1;
/**
* The height is fixed and the width is increased or decreased to obtain the desired aspect ratio.
*/
static final int RESIZE_MODE_FIXED_HEIGHT = 2;
/**
* The height and the width is increased or decreased to fit the size of the view.
*/
static final int RESIZE_MODE_FILL = 3;
/**
* Keeps the aspect ratio but takes up the view's size.
*/
static final int RESIZE_MODE_CENTER_CROP = 4;
@Retention(SOURCE)
@IntDef({
RESIZE_MODE_FIT,
RESIZE_MODE_FIXED_WIDTH,
RESIZE_MODE_FIXED_HEIGHT,
RESIZE_MODE_FILL,
RESIZE_MODE_CENTER_CROP
})
public @interface Mode {
}
@ResizeMode.Mode static int toResizeMode(int ordinal) {
switch (ordinal) {
case ResizeMode.RESIZE_MODE_FIXED_WIDTH:
return ResizeMode.RESIZE_MODE_FIXED_WIDTH;
case ResizeMode.RESIZE_MODE_FIXED_HEIGHT:
return ResizeMode.RESIZE_MODE_FIXED_HEIGHT;
case ResizeMode.RESIZE_MODE_FILL:
return ResizeMode.RESIZE_MODE_FILL;
case ResizeMode.RESIZE_MODE_CENTER_CROP:
return ResizeMode.RESIZE_MODE_CENTER_CROP;
case ResizeMode.RESIZE_MODE_FIT:
default:
return ResizeMode.RESIZE_MODE_FIT;
}
}
}

View File

@ -1,38 +0,0 @@
package com.brentvatne.exoplayer;
import com.brentvatne.ReactBridgeUtils;
import com.facebook.react.bridge.ReadableMap;
/**
* Helper file to parse SubtitleStyle prop and build a dedicated class
*/
public class SubtitleStyle {
private static final String PROP_FONT_SIZE_TRACK = "fontSize";
private static final String PROP_PADDING_BOTTOM = "paddingBottom";
private static final String PROP_PADDING_TOP = "paddingTop";
private static final String PROP_PADDING_LEFT = "paddingLeft";
private static final String PROP_PADDING_RIGHT = "paddingRight";
private int fontSize = -1;
private int paddingLeft = 0;
private int paddingRight = 0;
private int paddingTop = 0;
private int paddingBottom = 0;
private SubtitleStyle() {}
int getFontSize() {return fontSize;}
int getPaddingBottom() {return paddingBottom;}
int getPaddingTop() {return paddingTop;}
int getPaddingLeft() {return paddingLeft;}
int getPaddingRight() {return paddingRight;}
public static SubtitleStyle parse(ReadableMap src) {
SubtitleStyle subtitleStyle = new SubtitleStyle();
subtitleStyle.fontSize = ReactBridgeUtils.safeGetInt(src, PROP_FONT_SIZE_TRACK, -1);
subtitleStyle.paddingBottom = ReactBridgeUtils.safeGetInt(src, PROP_PADDING_BOTTOM, 0);
subtitleStyle.paddingTop = ReactBridgeUtils.safeGetInt(src, PROP_PADDING_TOP, 0);
subtitleStyle.paddingLeft = ReactBridgeUtils.safeGetInt(src, PROP_PADDING_LEFT, 0);
subtitleStyle.paddingRight = ReactBridgeUtils.safeGetInt(src, PROP_PADDING_RIGHT, 0);
return subtitleStyle;
}
}