Skip to content

Commit

Permalink
feat(android): add prop to control debug log level (#3277)
Browse files Browse the repository at this point in the history
* feat: add prop to allow controlling of debug log level

* fix: move props parsing to safeGetters

---------

Co-authored-by: olivier <[email protected]>
  • Loading branch information
freeboub and olivier authored Oct 10, 2023
1 parent 0ad2e52 commit add8792
Show file tree
Hide file tree
Showing 7 changed files with 324 additions and 72 deletions.
23 changes: 23 additions & 0 deletions API.md
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@ var styles = StyleSheet.create({
| [contentStartTime](#contentstarttime) | Android |
| [controls](#controls) | Android, iOS |
| [currentPlaybackTime](#currentplaybacktime) | Android |
| [debug](#debug) | Android |
| [disableFocus](#disablefocus) | Android, iOS |
| [disableDisconnectError](#disabledisconnecterror) | Android |
| [filter](#filter) | iOS |
Expand Down Expand Up @@ -497,6 +498,28 @@ The start time in ms for SSAI content. This determines at what time to load the

Platforms: Android, iOS

#### debug

Enable more verbosity in logs.

> [!WARNING]
> Do not use this open in production build
| Property | Type | Description |
| ------------------ | ------ | ------------------------------------------------------------------------------------------- |
| enable | boolean | when true, display logs with verbosity higher |
| thread | boolean | enable thread display |


Example with default values:
```
debug={{
enable: true,
thread: true,
}}
```
Platforms: Android

#### disableFocus
Determines whether video audio should override background music/audio in Android devices.
* **false (default)** - Override background audio/music
Expand Down
95 changes: 95 additions & 0 deletions android/src/main/java/com/brentvatne/common/toolbox/DebugLog.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package com.brentvatne.common.toolbox

import android.os.Build
import android.util.Log
import java.lang.Exception

/* log utils
* This class allow defining a log level for the package
* This is useful for debugging real time issue or tricky use cases
*/

object DebugLog {
// log level to display
private var level = Log.WARN
// enable thread display in logs
private var displayThread = true
// add a common prefix for easy filtering
private const val TAG_PREFIX = "RNV"

@JvmStatic
fun setConfig(_level: Int, _displayThread: Boolean) {
level = _level
displayThread = _displayThread
}

@JvmStatic
private fun getTag(tag: String): String {
return TAG_PREFIX + tag
}

@JvmStatic
private fun getMsg(msg: String): String {
return if (displayThread) {
"[" + Thread.currentThread().name + "] " + msg
} else msg
}

@JvmStatic
fun v(tag: String, msg: String) {
if (level <= Log.VERBOSE) Log.v(getTag(tag), getMsg(msg))
}

@JvmStatic
fun d(tag: String, msg: String) {
if (level <= Log.DEBUG) Log.d(getTag(tag), getMsg(msg))
}

@JvmStatic
fun i(tag: String, msg: String) {
if (level <= Log.INFO) Log.i(getTag(tag), getMsg(msg))
}

@JvmStatic
fun w(tag: String, msg: String) {
if (level <= Log.WARN) Log.w(getTag(tag), getMsg(msg))
}

@JvmStatic
fun e(tag: String, msg: String) {
if (level <= Log.ERROR) Log.e(getTag(tag), getMsg(msg))
}

@JvmStatic
fun wtf(tag: String, msg: String) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) {
Log.wtf(getTag(tag), "--------------->" + getMsg(msg))
} else {
Log.e(getTag(tag), "--------------->" + getMsg(msg))
}
printCallStack()
}

@JvmStatic
fun printCallStack() {
if (level <= Log.VERBOSE) {
val e = Exception()
e.printStackTrace()
}
}

// Additionnal thread safety checkers
@JvmStatic
fun checkUIThread(tag: String, msg: String) {
if (Thread.currentThread().name != "main") {
wtf(tag, "------------------------>" + getMsg(msg))
}
}

@JvmStatic
fun checkNotUIThread(tag: String, msg: String) {
if (Thread.currentThread().name == "main") {
wtf(tag, "------------------------>" + getMsg(msg))
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
package com.brentvatne.common.toolbox

import com.facebook.react.bridge.Dynamic
import com.facebook.react.bridge.ReadableMap
import com.facebook.react.bridge.ReadableArray
import java.util.HashMap

/*
* Toolbox to safe parsing of <Video props
* These are just safe accessors to ReadableMap
*/

object ReactBridgeUtils {
@JvmStatic
fun safeGetString(map: ReadableMap?, key: String?, fallback: String?): String? {
return if (map != null && map.hasKey(key!!) && !map.isNull(key)) map.getString(key) else fallback
}

@JvmStatic
fun safeGetString(map: ReadableMap?, key: String?): String? {
return safeGetString(map, key, null)
}

@JvmStatic
fun safeGetDynamic(map: ReadableMap?, key: String?, fallback: Dynamic?): Dynamic? {
return if (map != null && map.hasKey(key!!) && !map.isNull(key)) map.getDynamic(key) else fallback
}

@JvmStatic
fun safeGetDynamic(map: ReadableMap?, key: String?): Dynamic? {
return safeGetDynamic(map, key, null)
}

@JvmStatic
fun safeGetBool(map: ReadableMap?, key: String?, fallback: Boolean): Boolean {
return if (map != null && map.hasKey(key!!) && !map.isNull(key)) map.getBoolean(key) else fallback
}

@JvmStatic
fun safeGetMap(map: ReadableMap?, key: String?): ReadableMap? {
return if (map != null && map.hasKey(key!!) && !map.isNull(key)) map.getMap(key) else null
}

@JvmStatic
fun safeGetArray(map: ReadableMap?, key: String?): ReadableArray? {
return if (map != null && map.hasKey(key!!) && !map.isNull(key)) map.getArray(key) else null
}

@JvmStatic
fun safeGetInt(map: ReadableMap?, key: String?, fallback: Int): Int {
return if (map != null && map.hasKey(key!!) && !map.isNull(key)) map.getInt(key) else fallback
}

@JvmStatic
fun safeGetInt(map: ReadableMap?, key: String?): Int {
return safeGetInt(map, key, 0);
}

@JvmStatic
fun safeGetDouble(map: ReadableMap?, key: String?, fallback: Double): Double {
return if (map != null && map.hasKey(key!!) && !map.isNull(key)) map.getDouble(key) else fallback
}
@JvmStatic
fun safeGetDouble(map: ReadableMap?, key: String?): Double {
return safeGetDouble(map, key, 0.0);
}
/**
* toStringMap converts a [ReadableMap] into a HashMap.
*
* @param readableMap The ReadableMap to be conveted.
* @return A HashMap containing the data that was in the ReadableMap.
* @see 'Adapted from https://github.com/artemyarulin/react-native-eval/blob/master/android/src/main/java/com/evaluator/react/ConversionUtil.java'
*/
@JvmStatic
fun toStringMap(readableMap: ReadableMap?): Map<String, String?>? {
if (readableMap == null) return null
val iterator = readableMap.keySetIterator()
if (!iterator.hasNextKey()) return null
val result: MutableMap<String, String?> = HashMap()
while (iterator.hasNextKey()) {
val key = iterator.nextKey()
result[key] = readableMap.getString(key)
}
return result
}

/**
* toIntMap converts a [ReadableMap] into a HashMap.
*
* @param readableMap The ReadableMap to be conveted.
* @return A HashMap containing the data that was in the ReadableMap.
* @see 'Adapted from https://github.com/artemyarulin/react-native-eval/blob/master/android/src/main/java/com/evaluator/react/ConversionUtil.java'
*/
@JvmStatic
fun toIntMap(readableMap: ReadableMap?): Map<String, Int>? {
if (readableMap == null) return null
val iterator = readableMap.keySetIterator()
if (!iterator.hasNextKey()) return null
val result: MutableMap<String, Int> = HashMap()
while (iterator.hasNextKey()) {
val key = iterator.nextKey()
result[key] = readableMap.getInt(key)
}
return result
}

@JvmStatic
fun safeStringEquals(str1: String?, str2: String?): Boolean {
if (str1 == null && str2 == null) return true // both are null
return if (str1 == null || str2 == null) false else str1 == str2 // only 1 is null
}

@JvmStatic
fun safeStringArrayEquals(str1: Array<String>?, str2: Array<String>?): Boolean {
if (str1 == null && str2 == null) return true // both are null
if (str1 == null || str2 == null) return false // only 1 is null
if (str1.size != str2.size) return false // only 1 is null
for (i in str1.indices) {
if (str1[i] == str2[i]) // standard check
return false
}
return true
}

@JvmStatic
fun safeStringMapEquals(
first: Map<String?, String?>?,
second: Map<String?, String?>?
): Boolean {
if (first == null && second == null) return true // both are null
if (first == null || second == null) return false // only 1 is null
if (first.size != second.size) {
return false
}
for (key in first.keys) {
if (!safeStringEquals(first[key], second[key])) {
return false
}
}
return true
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.accessibility.CaptioningManager;
Expand All @@ -28,6 +27,7 @@

import com.brentvatne.common.Track;
import com.brentvatne.common.VideoTrack;
import com.brentvatne.common.toolbox.DebugLog;
import com.brentvatne.exoplayer.AudioOutput;
import com.brentvatne.react.R;
import com.brentvatne.receiver.AudioBecomingNoisyReceiver;
Expand Down Expand Up @@ -531,7 +531,7 @@ public boolean shouldContinueLoading(long playbackPositionUs, long bufferedDurat
return false;
}
if (runtime.freeMemory() == 0) {
Log.w("ExoPlayer Warning", "Free memory reached 0, forcing garbage collection");
DebugLog.w("ExoPlayer Warning", "Free memory reached 0, forcing garbage collection");
runtime.gc();
return false;
}
Expand Down Expand Up @@ -569,13 +569,13 @@ public void run() {
DrmSessionManager drmSessionManager = initializePlayerDrm(self);
if (drmSessionManager == null && self.drmUUID != null) {
// Failed to intialize DRM session manager - cannot continue
Log.e("ExoPlayer Exception", "Failed to initialize DRM Session Manager Framework!");
DebugLog.e("ExoPlayer Exception", "Failed to initialize DRM Session Manager Framework!");
eventEmitter.error("Failed to initialize DRM Session Manager Framework!", new Exception("DRM Session Manager Framework failure!"), "3003");
return;
}

if (activity == null) {
Log.e("ExoPlayer Exception", "Failed to initialize Player!");
DebugLog.e("ExoPlayer Exception", "Failed to initialize Player!");
eventEmitter.error("Failed to initialize Player!", new Exception("Current Activity is null!"), "1001");
return;
}
Expand All @@ -588,8 +588,8 @@ public void run() {
initializePlayerSource(self, drmSessionManager);
} catch (Exception ex) {
self.playerNeedsSource = true;
Log.e("ExoPlayer Exception", "Failed to initialize Player!");
Log.e("ExoPlayer Exception", ex.toString());
DebugLog.e("ExoPlayer Exception", "Failed to initialize Player!");
DebugLog.e("ExoPlayer Exception", ex.toString());
self.eventEmitter.error(ex.toString(), ex, "1001");
}
}
Expand All @@ -601,8 +601,8 @@ public void run() {
}
} catch (Exception ex) {
self.playerNeedsSource = true;
Log.e("ExoPlayer Exception", "Failed to initialize Player!");
Log.e("ExoPlayer Exception", ex.toString());
DebugLog.e("ExoPlayer Exception", "Failed to initialize Player!");
DebugLog.e("ExoPlayer Exception", ex.toString());
eventEmitter.error(ex.toString(), ex, "1001");
}
}
Expand Down Expand Up @@ -711,7 +711,7 @@ private void initializePlayerSource(ReactExoplayerView self, DrmSessionManager d
wait();
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
Log.e("ExoPlayer Exception", ex.toString());
DebugLog.e("ExoPlayer Exception", ex.toString());
}
}

Expand Down Expand Up @@ -1905,7 +1905,7 @@ public void setBackBufferDurationMs(int backBufferDurationMs) {
long reserveMemory = (long)minBackBufferMemoryReservePercent * runtime.maxMemory();
if (reserveMemory > freeMemory) {
// We don't have enough memory in reserve so we will
Log.w("ExoPlayer Warning", "Not enough reserve memory, setting back buffer to 0ms to reduce memory pressure!");
DebugLog.w("ExoPlayer Warning", "Not enough reserve memory, setting back buffer to 0ms to reduce memory pressure!");
this.backBufferDurationMs = 0;
return;
}
Expand Down Expand Up @@ -2027,23 +2027,23 @@ public void setDrmLicenseHeader(String[] header){

@Override
public void onDrmKeysLoaded(int windowIndex, MediaSource.MediaPeriodId mediaPeriodId) {
Log.d("DRM Info", "onDrmKeysLoaded");
DebugLog.d("DRM Info", "onDrmKeysLoaded");
}

@Override
public void onDrmSessionManagerError(int windowIndex, MediaSource.MediaPeriodId mediaPeriodId, Exception e) {
Log.d("DRM Info", "onDrmSessionManagerError");
DebugLog.d("DRM Info", "onDrmSessionManagerError");
eventEmitter.error("onDrmSessionManagerError", e, "3002");
}

@Override
public void onDrmKeysRestored(int windowIndex, MediaSource.MediaPeriodId mediaPeriodId) {
Log.d("DRM Info", "onDrmKeysRestored");
DebugLog.d("DRM Info", "onDrmKeysRestored");
}

@Override
public void onDrmKeysRemoved(int windowIndex, MediaSource.MediaPeriodId mediaPeriodId) {
Log.d("DRM Info", "onDrmKeysRemoved");
DebugLog.d("DRM Info", "onDrmKeysRemoved");
}

/**
Expand Down
Loading

0 comments on commit add8792

Please sign in to comment.