@stream-io/video-react-native-sdk 1.20.11 → 1.20.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,22 @@
2
2
 
3
3
  This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
4
4
 
5
+ ## [1.20.13](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-react-native-sdk-1.20.12...@stream-io/video-react-native-sdk-1.20.13) (2025-09-11)
6
+
7
+ ### Dependency Updates
8
+
9
+ - `@stream-io/video-client` updated to version `1.30.0`
10
+ - `@stream-io/video-react-bindings` updated to version `1.8.1`
11
+
12
+ ## [1.20.12](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-react-native-sdk-1.20.11...@stream-io/video-react-native-sdk-1.20.12) (2025-09-09)
13
+
14
+ ### Dependency Updates
15
+
16
+ - `@stream-io/video-client` updated to version `1.29.0`
17
+ - `@stream-io/video-react-bindings` updated to version `1.8.0`
18
+
19
+ - trace charging and battery level ([#1909](https://github.com/GetStream/stream-video-js/issues/1909)) ([31d7c01](https://github.com/GetStream/stream-video-js/commit/31d7c015a1b243b759b3ef8934e44c5dc521b9a2))
20
+
5
21
  ## [1.20.11](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-react-native-sdk-1.20.10...@stream-io/video-react-native-sdk-1.20.11) (2025-09-05)
6
22
 
7
23
  ### Dependency Updates
@@ -6,18 +6,18 @@ import android.content.Intent
6
6
  import android.content.IntentFilter
7
7
  import android.graphics.Bitmap
8
8
  import android.net.Uri
9
+ import android.os.BatteryManager
9
10
  import android.os.Build
10
11
  import android.os.PowerManager
11
12
  import android.util.Base64
12
- import android.util.Log
13
+ import com.facebook.react.bridge.Arguments
13
14
  import com.facebook.react.bridge.Promise
14
15
  import com.facebook.react.bridge.ReactApplicationContext
15
- import com.facebook.react.bridge.ReactContext
16
16
  import com.facebook.react.bridge.ReactContextBaseJavaModule
17
17
  import com.facebook.react.bridge.ReactMethod
18
+ import com.facebook.react.bridge.WritableMap
18
19
  import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter
19
20
  import com.oney.WebRTCModule.WebRTCModule
20
- import com.oney.WebRTCModule.WebRTCView
21
21
  import com.streamvideo.reactnative.util.CallAlivePermissionsHelper
22
22
  import com.streamvideo.reactnative.util.CallAliveServiceChecker
23
23
  import com.streamvideo.reactnative.util.PiPHelper
@@ -25,7 +25,6 @@ import com.streamvideo.reactnative.util.RingtoneUtil
25
25
  import com.streamvideo.reactnative.util.YuvFrame
26
26
  import kotlinx.coroutines.CoroutineScope
27
27
  import kotlinx.coroutines.Dispatchers
28
- import kotlinx.coroutines.Job
29
28
  import kotlinx.coroutines.launch
30
29
  import org.webrtc.VideoSink
31
30
  import org.webrtc.VideoTrack
@@ -41,6 +40,16 @@ class StreamVideoReactNativeModule(reactContext: ReactApplicationContext) :
41
40
 
42
41
  private var thermalStatusListener: PowerManager.OnThermalStatusChangedListener? = null
43
42
 
43
+ private var batteryChargingStateReceiver = object : BroadcastReceiver() {
44
+ override fun onReceive(context: Context?, intent: Intent?) {
45
+ if (intent == null) return
46
+ val result = getBatteryStatusFromIntent(intent)
47
+ reactApplicationContext
48
+ .getJSModule(RCTDeviceEventEmitter::class.java)
49
+ .emit("chargingStateChanged", result)
50
+ }
51
+ }
52
+
44
53
  override fun initialize() {
45
54
  super.initialize()
46
55
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@@ -48,8 +57,16 @@ class StreamVideoReactNativeModule(reactContext: ReactApplicationContext) :
48
57
  PiPHelper.onPiPChange(reactApplicationContext, isInPictureInPictureMode, newConfig)
49
58
  }
50
59
  }
51
- val filter = IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED)
52
- reactApplicationContext.registerReceiver(powerReceiver, filter)
60
+
61
+ reactApplicationContext.registerReceiver(
62
+ powerReceiver,
63
+ IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED)
64
+ )
65
+
66
+ reactApplicationContext.registerReceiver(batteryChargingStateReceiver, IntentFilter().apply {
67
+ addAction(Intent.ACTION_POWER_CONNECTED)
68
+ addAction(Intent.ACTION_POWER_DISCONNECTED)
69
+ })
53
70
  }
54
71
 
55
72
  @ReactMethod
@@ -104,6 +121,7 @@ class StreamVideoReactNativeModule(reactContext: ReactApplicationContext) :
104
121
  override fun invalidate() {
105
122
  StreamVideoReactNative.clearPipListeners()
106
123
  reactApplicationContext.unregisterReceiver(powerReceiver)
124
+ reactApplicationContext.unregisterReceiver(batteryChargingStateReceiver)
107
125
  stopThermalStatusUpdates()
108
126
  super.invalidate()
109
127
  }
@@ -281,12 +299,44 @@ class StreamVideoReactNativeModule(reactContext: ReactApplicationContext) :
281
299
  }
282
300
  }
283
301
  track.addSink(screenshotSink)
284
- }
285
- catch (e: Exception) {
302
+ } catch (e: Exception) {
286
303
  promise.reject("ERROR", e.message)
287
304
  }
288
305
  }
289
306
 
307
+ @ReactMethod
308
+ fun getBatteryState(promise: Promise) {
309
+ try {
310
+ val filter = IntentFilter(Intent.ACTION_BATTERY_CHANGED)
311
+ val batteryStatus = reactApplicationContext.registerReceiver(null, filter)
312
+ if (batteryStatus == null) {
313
+ return promise.reject("BATTERY_ERROR", "Failed to get battery status")
314
+ }
315
+
316
+ promise.resolve(getBatteryStatusFromIntent(batteryStatus))
317
+ } catch (e: Exception) {
318
+ promise.reject("BATTERY_ERROR", "Failed to get charging state", e)
319
+ }
320
+ }
321
+
322
+ private fun getBatteryStatusFromIntent(intent: Intent): WritableMap {
323
+ val status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1)
324
+ val level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
325
+ val scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
326
+
327
+ val isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
328
+ status == BatteryManager.BATTERY_STATUS_FULL
329
+
330
+ val batteryLevel = if (level >= 0 && scale > 0) {
331
+ (level.toFloat() / scale.toFloat()) * 100
332
+ } else -1f
333
+
334
+ return Arguments.createMap().apply {
335
+ putBoolean("charging", isCharging)
336
+ putInt("level", batteryLevel.toInt())
337
+ }
338
+ }
339
+
290
340
  companion object {
291
341
  private const val NAME = "StreamVideoReactNative"
292
342
  }
@@ -8,8 +8,10 @@ var _videoReactBindings = require("@stream-io/video-react-bindings");
8
8
  var _react = require("react");
9
9
  var _videoClient = require("@stream-io/video-client");
10
10
  var _reactNative = require("react-native");
11
- const eventEmitter = _reactNative.NativeModules?.StreamVideoReactNative ? new _reactNative.NativeEventEmitter(_reactNative.NativeModules?.StreamVideoReactNative) : undefined;
12
-
11
+ const {
12
+ StreamVideoReactNative
13
+ } = _reactNative.NativeModules;
14
+ const eventEmitter = new _reactNative.NativeEventEmitter(StreamVideoReactNative);
13
15
  /**
14
16
  * This is a renderless component to get the device stats like thermal state and power saver mode.
15
17
  */
@@ -21,32 +23,47 @@ const DeviceStats = () => {
21
23
  const call = (0, _videoReactBindings.useCall)();
22
24
  (0, _react.useEffect)(() => {
23
25
  if (!call || callingState !== _videoClient.CallingState.JOINED) return;
24
- _reactNative.NativeModules?.StreamVideoReactNative.isLowPowerModeEnabled().then(initialPowerMode => {
26
+ StreamVideoReactNative.isLowPowerModeEnabled().then(initialPowerMode => {
25
27
  (0, _videoClient.setPowerState)(initialPowerMode);
26
28
  call.tracer.trace('device.lowPowerMode', initialPowerMode);
27
29
  });
28
- const powerModeSubscription = eventEmitter?.addListener('isLowPowerModeEnabled', isLowPowerMode => {
30
+ const powerModeSubscription = eventEmitter.addListener('isLowPowerModeEnabled', isLowPowerMode => {
29
31
  (0, _videoClient.setPowerState)(isLowPowerMode);
30
32
  call.tracer.trace('device.lowPowerMode', isLowPowerMode);
31
33
  });
32
- _reactNative.NativeModules?.StreamVideoReactNative.currentThermalState().then(initialState => {
34
+ StreamVideoReactNative.currentThermalState().then(initialState => {
33
35
  (0, _videoClient.setThermalState)(initialState);
34
36
  call.tracer.trace('device.thermalState', initialState);
35
37
  });
36
- const thermalStateSubscription = eventEmitter?.addListener('thermalStateDidChange', thermalState => {
38
+ const thermalStateSubscription = eventEmitter.addListener('thermalStateDidChange', thermalState => {
37
39
  (0, _videoClient.setThermalState)(thermalState);
38
40
  call.tracer.trace('device.thermalStateChanged', thermalState);
39
41
  });
42
+ const pollBatteryState = () => {
43
+ StreamVideoReactNative.getBatteryState().then(data => {
44
+ call.tracer.trace('device.batteryState', data);
45
+ });
46
+ };
47
+
48
+ // poll every 3 minutes, so we can calculate potential battery drain
49
+ const batteryLevelId = setInterval(() => pollBatteryState(), 3 * 60 * 1000);
50
+ pollBatteryState(); // initial call
51
+
52
+ const batteryChargingSubscription = eventEmitter.addListener('chargingStateChanged', data => {
53
+ call.tracer.trace('device.chargingStateChanged', data);
54
+ });
40
55
 
41
56
  // on android we need to explicitly start and stop the thermal status updates
42
57
  if (_reactNative.Platform.OS === 'android') {
43
- _reactNative.NativeModules?.StreamVideoReactNative.startThermalStatusUpdates();
58
+ StreamVideoReactNative.startThermalStatusUpdates();
44
59
  }
45
60
  return () => {
46
- powerModeSubscription?.remove();
47
- thermalStateSubscription?.remove();
61
+ powerModeSubscription.remove();
62
+ thermalStateSubscription.remove();
63
+ batteryChargingSubscription.remove();
64
+ clearInterval(batteryLevelId);
48
65
  if (_reactNative.Platform.OS === 'android') {
49
- _reactNative.NativeModules?.StreamVideoReactNative.stopThermalStatusUpdates();
66
+ StreamVideoReactNative.stopThermalStatusUpdates();
50
67
  }
51
68
  };
52
69
  }, [call, callingState]);
@@ -1 +1 @@
1
- {"version":3,"names":["_videoReactBindings","require","_react","_videoClient","_reactNative","eventEmitter","NativeModules","StreamVideoReactNative","NativeEventEmitter","undefined","DeviceStats","useCallCallingState","useCallStateHooks","callingState","call","useCall","useEffect","CallingState","JOINED","isLowPowerModeEnabled","then","initialPowerMode","setPowerState","tracer","trace","powerModeSubscription","addListener","isLowPowerMode","currentThermalState","initialState","setThermalState","thermalStateSubscription","thermalState","Platform","OS","startThermalStatusUpdates","remove","stopThermalStatusUpdates","exports"],"sourceRoot":"../../../../src","sources":["providers/StreamCall/DeviceStats.tsx"],"mappings":";;;;;;AAAA,IAAAA,mBAAA,GAAAC,OAAA;AACA,IAAAC,MAAA,GAAAD,OAAA;AACA,IAAAE,YAAA,GAAAF,OAAA;AAKA,IAAAG,YAAA,GAAAH,OAAA;AAEA,MAAMI,YAAY,GAAGC,0BAAa,EAAEC,sBAAsB,GACtD,IAAIC,+BAAkB,CAACF,0BAAa,EAAEC,sBAAsB,CAAC,GAC7DE,SAAS;;AAEb;AACA;AACA;AACO,MAAMC,WAAW,GAAGA,CAAA,KAAM;EAC/B,MAAM;IAAEC;EAAoB,CAAC,GAAG,IAAAC,qCAAiB,EAAC,CAAC;EACnD,MAAMC,YAAY,GAAGF,mBAAmB,CAAC,CAAC;EAC1C,MAAMG,IAAI,GAAG,IAAAC,2BAAO,EAAC,CAAC;EAEtB,IAAAC,gBAAS,EAAC,MAAM;IACd,IAAI,CAACF,IAAI,IAAID,YAAY,KAAKI,yBAAY,CAACC,MAAM,EAAE;IAEnDZ,0BAAa,EAAEC,sBAAsB,CAACY,qBAAqB,CAAC,CAAC,CAACC,IAAI,CAC/DC,gBAAyB,IAAK;MAC7B,IAAAC,0BAAa,EAACD,gBAAgB,CAAC;MAC/BP,IAAI,CAACS,MAAM,CAACC,KAAK,CAAC,qBAAqB,EAAEH,gBAAgB,CAAC;IAC5D,CACF,CAAC;IAED,MAAMI,qBAAqB,GAAGpB,YAAY,EAAEqB,WAAW,CACrD,uBAAuB,EACtBC,cAAuB,IAAK;MAC3B,IAAAL,0BAAa,EAACK,cAAc,CAAC;MAC7Bb,IAAI,CAACS,MAAM,CAACC,KAAK,CAAC,qBAAqB,EAAEG,cAAc,CAAC;IAC1D,CACF,CAAC;IAEDrB,0BAAa,EAAEC,sBAAsB,CAACqB,mBAAmB,CAAC,CAAC,CAACR,IAAI,CAC7DS,YAAoB,IAAK;MACxB,IAAAC,4BAAe,EAACD,YAAY,CAAC;MAC7Bf,IAAI,CAACS,MAAM,CAACC,KAAK,CAAC,qBAAqB,EAAEK,YAAY,CAAC;IACxD,CACF,CAAC;IAED,MAAME,wBAAwB,GAAG1B,YAAY,EAAEqB,WAAW,CACxD,uBAAuB,EACtBM,YAAoB,IAAK;MACxB,IAAAF,4BAAe,EAACE,YAAY,CAAC;MAC7BlB,IAAI,CAACS,MAAM,CAACC,KAAK,CAAC,4BAA4B,EAAEQ,YAAY,CAAC;IAC/D,CACF,CAAC;;IAED;IACA,IAAIC,qBAAQ,CAACC,EAAE,KAAK,SAAS,EAAE;MAC7B5B,0BAAa,EAAEC,sBAAsB,CAAC4B,yBAAyB,CAAC,CAAC;IACnE;IAEA,OAAO,MAAM;MACXV,qBAAqB,EAAEW,MAAM,CAAC,CAAC;MAC/BL,wBAAwB,EAAEK,MAAM,CAAC,CAAC;MAClC,IAAIH,qBAAQ,CAACC,EAAE,KAAK,SAAS,EAAE;QAC7B5B,0BAAa,EAAEC,sBAAsB,CAAC8B,wBAAwB,CAAC,CAAC;MAClE;IACF,CAAC;EACH,CAAC,EAAE,CAACvB,IAAI,EAAED,YAAY,CAAC,CAAC;EAExB,OAAO,IAAI;AACb,CAAC;AAACyB,OAAA,CAAA5B,WAAA,GAAAA,WAAA","ignoreList":[]}
1
+ {"version":3,"names":["_videoReactBindings","require","_react","_videoClient","_reactNative","StreamVideoReactNative","NativeModules","eventEmitter","NativeEventEmitter","DeviceStats","useCallCallingState","useCallStateHooks","callingState","call","useCall","useEffect","CallingState","JOINED","isLowPowerModeEnabled","then","initialPowerMode","setPowerState","tracer","trace","powerModeSubscription","addListener","isLowPowerMode","currentThermalState","initialState","setThermalState","thermalStateSubscription","thermalState","pollBatteryState","getBatteryState","data","batteryLevelId","setInterval","batteryChargingSubscription","Platform","OS","startThermalStatusUpdates","remove","clearInterval","stopThermalStatusUpdates","exports"],"sourceRoot":"../../../../src","sources":["providers/StreamCall/DeviceStats.tsx"],"mappings":"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","ignoreList":[]}
@@ -4,5 +4,5 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.version = void 0;
7
- const version = exports.version = '1.20.11';
7
+ const version = exports.version = '1.20.13';
8
8
  //# sourceMappingURL=version.js.map
@@ -2,8 +2,10 @@ import { useCall, useCallStateHooks } from '@stream-io/video-react-bindings';
2
2
  import { useEffect } from 'react';
3
3
  import { CallingState, setPowerState, setThermalState } from '@stream-io/video-client';
4
4
  import { NativeEventEmitter, NativeModules, Platform } from 'react-native';
5
- const eventEmitter = NativeModules?.StreamVideoReactNative ? new NativeEventEmitter(NativeModules?.StreamVideoReactNative) : undefined;
6
-
5
+ const {
6
+ StreamVideoReactNative
7
+ } = NativeModules;
8
+ const eventEmitter = new NativeEventEmitter(StreamVideoReactNative);
7
9
  /**
8
10
  * This is a renderless component to get the device stats like thermal state and power saver mode.
9
11
  */
@@ -15,32 +17,47 @@ export const DeviceStats = () => {
15
17
  const call = useCall();
16
18
  useEffect(() => {
17
19
  if (!call || callingState !== CallingState.JOINED) return;
18
- NativeModules?.StreamVideoReactNative.isLowPowerModeEnabled().then(initialPowerMode => {
20
+ StreamVideoReactNative.isLowPowerModeEnabled().then(initialPowerMode => {
19
21
  setPowerState(initialPowerMode);
20
22
  call.tracer.trace('device.lowPowerMode', initialPowerMode);
21
23
  });
22
- const powerModeSubscription = eventEmitter?.addListener('isLowPowerModeEnabled', isLowPowerMode => {
24
+ const powerModeSubscription = eventEmitter.addListener('isLowPowerModeEnabled', isLowPowerMode => {
23
25
  setPowerState(isLowPowerMode);
24
26
  call.tracer.trace('device.lowPowerMode', isLowPowerMode);
25
27
  });
26
- NativeModules?.StreamVideoReactNative.currentThermalState().then(initialState => {
28
+ StreamVideoReactNative.currentThermalState().then(initialState => {
27
29
  setThermalState(initialState);
28
30
  call.tracer.trace('device.thermalState', initialState);
29
31
  });
30
- const thermalStateSubscription = eventEmitter?.addListener('thermalStateDidChange', thermalState => {
32
+ const thermalStateSubscription = eventEmitter.addListener('thermalStateDidChange', thermalState => {
31
33
  setThermalState(thermalState);
32
34
  call.tracer.trace('device.thermalStateChanged', thermalState);
33
35
  });
36
+ const pollBatteryState = () => {
37
+ StreamVideoReactNative.getBatteryState().then(data => {
38
+ call.tracer.trace('device.batteryState', data);
39
+ });
40
+ };
41
+
42
+ // poll every 3 minutes, so we can calculate potential battery drain
43
+ const batteryLevelId = setInterval(() => pollBatteryState(), 3 * 60 * 1000);
44
+ pollBatteryState(); // initial call
45
+
46
+ const batteryChargingSubscription = eventEmitter.addListener('chargingStateChanged', data => {
47
+ call.tracer.trace('device.chargingStateChanged', data);
48
+ });
34
49
 
35
50
  // on android we need to explicitly start and stop the thermal status updates
36
51
  if (Platform.OS === 'android') {
37
- NativeModules?.StreamVideoReactNative.startThermalStatusUpdates();
52
+ StreamVideoReactNative.startThermalStatusUpdates();
38
53
  }
39
54
  return () => {
40
- powerModeSubscription?.remove();
41
- thermalStateSubscription?.remove();
55
+ powerModeSubscription.remove();
56
+ thermalStateSubscription.remove();
57
+ batteryChargingSubscription.remove();
58
+ clearInterval(batteryLevelId);
42
59
  if (Platform.OS === 'android') {
43
- NativeModules?.StreamVideoReactNative.stopThermalStatusUpdates();
60
+ StreamVideoReactNative.stopThermalStatusUpdates();
44
61
  }
45
62
  };
46
63
  }, [call, callingState]);
@@ -1 +1 @@
1
- {"version":3,"names":["useCall","useCallStateHooks","useEffect","CallingState","setPowerState","setThermalState","NativeEventEmitter","NativeModules","Platform","eventEmitter","StreamVideoReactNative","undefined","DeviceStats","useCallCallingState","callingState","call","JOINED","isLowPowerModeEnabled","then","initialPowerMode","tracer","trace","powerModeSubscription","addListener","isLowPowerMode","currentThermalState","initialState","thermalStateSubscription","thermalState","OS","startThermalStatusUpdates","remove","stopThermalStatusUpdates"],"sourceRoot":"../../../../src","sources":["providers/StreamCall/DeviceStats.tsx"],"mappings":"AAAA,SAASA,OAAO,EAAEC,iBAAiB,QAAQ,iCAAiC;AAC5E,SAASC,SAAS,QAAQ,OAAO;AACjC,SACEC,YAAY,EACZC,aAAa,EACbC,eAAe,QACV,yBAAyB;AAChC,SAASC,kBAAkB,EAAEC,aAAa,EAAEC,QAAQ,QAAQ,cAAc;AAE1E,MAAMC,YAAY,GAAGF,aAAa,EAAEG,sBAAsB,GACtD,IAAIJ,kBAAkB,CAACC,aAAa,EAAEG,sBAAsB,CAAC,GAC7DC,SAAS;;AAEb;AACA;AACA;AACA,OAAO,MAAMC,WAAW,GAAGA,CAAA,KAAM;EAC/B,MAAM;IAAEC;EAAoB,CAAC,GAAGZ,iBAAiB,CAAC,CAAC;EACnD,MAAMa,YAAY,GAAGD,mBAAmB,CAAC,CAAC;EAC1C,MAAME,IAAI,GAAGf,OAAO,CAAC,CAAC;EAEtBE,SAAS,CAAC,MAAM;IACd,IAAI,CAACa,IAAI,IAAID,YAAY,KAAKX,YAAY,CAACa,MAAM,EAAE;IAEnDT,aAAa,EAAEG,sBAAsB,CAACO,qBAAqB,CAAC,CAAC,CAACC,IAAI,CAC/DC,gBAAyB,IAAK;MAC7Bf,aAAa,CAACe,gBAAgB,CAAC;MAC/BJ,IAAI,CAACK,MAAM,CAACC,KAAK,CAAC,qBAAqB,EAAEF,gBAAgB,CAAC;IAC5D,CACF,CAAC;IAED,MAAMG,qBAAqB,GAAGb,YAAY,EAAEc,WAAW,CACrD,uBAAuB,EACtBC,cAAuB,IAAK;MAC3BpB,aAAa,CAACoB,cAAc,CAAC;MAC7BT,IAAI,CAACK,MAAM,CAACC,KAAK,CAAC,qBAAqB,EAAEG,cAAc,CAAC;IAC1D,CACF,CAAC;IAEDjB,aAAa,EAAEG,sBAAsB,CAACe,mBAAmB,CAAC,CAAC,CAACP,IAAI,CAC7DQ,YAAoB,IAAK;MACxBrB,eAAe,CAACqB,YAAY,CAAC;MAC7BX,IAAI,CAACK,MAAM,CAACC,KAAK,CAAC,qBAAqB,EAAEK,YAAY,CAAC;IACxD,CACF,CAAC;IAED,MAAMC,wBAAwB,GAAGlB,YAAY,EAAEc,WAAW,CACxD,uBAAuB,EACtBK,YAAoB,IAAK;MACxBvB,eAAe,CAACuB,YAAY,CAAC;MAC7Bb,IAAI,CAACK,MAAM,CAACC,KAAK,CAAC,4BAA4B,EAAEO,YAAY,CAAC;IAC/D,CACF,CAAC;;IAED;IACA,IAAIpB,QAAQ,CAACqB,EAAE,KAAK,SAAS,EAAE;MAC7BtB,aAAa,EAAEG,sBAAsB,CAACoB,yBAAyB,CAAC,CAAC;IACnE;IAEA,OAAO,MAAM;MACXR,qBAAqB,EAAES,MAAM,CAAC,CAAC;MAC/BJ,wBAAwB,EAAEI,MAAM,CAAC,CAAC;MAClC,IAAIvB,QAAQ,CAACqB,EAAE,KAAK,SAAS,EAAE;QAC7BtB,aAAa,EAAEG,sBAAsB,CAACsB,wBAAwB,CAAC,CAAC;MAClE;IACF,CAAC;EACH,CAAC,EAAE,CAACjB,IAAI,EAAED,YAAY,CAAC,CAAC;EAExB,OAAO,IAAI;AACb,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["useCall","useCallStateHooks","useEffect","CallingState","setPowerState","setThermalState","NativeEventEmitter","NativeModules","Platform","StreamVideoReactNative","eventEmitter","DeviceStats","useCallCallingState","callingState","call","JOINED","isLowPowerModeEnabled","then","initialPowerMode","tracer","trace","powerModeSubscription","addListener","isLowPowerMode","currentThermalState","initialState","thermalStateSubscription","thermalState","pollBatteryState","getBatteryState","data","batteryLevelId","setInterval","batteryChargingSubscription","OS","startThermalStatusUpdates","remove","clearInterval","stopThermalStatusUpdates"],"sourceRoot":"../../../../src","sources":["providers/StreamCall/DeviceStats.tsx"],"mappings":"AAAA,SAASA,OAAO,EAAEC,iBAAiB,QAAQ,iCAAiC;AAC5E,SAASC,SAAS,QAAQ,OAAO;AACjC,SACEC,YAAY,EACZC,aAAa,EACbC,eAAe,QACV,yBAAyB;AAChC,SAASC,kBAAkB,EAAEC,aAAa,EAAEC,QAAQ,QAAQ,cAAc;AAE1E,MAAM;EAAEC;AAAuB,CAAC,GAAGF,aAAa;AAChD,MAAMG,YAAY,GAAG,IAAIJ,kBAAkB,CAACG,sBAAsB,CAAC;AACnE;AACA;AACA;AACA,OAAO,MAAME,WAAW,GAAGA,CAAA,KAAM;EAC/B,MAAM;IAAEC;EAAoB,CAAC,GAAGX,iBAAiB,CAAC,CAAC;EACnD,MAAMY,YAAY,GAAGD,mBAAmB,CAAC,CAAC;EAC1C,MAAME,IAAI,GAAGd,OAAO,CAAC,CAAC;EAEtBE,SAAS,CAAC,MAAM;IACd,IAAI,CAACY,IAAI,IAAID,YAAY,KAAKV,YAAY,CAACY,MAAM,EAAE;IAEnDN,sBAAsB,CAACO,qBAAqB,CAAC,CAAC,CAACC,IAAI,CAChDC,gBAAyB,IAAK;MAC7Bd,aAAa,CAACc,gBAAgB,CAAC;MAC/BJ,IAAI,CAACK,MAAM,CAACC,KAAK,CAAC,qBAAqB,EAAEF,gBAAgB,CAAC;IAC5D,CACF,CAAC;IAED,MAAMG,qBAAqB,GAAGX,YAAY,CAACY,WAAW,CACpD,uBAAuB,EACtBC,cAAuB,IAAK;MAC3BnB,aAAa,CAACmB,cAAc,CAAC;MAC7BT,IAAI,CAACK,MAAM,CAACC,KAAK,CAAC,qBAAqB,EAAEG,cAAc,CAAC;IAC1D,CACF,CAAC;IAEDd,sBAAsB,CAACe,mBAAmB,CAAC,CAAC,CAACP,IAAI,CAC9CQ,YAAoB,IAAK;MACxBpB,eAAe,CAACoB,YAAY,CAAC;MAC7BX,IAAI,CAACK,MAAM,CAACC,KAAK,CAAC,qBAAqB,EAAEK,YAAY,CAAC;IACxD,CACF,CAAC;IAED,MAAMC,wBAAwB,GAAGhB,YAAY,CAACY,WAAW,CACvD,uBAAuB,EACtBK,YAAoB,IAAK;MACxBtB,eAAe,CAACsB,YAAY,CAAC;MAC7Bb,IAAI,CAACK,MAAM,CAACC,KAAK,CAAC,4BAA4B,EAAEO,YAAY,CAAC;IAC/D,CACF,CAAC;IAED,MAAMC,gBAAgB,GAAGA,CAAA,KAAM;MAC7BnB,sBAAsB,CAACoB,eAAe,CAAC,CAAC,CAACZ,IAAI,CAC1Ca,IAA0C,IAAK;QAC9ChB,IAAI,CAACK,MAAM,CAACC,KAAK,CAAC,qBAAqB,EAAEU,IAAI,CAAC;MAChD,CACF,CAAC;IACH,CAAC;;IAED;IACA,MAAMC,cAAc,GAAGC,WAAW,CAAC,MAAMJ,gBAAgB,CAAC,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;IAC3EA,gBAAgB,CAAC,CAAC,CAAC,CAAC;;IAEpB,MAAMK,2BAA2B,GAAGvB,YAAY,CAACY,WAAW,CAC1D,sBAAsB,EACrBQ,IAA0C,IAAK;MAC9ChB,IAAI,CAACK,MAAM,CAACC,KAAK,CAAC,6BAA6B,EAAEU,IAAI,CAAC;IACxD,CACF,CAAC;;IAED;IACA,IAAItB,QAAQ,CAAC0B,EAAE,KAAK,SAAS,EAAE;MAC7BzB,sBAAsB,CAAC0B,yBAAyB,CAAC,CAAC;IACpD;IAEA,OAAO,MAAM;MACXd,qBAAqB,CAACe,MAAM,CAAC,CAAC;MAC9BV,wBAAwB,CAACU,MAAM,CAAC,CAAC;MACjCH,2BAA2B,CAACG,MAAM,CAAC,CAAC;MACpCC,aAAa,CAACN,cAAc,CAAC;MAC7B,IAAIvB,QAAQ,CAAC0B,EAAE,KAAK,SAAS,EAAE;QAC7BzB,sBAAsB,CAAC6B,wBAAwB,CAAC,CAAC;MACnD;IACF,CAAC;EACH,CAAC,EAAE,CAACxB,IAAI,EAAED,YAAY,CAAC,CAAC;EAExB,OAAO,IAAI;AACb,CAAC","ignoreList":[]}
@@ -1,2 +1,2 @@
1
- export const version = '1.20.11';
1
+ export const version = '1.20.13';
2
2
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"DeviceStats.d.ts","sourceRoot":"","sources":["../../../../src/providers/StreamCall/DeviceStats.tsx"],"names":[],"mappings":"AAaA;;GAEG;AACH,eAAO,MAAM,WAAW,YAqDvB,CAAC"}
1
+ {"version":3,"file":"DeviceStats.d.ts","sourceRoot":"","sources":["../../../../src/providers/StreamCall/DeviceStats.tsx"],"names":[],"mappings":"AAWA;;GAEG;AACH,eAAO,MAAM,WAAW,YA0EvB,CAAC"}
@@ -1,2 +1,2 @@
1
- export declare const version = "1.20.11";
1
+ export declare const version = "1.20.13";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -1,6 +1,6 @@
1
1
  #import <React/RCTBridgeModule.h>
2
2
  #import <React/RCTEventEmitter.h>
3
- #import <React/RCTUIManager.h>
3
+ #import <React/RCTUIManager.h>
4
4
  #import <UIKit/UIKit.h>
5
5
  #import "StreamVideoReactNative.h"
6
6
  #import "WebRTCModule.h"
@@ -118,6 +118,10 @@ RCT_EXPORT_METHOD(currentThermalState:(RCTPromiseResolveBlock)resolve rejecter:(
118
118
  selector:@selector(thermalStateDidChange)
119
119
  name:NSProcessInfoThermalStateDidChangeNotification
120
120
  object:nil];
121
+ [[NSNotificationCenter defaultCenter] addObserver:self
122
+ selector:@selector(batteryStateDidChange:)
123
+ name:UIDeviceBatteryStateDidChangeNotification
124
+ object:nil];
121
125
  }
122
126
 
123
127
  -(void)stopObserving {
@@ -128,6 +132,9 @@ RCT_EXPORT_METHOD(currentThermalState:(RCTPromiseResolveBlock)resolve rejecter:(
128
132
  [[NSNotificationCenter defaultCenter] removeObserver:self
129
133
  name:NSProcessInfoThermalStateDidChangeNotification
130
134
  object:nil];
135
+ [[NSNotificationCenter defaultCenter] removeObserver:self
136
+ name:UIDeviceBatteryStateDidChangeNotification
137
+ object:nil];
131
138
  }
132
139
 
133
140
  - (void)powerModeDidChange {
@@ -171,7 +178,7 @@ RCT_EXPORT_METHOD(currentThermalState:(RCTPromiseResolveBlock)resolve rejecter:(
171
178
  +(void)registerIncomingCall:(NSString *)cid uuid:(NSString *)uuid {
172
179
  [StreamVideoReactNative initializeSharedDictionaries];
173
180
  dispatch_sync(_dictionaryQueue, ^{
174
-
181
+
175
182
  #ifdef DEBUG
176
183
  NSLog(@"registerIncomingCall cid:%@ -> uuid:%@",cid,uuid);
177
184
  #endif
@@ -203,7 +210,7 @@ RCT_EXPORT_METHOD(getIncomingCallCid:(NSString *)uuid
203
210
  dispatch_sync(_dictionaryQueue, ^{
204
211
  NSString *lowercaseUUID = [uuid lowercaseString];
205
212
  NSString *foundCid = _incomingCallCidsByUUID[lowercaseUUID];
206
-
213
+
207
214
  if (foundCid) {
208
215
  resolve(foundCid);
209
216
  } else {
@@ -223,7 +230,7 @@ RCT_EXPORT_METHOD(removeIncomingCall:(NSString *)cid
223
230
  #ifdef DEBUG
224
231
  NSLog(@"removeIncomingCall cid:%@ -> uuid:%@",cid,uuid);
225
232
  #endif
226
-
233
+
227
234
  [_incomingCallUUIDsByCallID removeObjectForKey:cid];
228
235
  [_incomingCallCidsByUUID removeObjectForKey:uuid];
229
236
  resolve(@YES);
@@ -241,7 +248,7 @@ RCT_EXPORT_METHOD(captureRef:(nonnull NSNumber *)reactTag
241
248
  #ifdef RCT_NEW_ARCH_ENABLED
242
249
  [self.viewRegistry_DEPRECATED addUIBlock:^(RCTViewRegistry *viewRegistry) {
243
250
  UIView *view = [self.viewRegistry_DEPRECATED viewForReactTag:reactTag];
244
-
251
+
245
252
  #else
246
253
  [self.bridge.uiManager
247
254
  addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
@@ -252,13 +259,13 @@ RCT_EXPORT_METHOD(captureRef:(nonnull NSNumber *)reactTag
252
259
  reject(RCTErrorUnspecified, [NSString stringWithFormat:@"No view found with reactTag: %@", reactTag], nil);
253
260
  return;
254
261
  }
255
-
262
+
256
263
  // Get capture options
257
264
  NSString *format = options[@"format"] ? [options[@"format"] lowercaseString] : @"png";
258
265
  CGFloat quality = options[@"quality"] ? [options[@"quality"] floatValue] : 1.0;
259
266
  NSNumber *width = options[@"width"];
260
267
  NSNumber *height = options[@"height"];
261
-
268
+
262
269
  // Determine the size to render
263
270
  CGSize size;
264
271
  CGRect bounds = view.bounds;
@@ -267,22 +274,22 @@ RCT_EXPORT_METHOD(captureRef:(nonnull NSNumber *)reactTag
267
274
  } else {
268
275
  size = bounds.size;
269
276
  }
270
-
277
+
271
278
  // Abort if size is invalid
272
279
  if (size.width <= 0 || size.height <= 0) {
273
280
  reject(@"INVALID_SIZE", @"View has invalid size", nil);
274
281
  return;
275
282
  }
276
-
283
+
277
284
  // Begin image context with appropriate scale
278
285
  UIGraphicsBeginImageContextWithOptions(size, NO, 0);
279
-
286
+
280
287
  // Calculate scaling if needed
281
288
  CGRect drawRect = bounds;
282
289
  if (width && height) {
283
290
  CGFloat scaleX = size.width / bounds.size.width;
284
291
  CGFloat scaleY = size.height / bounds.size.height;
285
-
292
+
286
293
  // Apply transform to context for scaling if dimensions differ
287
294
  CGContextRef context = UIGraphicsGetCurrentContext();
288
295
  if (context) {
@@ -291,17 +298,17 @@ RCT_EXPORT_METHOD(captureRef:(nonnull NSNumber *)reactTag
291
298
  drawRect = CGRectMake(0, 0, bounds.size.width, bounds.size.height);
292
299
  }
293
300
  }
294
-
301
+
295
302
  BOOL success = [view drawViewHierarchyInRect:drawRect afterScreenUpdates:YES];
296
-
303
+
297
304
  UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
298
305
  UIGraphicsEndImageContext();
299
-
306
+
300
307
  if (!success || !image) {
301
308
  reject(@"CAPTURE_FAILED", @"Failed to capture view as image", nil);
302
309
  return;
303
310
  }
304
-
311
+
305
312
  // Convert to base64 string based on format
306
313
  NSString *base64;
307
314
  if ([format isEqualToString:@"jpg"] || [format isEqualToString:@"jpeg"]) {
@@ -312,7 +319,7 @@ RCT_EXPORT_METHOD(captureRef:(nonnull NSNumber *)reactTag
312
319
  NSData *imageData = UIImagePNGRepresentation(image);
313
320
  base64 = [imageData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithCarriageReturn];
314
321
  }
315
-
322
+
316
323
  if (base64) {
317
324
  resolve(base64);
318
325
  } else {
@@ -321,8 +328,36 @@ RCT_EXPORT_METHOD(captureRef:(nonnull NSNumber *)reactTag
321
328
  }];
322
329
  }
323
330
 
331
+ RCT_EXPORT_METHOD(getBatteryState:(RCTPromiseResolveBlock)resolve
332
+ rejecter:(RCTPromiseRejectBlock)reject) {
333
+ UIDeviceBatteryState batteryState = [UIDevice currentDevice].batteryState;
334
+ BOOL isCharging = (batteryState == UIDeviceBatteryStateCharging ||
335
+ batteryState == UIDeviceBatteryStateFull);
336
+
337
+ resolve(@{
338
+ @"charging": @(isCharging),
339
+ @"level": @(round([UIDevice currentDevice].batteryLevel * 100))
340
+ });
341
+ }
342
+
343
+ -(void)batteryStateDidChange:(NSNotification *)notification {
344
+ UIDeviceBatteryState batteryState = [UIDevice currentDevice].batteryState;
345
+ BOOL isCharging = (batteryState == UIDeviceBatteryStateCharging ||
346
+ batteryState == UIDeviceBatteryStateFull);
347
+
348
+ [self sendEventWithName:@"chargingStateChanged" body:@{
349
+ @"charging": @(isCharging),
350
+ @"level": @(round([UIDevice currentDevice].batteryLevel * 100))
351
+ }];
352
+ }
353
+
324
354
  -(NSArray<NSString *> *)supportedEvents {
325
- return @[@"StreamVideoReactNative_Ios_Screenshare_Event", @"isLowPowerModeEnabled", @"thermalStateDidChange"];
355
+ return @[
356
+ @"StreamVideoReactNative_Ios_Screenshare_Event",
357
+ @"isLowPowerModeEnabled",
358
+ @"thermalStateDidChange",
359
+ @"chargingStateChanged"
360
+ ];
326
361
  }
327
362
 
328
363
  @end
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stream-io/video-react-native-sdk",
3
- "version": "1.20.11",
3
+ "version": "1.20.13",
4
4
  "description": "Stream Video SDK for React Native",
5
5
  "author": "https://getstream.io",
6
6
  "homepage": "https://getstream.io/video/docs/react-native/",
@@ -45,8 +45,8 @@
45
45
  "!**/.*"
46
46
  ],
47
47
  "dependencies": {
48
- "@stream-io/video-client": "1.28.1",
49
- "@stream-io/video-react-bindings": "1.7.16",
48
+ "@stream-io/video-client": "1.30.0",
49
+ "@stream-io/video-react-bindings": "1.8.1",
50
50
  "intl-pluralrules": "2.0.1",
51
51
  "lodash.merge": "^4.6.2",
52
52
  "react-native-url-polyfill": "1.3.0",
@@ -7,10 +7,8 @@ import {
7
7
  } from '@stream-io/video-client';
8
8
  import { NativeEventEmitter, NativeModules, Platform } from 'react-native';
9
9
 
10
- const eventEmitter = NativeModules?.StreamVideoReactNative
11
- ? new NativeEventEmitter(NativeModules?.StreamVideoReactNative)
12
- : undefined;
13
-
10
+ const { StreamVideoReactNative } = NativeModules;
11
+ const eventEmitter = new NativeEventEmitter(StreamVideoReactNative);
14
12
  /**
15
13
  * This is a renderless component to get the device stats like thermal state and power saver mode.
16
14
  */
@@ -22,14 +20,14 @@ export const DeviceStats = () => {
22
20
  useEffect(() => {
23
21
  if (!call || callingState !== CallingState.JOINED) return;
24
22
 
25
- NativeModules?.StreamVideoReactNative.isLowPowerModeEnabled().then(
23
+ StreamVideoReactNative.isLowPowerModeEnabled().then(
26
24
  (initialPowerMode: boolean) => {
27
25
  setPowerState(initialPowerMode);
28
26
  call.tracer.trace('device.lowPowerMode', initialPowerMode);
29
27
  },
30
28
  );
31
29
 
32
- const powerModeSubscription = eventEmitter?.addListener(
30
+ const powerModeSubscription = eventEmitter.addListener(
33
31
  'isLowPowerModeEnabled',
34
32
  (isLowPowerMode: boolean) => {
35
33
  setPowerState(isLowPowerMode);
@@ -37,14 +35,14 @@ export const DeviceStats = () => {
37
35
  },
38
36
  );
39
37
 
40
- NativeModules?.StreamVideoReactNative.currentThermalState().then(
38
+ StreamVideoReactNative.currentThermalState().then(
41
39
  (initialState: string) => {
42
40
  setThermalState(initialState);
43
41
  call.tracer.trace('device.thermalState', initialState);
44
42
  },
45
43
  );
46
44
 
47
- const thermalStateSubscription = eventEmitter?.addListener(
45
+ const thermalStateSubscription = eventEmitter.addListener(
48
46
  'thermalStateDidChange',
49
47
  (thermalState: string) => {
50
48
  setThermalState(thermalState);
@@ -52,16 +50,37 @@ export const DeviceStats = () => {
52
50
  },
53
51
  );
54
52
 
53
+ const pollBatteryState = () => {
54
+ StreamVideoReactNative.getBatteryState().then(
55
+ (data: { charging: boolean; level: number }) => {
56
+ call.tracer.trace('device.batteryState', data);
57
+ },
58
+ );
59
+ };
60
+
61
+ // poll every 3 minutes, so we can calculate potential battery drain
62
+ const batteryLevelId = setInterval(() => pollBatteryState(), 3 * 60 * 1000);
63
+ pollBatteryState(); // initial call
64
+
65
+ const batteryChargingSubscription = eventEmitter.addListener(
66
+ 'chargingStateChanged',
67
+ (data: { charging: boolean; level: number }) => {
68
+ call.tracer.trace('device.chargingStateChanged', data);
69
+ },
70
+ );
71
+
55
72
  // on android we need to explicitly start and stop the thermal status updates
56
73
  if (Platform.OS === 'android') {
57
- NativeModules?.StreamVideoReactNative.startThermalStatusUpdates();
74
+ StreamVideoReactNative.startThermalStatusUpdates();
58
75
  }
59
76
 
60
77
  return () => {
61
- powerModeSubscription?.remove();
62
- thermalStateSubscription?.remove();
78
+ powerModeSubscription.remove();
79
+ thermalStateSubscription.remove();
80
+ batteryChargingSubscription.remove();
81
+ clearInterval(batteryLevelId);
63
82
  if (Platform.OS === 'android') {
64
- NativeModules?.StreamVideoReactNative.stopThermalStatusUpdates();
83
+ StreamVideoReactNative.stopThermalStatusUpdates();
65
84
  }
66
85
  };
67
86
  }, [call, callingState]);
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const version = '1.20.11';
1
+ export const version = '1.20.13';