From 6274cac2ecf155aa6ce0c6d764229e0e9cd39a6a Mon Sep 17 00:00:00 2001 From: Matvei Andrienko Date: Mon, 28 Oct 2024 15:31:31 +0100 Subject: [PATCH 01/19] fix: make device selection by device id exact (#1538) Somewhere around Chrome v126 a new behavior was introduced, and the `deviceId: string` constraint when querying `getUserMedia` was no longer respected. The default device was always returned instead. Using the `deviceId: { exact: string }` constraint seems to solve the issue. However, it also can cause the `OvercontrainedError` exception when device id is not valid. We handle it by falling back to default device in this case. --- .../src/devices/InputMediaDeviceManager.ts | 16 +++++-- .../devices/__tests__/CameraManager.test.ts | 4 +- .../__tests__/InputMediaDeviceManager.test.ts | 2 +- packages/client/src/devices/devices.ts | 44 ++++++++++++++----- 4 files changed, 47 insertions(+), 19 deletions(-) diff --git a/packages/client/src/devices/InputMediaDeviceManager.ts b/packages/client/src/devices/InputMediaDeviceManager.ts index 0b13138165..a5cda2df78 100644 --- a/packages/client/src/devices/InputMediaDeviceManager.ts +++ b/packages/client/src/devices/InputMediaDeviceManager.ts @@ -206,11 +206,17 @@ export abstract class InputMediaDeviceManager< 'This method is not supported in React Native. Please visit https://getstream.io/video/docs/reactnative/core/camera-and-microphone/#speaker-management for reference.', ); } - if (deviceId === this.state.selectedDevice) { + const prevDeviceId = this.state.selectedDevice; + if (deviceId === prevDeviceId) { return; } - this.state.setDevice(deviceId); - await this.applySettingsToStream(); + try { + this.state.setDevice(deviceId); + await this.applySettingsToStream(); + } catch (error) { + this.state.setDevice(prevDeviceId); + throw error; + } } /** @@ -308,7 +314,9 @@ export abstract class InputMediaDeviceManager< const defaultConstraints = this.state.defaultConstraints; const constraints: MediaTrackConstraints = { ...defaultConstraints, - deviceId: this.state.selectedDevice, + deviceId: this.state.selectedDevice + ? { exact: this.state.selectedDevice } + : undefined, }; /** diff --git a/packages/client/src/devices/__tests__/CameraManager.test.ts b/packages/client/src/devices/__tests__/CameraManager.test.ts index df7d74b171..e432ba6305 100644 --- a/packages/client/src/devices/__tests__/CameraManager.test.ts +++ b/packages/client/src/devices/__tests__/CameraManager.test.ts @@ -157,7 +157,7 @@ describe('CameraManager', () => { await manager.select(deviceId); expect((getVideoStream as Mock).mock.lastCall[0]).toEqual({ - deviceId, + deviceId: { exact: deviceId }, width: 1280, height: 720, }); @@ -182,7 +182,7 @@ describe('CameraManager', () => { await manager.selectTargetResolution({ width: 640, height: 480 }); expect((getVideoStream as Mock).mock.lastCall[0]).toEqual({ - deviceId: mockVideoDevices[0].deviceId, + deviceId: { exact: mockVideoDevices[0].deviceId }, width: 640, height: 480, }); diff --git a/packages/client/src/devices/__tests__/InputMediaDeviceManager.test.ts b/packages/client/src/devices/__tests__/InputMediaDeviceManager.test.ts index ae3b4743a7..545bb1902e 100644 --- a/packages/client/src/devices/__tests__/InputMediaDeviceManager.test.ts +++ b/packages/client/src/devices/__tests__/InputMediaDeviceManager.test.ts @@ -181,7 +181,7 @@ describe('InputMediaDeviceManager.test', () => { expect(manager.stopPublishStream).toHaveBeenCalledWith(true); expect(manager.getStream).toHaveBeenCalledWith({ - deviceId, + deviceId: { exact: deviceId }, }); expect(manager.publishStream).toHaveBeenCalled(); }); diff --git a/packages/client/src/devices/devices.ts b/packages/client/src/devices/devices.ts index 684da44b14..107d534ffe 100644 --- a/packages/client/src/devices/devices.ts +++ b/packages/client/src/devices/devices.ts @@ -167,7 +167,7 @@ const getStream = async (constraints: MediaStreamConstraints) => { */ export const getAudioStream = async ( trackConstraints?: MediaTrackConstraints, -) => { +): Promise => { const constraints: MediaStreamConstraints = { audio: { ...audioDeviceConstraints.audio, @@ -180,13 +180,23 @@ export const getAudioStream = async ( throwOnNotAllowed: true, forcePrompt: true, }); - return getStream(constraints); - } catch (e) { + return await getStream(constraints); + } catch (error) { + if (error instanceof OverconstrainedError && trackConstraints?.deviceId) { + const { deviceId, ...relaxedContraints } = trackConstraints; + getLogger(['devices'])( + 'warn', + 'Failed to get audio stream, will try again with relaxed contraints', + { error, constraints, relaxedContraints }, + ); + return getAudioStream(relaxedContraints); + } + getLogger(['devices'])('error', 'Failed to get audio stream', { - error: e, - constraints: constraints, + error, + constraints, }); - throw e; + throw error; } }; @@ -200,7 +210,7 @@ export const getAudioStream = async ( */ export const getVideoStream = async ( trackConstraints?: MediaTrackConstraints, -) => { +): Promise => { const constraints: MediaStreamConstraints = { video: { ...videoDeviceConstraints.video, @@ -212,13 +222,23 @@ export const getVideoStream = async ( throwOnNotAllowed: true, forcePrompt: true, }); - return getStream(constraints); - } catch (e) { + return await getStream(constraints); + } catch (error) { + if (error instanceof OverconstrainedError && trackConstraints?.deviceId) { + const { deviceId, ...relaxedContraints } = trackConstraints; + getLogger(['devices'])( + 'warn', + 'Failed to get video stream, will try again with relaxed contraints', + { error, constraints, relaxedContraints }, + ); + return getVideoStream(relaxedContraints); + } + getLogger(['devices'])('error', 'Failed to get video stream', { - error: e, - constraints: constraints, + error, + constraints, }); - throw e; + throw error; } }; From b0b1e5bdf36b728835b345b80ac23c13cba10d4a Mon Sep 17 00:00:00 2001 From: GitHub Actions Bot <> Date: Mon, 28 Oct 2024 14:35:58 +0000 Subject: [PATCH 02/19] chore(@stream-io/video-client): release version 1.9.3 --- packages/client/CHANGELOG.md | 7 +++++++ packages/client/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/client/CHANGELOG.md b/packages/client/CHANGELOG.md index 604a7eb91e..c512670200 100644 --- a/packages/client/CHANGELOG.md +++ b/packages/client/CHANGELOG.md @@ -2,6 +2,13 @@ This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver). +## [1.9.3](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.9.2...@stream-io/video-client-1.9.3) (2024-10-28) + + +### Bug Fixes + +* make device selection by device id exact ([#1538](https://github.com/GetStream/stream-video-js/issues/1538)) ([6274cac](https://github.com/GetStream/stream-video-js/commit/6274cac2ecf155aa6ce0c6d764229e0e9cd39a6a)) + ## [1.9.2](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.9.1...@stream-io/video-client-1.9.2) (2024-10-21) diff --git a/packages/client/package.json b/packages/client/package.json index fce1e9c3ed..22ddf25a6c 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@stream-io/video-client", - "version": "1.9.2", + "version": "1.9.3", "packageManager": "yarn@3.2.4", "main": "dist/index.cjs.js", "module": "dist/index.es.js", From ccbf12f50fe254fabd835bb7859ef1407063f9c4 Mon Sep 17 00:00:00 2001 From: GitHub Actions Bot <> Date: Mon, 28 Oct 2024 14:36:22 +0000 Subject: [PATCH 03/19] chore(@stream-io/video-react-bindings): release version 1.1.8 --- packages/react-bindings/CHANGELOG.md | 5 +++++ packages/react-bindings/package.json | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/react-bindings/CHANGELOG.md b/packages/react-bindings/CHANGELOG.md index b68e05db69..6c0330230a 100644 --- a/packages/react-bindings/CHANGELOG.md +++ b/packages/react-bindings/CHANGELOG.md @@ -2,6 +2,11 @@ This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver). +## [1.1.8](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-react-bindings-1.1.7...@stream-io/video-react-bindings-1.1.8) (2024-10-28) + +### Dependency Updates + +* `@stream-io/video-client` updated to version `1.9.3` ## [1.1.7](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-react-bindings-1.1.6...@stream-io/video-react-bindings-1.1.7) (2024-10-21) ### Dependency Updates diff --git a/packages/react-bindings/package.json b/packages/react-bindings/package.json index 92385ae772..ea65f2fef2 100644 --- a/packages/react-bindings/package.json +++ b/packages/react-bindings/package.json @@ -1,6 +1,6 @@ { "name": "@stream-io/video-react-bindings", - "version": "1.1.7", + "version": "1.1.8", "packageManager": "yarn@3.2.4", "main": "./dist/index.cjs.js", "module": "./dist/index.es.js", From ba50ee72d83fd96584fbb58135815b9b53e47dea Mon Sep 17 00:00:00 2001 From: GitHub Actions Bot <> Date: Mon, 28 Oct 2024 14:36:31 +0000 Subject: [PATCH 04/19] chore(@stream-io/video-react-sdk): release version 1.7.3 --- packages/react-sdk/CHANGELOG.md | 6 ++++++ packages/react-sdk/package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/react-sdk/CHANGELOG.md b/packages/react-sdk/CHANGELOG.md index 625f2d7722..4ea144b6b3 100644 --- a/packages/react-sdk/CHANGELOG.md +++ b/packages/react-sdk/CHANGELOG.md @@ -2,6 +2,12 @@ This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver). +## [1.7.3](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-react-sdk-1.7.2...@stream-io/video-react-sdk-1.7.3) (2024-10-28) + +### Dependency Updates + +* `@stream-io/video-client` updated to version `1.9.3` +* `@stream-io/video-react-bindings` updated to version `1.1.8` ## [1.7.2](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-react-sdk-1.7.1...@stream-io/video-react-sdk-1.7.2) (2024-10-21) ### Dependency Updates diff --git a/packages/react-sdk/package.json b/packages/react-sdk/package.json index 4517a40599..35a002ed60 100644 --- a/packages/react-sdk/package.json +++ b/packages/react-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@stream-io/video-react-sdk", - "version": "1.7.2", + "version": "1.7.3", "packageManager": "yarn@3.2.4", "main": "./dist/index.cjs.js", "module": "./dist/index.es.js", From 55b7eacff7ce324d692133edb64ad6a761c9c315 Mon Sep 17 00:00:00 2001 From: GitHub Actions Bot <> Date: Mon, 28 Oct 2024 14:36:50 +0000 Subject: [PATCH 05/19] chore(@stream-io/video-react-native-sdk): release version 1.2.5 --- packages/react-native-sdk/CHANGELOG.md | 6 ++++++ packages/react-native-sdk/package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/react-native-sdk/CHANGELOG.md b/packages/react-native-sdk/CHANGELOG.md index d409ae4f75..820371adca 100644 --- a/packages/react-native-sdk/CHANGELOG.md +++ b/packages/react-native-sdk/CHANGELOG.md @@ -2,6 +2,12 @@ This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver). +## [1.2.5](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-react-native-sdk-1.2.4...@stream-io/video-react-native-sdk-1.2.5) (2024-10-28) + +### Dependency Updates + +* `@stream-io/video-client` updated to version `1.9.3` +* `@stream-io/video-react-bindings` updated to version `1.1.8` ## [1.2.4](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-react-native-sdk-1.2.3...@stream-io/video-react-native-sdk-1.2.4) (2024-10-22) diff --git a/packages/react-native-sdk/package.json b/packages/react-native-sdk/package.json index 2305ce0392..260c30f0ea 100644 --- a/packages/react-native-sdk/package.json +++ b/packages/react-native-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@stream-io/video-react-native-sdk", - "version": "1.2.4", + "version": "1.2.5", "packageManager": "yarn@3.2.4", "main": "dist/commonjs/index.js", "module": "dist/module/index.js", From 4efe03b2d9d2731857abbd535ab16b9cfcaa2c88 Mon Sep 17 00:00:00 2001 From: GitHub Actions Bot <> Date: Mon, 28 Oct 2024 14:37:14 +0000 Subject: [PATCH 06/19] chore(@stream-io/video-react-native-dogfood): release version 4.4.5 --- sample-apps/react-native/dogfood/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sample-apps/react-native/dogfood/package.json b/sample-apps/react-native/dogfood/package.json index 8888eed99a..724a92472a 100644 --- a/sample-apps/react-native/dogfood/package.json +++ b/sample-apps/react-native/dogfood/package.json @@ -1,6 +1,6 @@ { "name": "@stream-io/video-react-native-dogfood", - "version": "4.4.4", + "version": "4.4.5", "private": true, "scripts": { "android": "react-native run-android", From 1e24dafe507e846288fae3fa137a3834983a783d Mon Sep 17 00:00:00 2001 From: Zachary Ebenfeld Date: Tue, 29 Oct 2024 05:44:06 -0400 Subject: [PATCH 07/19] docs: changed call[0] to calls[0] in docs (#1540) --- .../docs/reactnative/04-ui-components/call/incoming-call.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-native-sdk/docusaurus/docs/reactnative/04-ui-components/call/incoming-call.mdx b/packages/react-native-sdk/docusaurus/docs/reactnative/04-ui-components/call/incoming-call.mdx index d8941807d2..0bb157e7ad 100644 --- a/packages/react-native-sdk/docusaurus/docs/reactnative/04-ui-components/call/incoming-call.mdx +++ b/packages/react-native-sdk/docusaurus/docs/reactnative/04-ui-components/call/incoming-call.mdx @@ -42,7 +42,7 @@ const Call = () => { const calls = useCalls(); return ( - + ); From f34fe0a0444903099565ae55a9639e39fc19b76c Mon Sep 17 00:00:00 2001 From: Oliver Lazoroski Date: Wed, 30 Oct 2024 13:22:40 +0100 Subject: [PATCH 08/19] feat: report input devices in call stats (#1533) Add input device reporting to the call stats. --------- Co-authored-by: Matvei Andrienko --- packages/client/src/Call.ts | 3 + .../src/coordinator/connection/client.ts | 2 +- .../client/src/gen/video/sfu/models/models.ts | 192 ++++++++++++++++++ .../src/gen/video/sfu/signal_rpc/signal.ts | 48 +++++ packages/client/src/stats/SfuStatsReporter.ts | 88 +++++++- packages/client/src/store/rxUtils.ts | 11 +- .../react-dogfood/components/ActiveCall.tsx | 9 +- .../components/ToggleDualCameraButton.tsx | 18 +- .../components/ToggleDualMicButton.tsx | 18 +- 9 files changed, 363 insertions(+), 26 deletions(-) diff --git a/packages/client/src/Call.ts b/packages/client/src/Call.ts index 770d6ada1a..f1918e29a7 100644 --- a/packages/client/src/Call.ts +++ b/packages/client/src/Call.ts @@ -993,6 +993,9 @@ export class Call { options: statsOptions, subscriber: this.subscriber, publisher: this.publisher, + microphone: this.microphone, + camera: this.camera, + state: this.state, }); this.sfuStatsReporter.start(); } diff --git a/packages/client/src/coordinator/connection/client.ts b/packages/client/src/coordinator/connection/client.ts index 5f72be7fb8..80e909395d 100644 --- a/packages/client/src/coordinator/connection/client.ts +++ b/packages/client/src/coordinator/connection/client.ts @@ -252,7 +252,7 @@ export class StreamClient { ) { this.logger( 'warn', - 'Please do not use connectUser server side. connectUser impacts MAU and concurrent connection usage and thus your bill. If you have a valid use-case, add "allowServerSideConnect: true" to the client options to disable this warning.', + 'Please do not use connectUser server side. Use our @stream-io/node-sdk instead: https://getstream.io/video/docs/api/', ); } diff --git a/packages/client/src/gen/video/sfu/models/models.ts b/packages/client/src/gen/video/sfu/models/models.ts index b555626a74..fb2b9a0045 100644 --- a/packages/client/src/gen/video/sfu/models/models.ts +++ b/packages/client/src/gen/video/sfu/models/models.ts @@ -442,6 +442,51 @@ export interface CallGrants { */ canScreenshare: boolean; } +/** + * @generated from protobuf message stream.video.sfu.models.InputDevices + */ +export interface InputDevices { + /** + * @generated from protobuf field: repeated string available_devices = 1; + */ + availableDevices: string[]; + /** + * @generated from protobuf field: string current_device = 2; + */ + currentDevice: string; + /** + * @generated from protobuf field: bool is_permitted = 3; + */ + isPermitted: boolean; +} +/** + * @generated from protobuf message stream.video.sfu.models.AndroidState + */ +export interface AndroidState { + /** + * @generated from protobuf field: stream.video.sfu.models.AndroidThermalState thermal_state = 1; + */ + thermalState: AndroidThermalState; + /** + * @generated from protobuf field: bool is_power_saver_mode = 2; + */ + isPowerSaverMode: boolean; +} +/** + * @generated from protobuf message stream.video.sfu.models.AppleState + */ +export interface AppleState { + /** + * @generated from protobuf field: stream.video.sfu.models.AppleThermalState thermal_state = 1; + */ + thermalState: AppleThermalState; + /** + * https://developer.apple.com/documentation/foundation/processinfo/1617047-islowpowermodeenabled + * + * @generated from protobuf field: bool is_low_power_mode_enabled = 2; + */ + isLowPowerModeEnabled: boolean; +} /** * @generated from protobuf enum stream.video.sfu.models.PeerType */ @@ -773,6 +818,74 @@ export enum WebsocketReconnectStrategy { */ MIGRATE = 4, } +/** + * AndroidThermalState is reported by the Android API. The full list of values is documented here + * https://developer.android.com/reference/android/os/PowerManager.html#getCurrentThermalStatus() + * + * @generated from protobuf enum stream.video.sfu.models.AndroidThermalState + */ +export enum AndroidThermalState { + /** + * @generated from protobuf enum value: ANDROID_THERMAL_STATE_UNSPECIFIED = 0; + */ + UNSPECIFIED = 0, + /** + * @generated from protobuf enum value: ANDROID_THERMAL_STATE_NONE = 1; + */ + NONE = 1, + /** + * @generated from protobuf enum value: ANDROID_THERMAL_STATE_LIGHT = 2; + */ + LIGHT = 2, + /** + * @generated from protobuf enum value: ANDROID_THERMAL_STATE_MODERATE = 3; + */ + MODERATE = 3, + /** + * @generated from protobuf enum value: ANDROID_THERMAL_STATE_SEVERE = 4; + */ + SEVERE = 4, + /** + * @generated from protobuf enum value: ANDROID_THERMAL_STATE_CRITICAL = 5; + */ + CRITICAL = 5, + /** + * @generated from protobuf enum value: ANDROID_THERMAL_STATE_EMERGENCY = 6; + */ + EMERGENCY = 6, + /** + * @generated from protobuf enum value: ANDROID_THERMAL_STATE_SHUTDOWN = 7; + */ + SHUTDOWN = 7, +} +/** + * AppleThermalState is the thermal state as reported by Apple devices when available or applicable to the platform. + * The full list of states (enum) is available here: https://developer.apple.com/documentation/foundation/processinfo/thermalstate + * + * @generated from protobuf enum stream.video.sfu.models.AppleThermalState + */ +export enum AppleThermalState { + /** + * @generated from protobuf enum value: APPLE_THERMAL_STATE_UNSPECIFIED = 0; + */ + UNSPECIFIED = 0, + /** + * @generated from protobuf enum value: APPLE_THERMAL_STATE_NOMINAL = 1; + */ + NOMINAL = 1, + /** + * @generated from protobuf enum value: APPLE_THERMAL_STATE_FAIR = 2; + */ + FAIR = 2, + /** + * @generated from protobuf enum value: APPLE_THERMAL_STATE_SERIOUS = 3; + */ + SERIOUS = 3, + /** + * @generated from protobuf enum value: APPLE_THERMAL_STATE_CRITICAL = 4; + */ + CRITICAL = 4, +} // @generated message type with reflection information, may provide speed optimized methods class CallState$Type extends MessageType { constructor() { @@ -1211,3 +1324,82 @@ class CallGrants$Type extends MessageType { * @generated MessageType for protobuf message stream.video.sfu.models.CallGrants */ export const CallGrants = new CallGrants$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class InputDevices$Type extends MessageType { + constructor() { + super('stream.video.sfu.models.InputDevices', [ + { + no: 1, + name: 'available_devices', + kind: 'scalar', + repeat: 2 /*RepeatType.UNPACKED*/, + T: 9 /*ScalarType.STRING*/, + }, + { + no: 2, + name: 'current_device', + kind: 'scalar', + T: 9 /*ScalarType.STRING*/, + }, + { no: 3, name: 'is_permitted', kind: 'scalar', T: 8 /*ScalarType.BOOL*/ }, + ]); + } +} +/** + * @generated MessageType for protobuf message stream.video.sfu.models.InputDevices + */ +export const InputDevices = new InputDevices$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class AndroidState$Type extends MessageType { + constructor() { + super('stream.video.sfu.models.AndroidState', [ + { + no: 1, + name: 'thermal_state', + kind: 'enum', + T: () => [ + 'stream.video.sfu.models.AndroidThermalState', + AndroidThermalState, + 'ANDROID_THERMAL_STATE_', + ], + }, + { + no: 2, + name: 'is_power_saver_mode', + kind: 'scalar', + T: 8 /*ScalarType.BOOL*/, + }, + ]); + } +} +/** + * @generated MessageType for protobuf message stream.video.sfu.models.AndroidState + */ +export const AndroidState = new AndroidState$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class AppleState$Type extends MessageType { + constructor() { + super('stream.video.sfu.models.AppleState', [ + { + no: 1, + name: 'thermal_state', + kind: 'enum', + T: () => [ + 'stream.video.sfu.models.AppleThermalState', + AppleThermalState, + 'APPLE_THERMAL_STATE_', + ], + }, + { + no: 2, + name: 'is_low_power_mode_enabled', + kind: 'scalar', + T: 8 /*ScalarType.BOOL*/, + }, + ]); + } +} +/** + * @generated MessageType for protobuf message stream.video.sfu.models.AppleState + */ +export const AppleState = new AppleState$Type(); diff --git a/packages/client/src/gen/video/sfu/signal_rpc/signal.ts b/packages/client/src/gen/video/sfu/signal_rpc/signal.ts index 5c726a2396..80de3b8a61 100644 --- a/packages/client/src/gen/video/sfu/signal_rpc/signal.ts +++ b/packages/client/src/gen/video/sfu/signal_rpc/signal.ts @@ -3,8 +3,11 @@ // @generated from protobuf file "video/sfu/signal_rpc/signal.proto" (package "stream.video.sfu.signal", syntax proto3) // tslint:disable import { + AndroidState, + AppleState, Error, ICETrickle, + InputDevices, PeerType, TrackInfo, TrackType, @@ -77,6 +80,35 @@ export interface SendStatsRequest { * @generated from protobuf field: string sdk_version = 6; */ sdkVersion: string; + /** + * @generated from protobuf field: stream.video.sfu.models.InputDevices audio_devices = 7; + */ + audioDevices?: InputDevices; + /** + * @generated from protobuf field: stream.video.sfu.models.InputDevices video_devices = 8; + */ + videoDevices?: InputDevices; + /** + * @generated from protobuf oneof: device_state + */ + deviceState: + | { + oneofKind: 'android'; + /** + * @generated from protobuf field: stream.video.sfu.models.AndroidState android = 9; + */ + android: AndroidState; + } + | { + oneofKind: 'apple'; + /** + * @generated from protobuf field: stream.video.sfu.models.AppleState apple = 10; + */ + apple: AppleState; + } + | { + oneofKind: undefined; + }; } /** * @generated from protobuf message stream.video.sfu.signal.SendStatsResponse @@ -364,6 +396,22 @@ class SendStatsRequest$Type extends MessageType { kind: 'scalar', T: 9 /*ScalarType.STRING*/, }, + { no: 7, name: 'audio_devices', kind: 'message', T: () => InputDevices }, + { no: 8, name: 'video_devices', kind: 'message', T: () => InputDevices }, + { + no: 9, + name: 'android', + kind: 'message', + oneof: 'deviceState', + T: () => AndroidState, + }, + { + no: 10, + name: 'apple', + kind: 'message', + oneof: 'deviceState', + T: () => AppleState, + }, ]); } } diff --git a/packages/client/src/stats/SfuStatsReporter.ts b/packages/client/src/stats/SfuStatsReporter.ts index 459686041e..be010e7fd3 100644 --- a/packages/client/src/stats/SfuStatsReporter.ts +++ b/packages/client/src/stats/SfuStatsReporter.ts @@ -1,15 +1,23 @@ +import { combineLatest } from 'rxjs'; import { StreamSfuClient } from '../StreamSfuClient'; -import { StatsOptions } from '../gen/coordinator'; +import { OwnCapability, StatsOptions } from '../gen/coordinator'; import { getLogger } from '../logger'; import { Publisher, Subscriber } from '../rtc'; import { flatten, getSdkName, getSdkVersion } from './utils'; import { getWebRTCInfo, LocalClientDetailsType } from '../client-details'; +import { InputDevices } from '../gen/video/sfu/models/models'; +import { CameraManager, MicrophoneManager } from '../devices'; +import { createSubscription } from '../store/rxUtils'; +import { CallState } from '../store'; export type SfuStatsReporterOptions = { options: StatsOptions; clientDetails: LocalClientDetailsType; subscriber: Subscriber; publisher?: Publisher; + microphone: MicrophoneManager; + camera: CameraManager; + state: CallState; }; export class SfuStatsReporter { @@ -20,34 +28,91 @@ export class SfuStatsReporter { private readonly sfuClient: StreamSfuClient; private readonly subscriber: Subscriber; private readonly publisher?: Publisher; + private readonly microphone: MicrophoneManager; + private readonly camera: CameraManager; + private readonly state: CallState; private intervalId: NodeJS.Timeout | undefined; + private unsubscribeDevicePermissionsSubscription?: () => void; + private unsubscribeListDevicesSubscription?: () => void; private readonly sdkName: string; private readonly sdkVersion: string; private readonly webRTCVersion: string; + private readonly inputDevices = new Map<'mic' | 'camera', InputDevices>(); constructor( sfuClient: StreamSfuClient, - { options, clientDetails, subscriber, publisher }: SfuStatsReporterOptions, + { + options, + clientDetails, + subscriber, + publisher, + microphone, + camera, + state, + }: SfuStatsReporterOptions, ) { this.sfuClient = sfuClient; this.options = options; this.subscriber = subscriber; this.publisher = publisher; - const webRTCInfo = getWebRTCInfo(); + this.microphone = microphone; + this.camera = camera; + this.state = state; const { sdk, browser } = clientDetails; - this.sdkName = getSdkName(sdk); this.sdkVersion = getSdkVersion(sdk); - // The WebRTC version if passed from the SDK, it is taken else the browser info is sent. + // use the WebRTC version if set by the SDK (React Native) otherwise, + // use the browser version as a fallback + const webRTCInfo = getWebRTCInfo(); this.webRTCVersion = webRTCInfo?.version || `${browser?.name || ''}-${browser?.version || ''}` || 'N/A'; } + private observeDevice = ( + device: CameraManager | MicrophoneManager, + kind: 'mic' | 'camera', + ) => { + const { hasBrowserPermission$ } = device.state; + this.unsubscribeDevicePermissionsSubscription?.(); + this.unsubscribeDevicePermissionsSubscription = createSubscription( + combineLatest([hasBrowserPermission$, this.state.ownCapabilities$]), + ([hasPermission, ownCapabilities]) => { + // cleanup the previous listDevices() subscription in case + // permissions or capabilities have changed. + // we will subscribe again if everything is in order. + this.unsubscribeListDevicesSubscription?.(); + const hasCapability = + kind === 'mic' + ? ownCapabilities.includes(OwnCapability.SEND_AUDIO) + : ownCapabilities.includes(OwnCapability.SEND_VIDEO); + if (!hasPermission || !hasCapability) { + this.inputDevices.set(kind, { + currentDevice: '', + availableDevices: [], + isPermitted: false, + }); + return; + } + this.unsubscribeListDevicesSubscription = createSubscription( + combineLatest([device.listDevices(), device.state.selectedDevice$]), + ([devices, deviceId]) => { + const selected = devices.find((d) => d.deviceId === deviceId); + this.inputDevices.set(kind, { + currentDevice: selected?.label || deviceId || '', + availableDevices: devices.map((d) => d.label), + isPermitted: true, + }); + }, + ); + }, + ); + }; + private run = async () => { const [subscriberStats, publisherStats] = await Promise.all([ this.subscriber.getStats().then(flatten).then(JSON.stringify), @@ -60,11 +125,18 @@ export class SfuStatsReporter { webrtcVersion: this.webRTCVersion, subscriberStats, publisherStats, + audioDevices: this.inputDevices.get('mic'), + videoDevices: this.inputDevices.get('camera'), + deviceState: { oneofKind: undefined }, }); }; start = () => { if (this.options.reporting_interval_ms <= 0) return; + + this.observeDevice(this.microphone, 'mic'); + this.observeDevice(this.camera, 'camera'); + clearInterval(this.intervalId); this.intervalId = setInterval(() => { this.run().catch((err) => { @@ -74,6 +146,12 @@ export class SfuStatsReporter { }; stop = () => { + this.unsubscribeDevicePermissionsSubscription?.(); + this.unsubscribeDevicePermissionsSubscription = undefined; + this.unsubscribeListDevicesSubscription?.(); + this.unsubscribeListDevicesSubscription = undefined; + + this.inputDevices.clear(); clearInterval(this.intervalId); this.intervalId = undefined; }; diff --git a/packages/client/src/store/rxUtils.ts b/packages/client/src/store/rxUtils.ts index a5095e281c..9f9d7f638e 100644 --- a/packages/client/src/store/rxUtils.ts +++ b/packages/client/src/store/rxUtils.ts @@ -1,5 +1,6 @@ import { combineLatest, Observable, Subject } from 'rxjs'; import { withoutConcurrency } from '../helpers/concurrency'; +import { getLogger } from '../logger'; type FunctionPatch = (currentValue: T) => T; @@ -63,12 +64,15 @@ export const setCurrentValue = (subject: Subject, update: Patch) => { * * @param observable the observable to subscribe to. * @param handler the handler to call when the observable emits a value. + * @param onError an optional error handler. */ export const createSubscription = ( observable: Observable, handler: (value: T) => void, + onError: (error: any) => void = (error) => + getLogger(['RxUtils'])('warn', 'An observable emitted an error', error), ) => { - const subscription = observable.subscribe(handler); + const subscription = observable.subscribe({ next: handler, error: onError }); return () => { subscription.unsubscribe(); }; @@ -87,10 +91,7 @@ export const createSafeAsyncSubscription = ( handler: (value: T) => Promise, ) => { const tag = Symbol(); - const subscription = observable.subscribe((value) => { + return createSubscription(observable, (value) => { withoutConcurrency(tag, () => handler(value)); }); - return () => { - subscription.unsubscribe(); - }; }; diff --git a/sample-apps/react/react-dogfood/components/ActiveCall.tsx b/sample-apps/react/react-dogfood/components/ActiveCall.tsx index bd7907961c..eed08f78f1 100644 --- a/sample-apps/react/react-dogfood/components/ActiveCall.tsx +++ b/sample-apps/react/react-dogfood/components/ActiveCall.tsx @@ -7,10 +7,12 @@ import { CancelCallConfirmButton, CompositeButton, Icon, + OwnCapability, PermissionRequests, ReactionsButton, RecordCallConfirmationButton, RecordingInProgressNotification, + Restricted, ScreenShareButton, SpeakingWhileMutedNotification, useCallStateHooks, @@ -194,7 +196,12 @@ export const ActiveCall = (props: ActiveCallProps) => {
- + + +
{ return ( -
- } - menuPlacement="top" - /> -
+ +
+ } + menuPlacement="top" + /> +
+
); }; diff --git a/sample-apps/react/react-dogfood/components/ToggleDualMicButton.tsx b/sample-apps/react/react-dogfood/components/ToggleDualMicButton.tsx index 4a07c7e4af..0a0b4aef7b 100644 --- a/sample-apps/react/react-dogfood/components/ToggleDualMicButton.tsx +++ b/sample-apps/react/react-dogfood/components/ToggleDualMicButton.tsx @@ -1,15 +1,21 @@ import { DeviceSelectorAudioInput, + OwnCapability, + Restricted, ToggleAudioPublishingButton, } from '@stream-io/video-react-sdk'; export const ToggleDualMicButton = () => { return ( -
- } - menuPlacement="top" - /> -
+ +
+ + } + menuPlacement="top" + /> +
+
); }; From cbbdeaab8108079274e4b8826e3106d49e0b97e4 Mon Sep 17 00:00:00 2001 From: GitHub Actions Bot <> Date: Wed, 30 Oct 2024 12:25:40 +0000 Subject: [PATCH 09/19] chore(@stream-io/video-client): release version 1.10.0 --- packages/client/CHANGELOG.md | 7 +++++++ packages/client/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/client/CHANGELOG.md b/packages/client/CHANGELOG.md index c512670200..e108201f8b 100644 --- a/packages/client/CHANGELOG.md +++ b/packages/client/CHANGELOG.md @@ -2,6 +2,13 @@ This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver). +## [1.10.0](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.9.3...@stream-io/video-client-1.10.0) (2024-10-30) + + +### Features + +* report input devices in call stats ([#1533](https://github.com/GetStream/stream-video-js/issues/1533)) ([f34fe0a](https://github.com/GetStream/stream-video-js/commit/f34fe0a0444903099565ae55a9639e39fc19b76c)) + ## [1.9.3](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.9.2...@stream-io/video-client-1.9.3) (2024-10-28) diff --git a/packages/client/package.json b/packages/client/package.json index 22ddf25a6c..cf94ecd9ef 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@stream-io/video-client", - "version": "1.9.3", + "version": "1.10.0", "packageManager": "yarn@3.2.4", "main": "dist/index.cjs.js", "module": "dist/index.es.js", From 8984b8befbb1d1219559130e31c5232fe16ced5b Mon Sep 17 00:00:00 2001 From: GitHub Actions Bot <> Date: Wed, 30 Oct 2024 12:26:05 +0000 Subject: [PATCH 10/19] chore(@stream-io/video-react-bindings): release version 1.1.9 --- packages/react-bindings/CHANGELOG.md | 5 +++++ packages/react-bindings/package.json | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/react-bindings/CHANGELOG.md b/packages/react-bindings/CHANGELOG.md index 6c0330230a..27c43da124 100644 --- a/packages/react-bindings/CHANGELOG.md +++ b/packages/react-bindings/CHANGELOG.md @@ -2,6 +2,11 @@ This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver). +## [1.1.9](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-react-bindings-1.1.8...@stream-io/video-react-bindings-1.1.9) (2024-10-30) + +### Dependency Updates + +* `@stream-io/video-client` updated to version `1.10.0` ## [1.1.8](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-react-bindings-1.1.7...@stream-io/video-react-bindings-1.1.8) (2024-10-28) ### Dependency Updates diff --git a/packages/react-bindings/package.json b/packages/react-bindings/package.json index ea65f2fef2..bf787d5fac 100644 --- a/packages/react-bindings/package.json +++ b/packages/react-bindings/package.json @@ -1,6 +1,6 @@ { "name": "@stream-io/video-react-bindings", - "version": "1.1.8", + "version": "1.1.9", "packageManager": "yarn@3.2.4", "main": "./dist/index.cjs.js", "module": "./dist/index.es.js", From 4e3d5b2326c983dd57ccce2eb2247e2e4980b5be Mon Sep 17 00:00:00 2001 From: GitHub Actions Bot <> Date: Wed, 30 Oct 2024 12:26:13 +0000 Subject: [PATCH 11/19] chore(@stream-io/video-react-sdk): release version 1.7.4 --- packages/react-sdk/CHANGELOG.md | 6 ++++++ packages/react-sdk/package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/react-sdk/CHANGELOG.md b/packages/react-sdk/CHANGELOG.md index 4ea144b6b3..c5c648f3e3 100644 --- a/packages/react-sdk/CHANGELOG.md +++ b/packages/react-sdk/CHANGELOG.md @@ -2,6 +2,12 @@ This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver). +## [1.7.4](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-react-sdk-1.7.3...@stream-io/video-react-sdk-1.7.4) (2024-10-30) + +### Dependency Updates + +* `@stream-io/video-client` updated to version `1.10.0` +* `@stream-io/video-react-bindings` updated to version `1.1.9` ## [1.7.3](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-react-sdk-1.7.2...@stream-io/video-react-sdk-1.7.3) (2024-10-28) ### Dependency Updates diff --git a/packages/react-sdk/package.json b/packages/react-sdk/package.json index 35a002ed60..adc837cea6 100644 --- a/packages/react-sdk/package.json +++ b/packages/react-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@stream-io/video-react-sdk", - "version": "1.7.3", + "version": "1.7.4", "packageManager": "yarn@3.2.4", "main": "./dist/index.cjs.js", "module": "./dist/index.es.js", From 8a0261811f670e5f8f06f4fc8d4b69ec19480e2f Mon Sep 17 00:00:00 2001 From: GitHub Actions Bot <> Date: Wed, 30 Oct 2024 12:26:32 +0000 Subject: [PATCH 12/19] chore(@stream-io/video-react-native-sdk): release version 1.2.6 --- packages/react-native-sdk/CHANGELOG.md | 6 ++++++ packages/react-native-sdk/package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/react-native-sdk/CHANGELOG.md b/packages/react-native-sdk/CHANGELOG.md index 820371adca..704e524e0a 100644 --- a/packages/react-native-sdk/CHANGELOG.md +++ b/packages/react-native-sdk/CHANGELOG.md @@ -2,6 +2,12 @@ This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver). +## [1.2.6](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-react-native-sdk-1.2.5...@stream-io/video-react-native-sdk-1.2.6) (2024-10-30) + +### Dependency Updates + +* `@stream-io/video-client` updated to version `1.10.0` +* `@stream-io/video-react-bindings` updated to version `1.1.9` ## [1.2.5](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-react-native-sdk-1.2.4...@stream-io/video-react-native-sdk-1.2.5) (2024-10-28) ### Dependency Updates diff --git a/packages/react-native-sdk/package.json b/packages/react-native-sdk/package.json index 260c30f0ea..2a46fab05b 100644 --- a/packages/react-native-sdk/package.json +++ b/packages/react-native-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@stream-io/video-react-native-sdk", - "version": "1.2.5", + "version": "1.2.6", "packageManager": "yarn@3.2.4", "main": "dist/commonjs/index.js", "module": "dist/module/index.js", From 84d49b32cc95a7ca46831142422fb88e1ae73862 Mon Sep 17 00:00:00 2001 From: GitHub Actions Bot <> Date: Wed, 30 Oct 2024 12:26:56 +0000 Subject: [PATCH 13/19] chore(@stream-io/video-react-native-dogfood): release version 4.4.6 --- sample-apps/react-native/dogfood/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sample-apps/react-native/dogfood/package.json b/sample-apps/react-native/dogfood/package.json index 724a92472a..245e283faa 100644 --- a/sample-apps/react-native/dogfood/package.json +++ b/sample-apps/react-native/dogfood/package.json @@ -1,6 +1,6 @@ { "name": "@stream-io/video-react-native-dogfood", - "version": "4.4.5", + "version": "4.4.6", "private": true, "scripts": { "android": "react-native run-android", From f23618bda447eeb2d66f908bdb38b24db051f87c Mon Sep 17 00:00:00 2001 From: Matvei Andrienko Date: Wed, 30 Oct 2024 15:11:09 +0100 Subject: [PATCH 14/19] fix: various device selector issues (#1541) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR fixes a bunch of device selector issues. ## Invalid default device indicator In some of our device selector components, we assumed that the first device in the list was the default. This isn't always true. So now, if we don't know what the default device is, we don't mark any device as selected, which is more "honest" behavior. ![image](https://github.com/user-attachments/assets/ae815782-5950-4845-a338-95cabc9d35d5) This PR also ensures that device selectors always fall back to the "Default" option if the current device is not found in the device list (e.g. because of stale persisted device preferences) or the device list is empty (e.g. if there's no browser permission). ![image](https://github.com/user-attachments/assets/05c132fa-d581-4ca8-964d-476c22d60b0c) ![image](https://github.com/user-attachments/assets/ca36a120-e178-4531-bb5e-a487be7bb1ba) ## Older Firefox cannot query permissions Up until version 131 (incl.) there was no way to query camera and microphone permissions with `navigator.permissions.query`. We now assume that permission status is `prompt` in this case, and just try getting user media. If it works, permission is granted, if not - it’s denied. ## Firefox doesn't show device labels without `getUserMedia` When enumerating devices, Firefox will hide device labels unless there’s been an active user media stream on the page. So even when camera and microphone permissions are `granted`, device labels are still hidden until there’s been a successful call to `getUserMedia`. Now we force device list updates after every successful `getUserMedia` call. ## Safari doesn't fire permission change events reliably Safari doesn't fire camera and microphone permission change events for reliably. For example, the event doesn't fire if the user denies camera/microphone access in the initial prompt. As a result, we didn't reliably display missing permission indicators in Safari. We now update browser permission state not only from permission change events, but also based on `NotAllowedError` and successful attempts to obtain the user's media stream. --- .../client/src/devices/BrowserPermission.ts | 4 +- packages/client/src/devices/devices.ts | 25 ++++++-- .../DeviceSettings/DeviceSelector.tsx | 64 +++++-------------- packages/react-sdk/src/translations/en.json | 1 + 4 files changed, 38 insertions(+), 56 deletions(-) diff --git a/packages/client/src/devices/BrowserPermission.ts b/packages/client/src/devices/BrowserPermission.ts index 299481202e..ce4a299970 100644 --- a/packages/client/src/devices/BrowserPermission.ts +++ b/packages/client/src/devices/BrowserPermission.ts @@ -22,7 +22,7 @@ export class BrowserPermission { this.ready = (async () => { const assumeGranted = (error?: unknown) => { - this.setState('granted'); + this.setState('prompt'); }; if (!canQueryPermissions()) { @@ -88,12 +88,14 @@ export class BrowserPermission { this.permission.constraints, ); disposeOfMediaStream(stream); + this.setState('granted'); return true; } catch (e) { if (e instanceof DOMException && e.name === 'NotAllowedError') { this.logger('info', 'Browser permission was not granted', { permission: this.permission, }); + this.setState('denied'); if (throwOnNotAllowed) { throw e; diff --git a/packages/client/src/devices/devices.ts b/packages/client/src/devices/devices.ts index 107d534ffe..2bbf19a93d 100644 --- a/packages/client/src/devices/devices.ts +++ b/packages/client/src/devices/devices.ts @@ -11,6 +11,7 @@ import { import { getLogger } from '../logger'; import { BrowserPermission } from './BrowserPermission'; import { lazy } from '../helpers/lazy'; +import { isFirefox } from '../helpers/browsers'; /** * Returns an Observable that emits the list of available devices @@ -32,7 +33,12 @@ const getDevices = (permission: BrowserPermission, kind: MediaDeviceKind) => { await permission.prompt({ throwOnNotAllowed: true }); devices = await navigator.mediaDevices.enumerateDevices(); } - return devices.filter((d) => d.kind === kind); + return devices.filter( + (device) => + device.kind === kind && + device.label !== '' && + device.deviceId !== 'default', + ); })(), ); }; @@ -125,7 +131,7 @@ export const getAudioDevices = lazy(() => { * if devices are added/removed the list is updated, and if the permission is revoked, * the observable errors. */ -export const getVideoDevices = () => { +export const getVideoDevices = lazy(() => { return merge( getDeviceChangeObserver(), getVideoBrowserPermission().asObservable(), @@ -134,7 +140,7 @@ export const getVideoDevices = () => { concatMap(() => getDevices(getVideoBrowserPermission(), 'videoinput')), shareReplay(1), ); -}; +}); /** * Prompts the user for a permission to use video devices (if not already granted @@ -142,7 +148,7 @@ export const getVideoDevices = () => { * if devices are added/removed the list is updated, and if the permission is revoked, * the observable errors. */ -export const getAudioOutputDevices = () => { +export const getAudioOutputDevices = lazy(() => { return merge( getDeviceChangeObserver(), getAudioBrowserPermission().asObservable(), @@ -151,10 +157,17 @@ export const getAudioOutputDevices = () => { concatMap(() => getDevices(getAudioBrowserPermission(), 'audiooutput')), shareReplay(1), ); -}; +}); const getStream = async (constraints: MediaStreamConstraints) => { - return await navigator.mediaDevices.getUserMedia(constraints); + const stream = await navigator.mediaDevices.getUserMedia(constraints); + if (isFirefox()) { + // When enumerating devices, Firefox will hide device labels unless there's been + // an active user media stream on the page. So we force device list updates after + // every successful getUserMedia call. + navigator.mediaDevices.dispatchEvent(new Event('devicechange')); + } + return stream; }; /** diff --git a/packages/react-sdk/src/components/DeviceSettings/DeviceSelector.tsx b/packages/react-sdk/src/components/DeviceSettings/DeviceSelector.tsx index 6c0074bcf5..50131061be 100644 --- a/packages/react-sdk/src/components/DeviceSettings/DeviceSelector.tsx +++ b/packages/react-sdk/src/components/DeviceSettings/DeviceSelector.tsx @@ -3,6 +3,7 @@ import { ChangeEventHandler, useCallback } from 'react'; import { DropDownSelect, DropDownSelectOption } from '../DropdownSelect'; import { useMenuContext } from '../Menu'; +import { useI18n } from '@stream-io/video-react-bindings'; type DeviceSelectorOptionProps = { id: string; @@ -57,26 +58,9 @@ const DeviceSelectorList = (props: { title?: string; onChange?: (deviceId: string) => void; }) => { - const { - devices = [], - selectedDeviceId: selectedDeviceFromProps, - title, - type, - onChange, - } = props; - + const { devices = [], selectedDeviceId, title, type, onChange } = props; const { close } = useMenuContext(); - - // sometimes the browser (Chrome) will report the system-default device - // with an id of 'default'. In case when it doesn't, we'll select the first - // available device. - let selectedDeviceId = selectedDeviceFromProps; - if ( - devices.length > 0 && - !devices.find((d) => d.deviceId === selectedDeviceId) - ) { - selectedDeviceId = devices[0].deviceId; - } + const { t } = useI18n(); return (
@@ -85,10 +69,10 @@ const DeviceSelectorList = (props: { {title}
)} - {!devices.length ? ( + {devices.length === 0 ? ( void; - visualType?: 'list' | 'dropdown'; icon: string; - placeholder?: string; }) => { - const { - devices = [], - selectedDeviceId: selectedDeviceFromProps, - title, - onChange, - icon, - } = props; - - // sometimes the browser (Chrome) will report the system-default device - // with an id of 'default'. In case when it doesn't, we'll select the first - // available device. - let selectedDeviceId = selectedDeviceFromProps; - if ( - devices.length > 0 && - !devices.find((d) => d.deviceId === selectedDeviceId) - ) { - selectedDeviceId = devices[0].deviceId; - } + const { devices = [], selectedDeviceId, title, onChange, icon } = props; + const { t } = useI18n(); const selectedIndex = devices.findIndex( (d) => d.deviceId === selectedDeviceId, @@ -164,11 +130,13 @@ const DeviceSelectorDropdown = (props: { - {devices.map((device) => { - return ( + {devices.length === 0 ? ( + + ) : ( + devices.map((device) => ( - ); - })} + )) + )}
); @@ -199,7 +167,5 @@ export const DeviceSelector = (props: { if (visualType === 'list') { return ; } - return ( - - ); + return ; }; diff --git a/packages/react-sdk/src/translations/en.json b/packages/react-sdk/src/translations/en.json index 05ba62a465..bf1176a60f 100644 --- a/packages/react-sdk/src/translations/en.json +++ b/packages/react-sdk/src/translations/en.json @@ -38,6 +38,7 @@ "Me": "Me", "Unknown": "Unknown", "Toggle device menu": "Toggle device menu", + "Default": "Default", "Call Recordings": "Call Recordings", "Refresh": "Refresh", "Check your browser video permissions": "Check your browser video permissions", From 02ef492a4c5b53f8eafd43598e1ba7fbffe71039 Mon Sep 17 00:00:00 2001 From: GitHub Actions Bot <> Date: Wed, 30 Oct 2024 14:13:57 +0000 Subject: [PATCH 15/19] chore(@stream-io/video-client): release version 1.10.1 --- packages/client/CHANGELOG.md | 7 +++++++ packages/client/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/client/CHANGELOG.md b/packages/client/CHANGELOG.md index e108201f8b..51357ce4a7 100644 --- a/packages/client/CHANGELOG.md +++ b/packages/client/CHANGELOG.md @@ -2,6 +2,13 @@ This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver). +## [1.10.1](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.10.0...@stream-io/video-client-1.10.1) (2024-10-30) + + +### Bug Fixes + +* various device selector issues ([#1541](https://github.com/GetStream/stream-video-js/issues/1541)) ([f23618b](https://github.com/GetStream/stream-video-js/commit/f23618bda447eeb2d66f908bdb38b24db051f87c)) + ## [1.10.0](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.9.3...@stream-io/video-client-1.10.0) (2024-10-30) diff --git a/packages/client/package.json b/packages/client/package.json index cf94ecd9ef..d9bab64954 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@stream-io/video-client", - "version": "1.10.0", + "version": "1.10.1", "packageManager": "yarn@3.2.4", "main": "dist/index.cjs.js", "module": "dist/index.es.js", From 2c211ce254d0cb0bfa8fd00d046b4703c0291c33 Mon Sep 17 00:00:00 2001 From: GitHub Actions Bot <> Date: Wed, 30 Oct 2024 14:14:20 +0000 Subject: [PATCH 16/19] chore(@stream-io/video-react-bindings): release version 1.1.10 --- packages/react-bindings/CHANGELOG.md | 5 +++++ packages/react-bindings/package.json | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/react-bindings/CHANGELOG.md b/packages/react-bindings/CHANGELOG.md index 27c43da124..ad739ae6a3 100644 --- a/packages/react-bindings/CHANGELOG.md +++ b/packages/react-bindings/CHANGELOG.md @@ -2,6 +2,11 @@ This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver). +## [1.1.10](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-react-bindings-1.1.9...@stream-io/video-react-bindings-1.1.10) (2024-10-30) + +### Dependency Updates + +* `@stream-io/video-client` updated to version `1.10.1` ## [1.1.9](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-react-bindings-1.1.8...@stream-io/video-react-bindings-1.1.9) (2024-10-30) ### Dependency Updates diff --git a/packages/react-bindings/package.json b/packages/react-bindings/package.json index bf787d5fac..52d5b72904 100644 --- a/packages/react-bindings/package.json +++ b/packages/react-bindings/package.json @@ -1,6 +1,6 @@ { "name": "@stream-io/video-react-bindings", - "version": "1.1.9", + "version": "1.1.10", "packageManager": "yarn@3.2.4", "main": "./dist/index.cjs.js", "module": "./dist/index.es.js", From 029870d2e4527b3b7c2688db40c687bf4da6df7c Mon Sep 17 00:00:00 2001 From: GitHub Actions Bot <> Date: Wed, 30 Oct 2024 14:14:28 +0000 Subject: [PATCH 17/19] chore(@stream-io/video-react-sdk): release version 1.7.5 --- packages/react-sdk/CHANGELOG.md | 11 +++++++++++ packages/react-sdk/package.json | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/react-sdk/CHANGELOG.md b/packages/react-sdk/CHANGELOG.md index c5c648f3e3..c7efd7bfc6 100644 --- a/packages/react-sdk/CHANGELOG.md +++ b/packages/react-sdk/CHANGELOG.md @@ -2,6 +2,17 @@ This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver). +## [1.7.5](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-react-sdk-1.7.4...@stream-io/video-react-sdk-1.7.5) (2024-10-30) + +### Dependency Updates + +* `@stream-io/video-client` updated to version `1.10.1` +* `@stream-io/video-react-bindings` updated to version `1.1.10` + +### Bug Fixes + +* various device selector issues ([#1541](https://github.com/GetStream/stream-video-js/issues/1541)) ([f23618b](https://github.com/GetStream/stream-video-js/commit/f23618bda447eeb2d66f908bdb38b24db051f87c)) + ## [1.7.4](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-react-sdk-1.7.3...@stream-io/video-react-sdk-1.7.4) (2024-10-30) ### Dependency Updates diff --git a/packages/react-sdk/package.json b/packages/react-sdk/package.json index adc837cea6..39dc2fa31a 100644 --- a/packages/react-sdk/package.json +++ b/packages/react-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@stream-io/video-react-sdk", - "version": "1.7.4", + "version": "1.7.5", "packageManager": "yarn@3.2.4", "main": "./dist/index.cjs.js", "module": "./dist/index.es.js", From 615147eece28e671353121626971ba5007a9571c Mon Sep 17 00:00:00 2001 From: GitHub Actions Bot <> Date: Wed, 30 Oct 2024 14:14:46 +0000 Subject: [PATCH 18/19] chore(@stream-io/video-react-native-sdk): release version 1.2.7 --- packages/react-native-sdk/CHANGELOG.md | 6 ++++++ packages/react-native-sdk/package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/react-native-sdk/CHANGELOG.md b/packages/react-native-sdk/CHANGELOG.md index 704e524e0a..219b6cf53c 100644 --- a/packages/react-native-sdk/CHANGELOG.md +++ b/packages/react-native-sdk/CHANGELOG.md @@ -2,6 +2,12 @@ This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver). +## [1.2.7](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-react-native-sdk-1.2.6...@stream-io/video-react-native-sdk-1.2.7) (2024-10-30) + +### Dependency Updates + +* `@stream-io/video-client` updated to version `1.10.1` +* `@stream-io/video-react-bindings` updated to version `1.1.10` ## [1.2.6](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-react-native-sdk-1.2.5...@stream-io/video-react-native-sdk-1.2.6) (2024-10-30) ### Dependency Updates diff --git a/packages/react-native-sdk/package.json b/packages/react-native-sdk/package.json index 2a46fab05b..28c1c613b6 100644 --- a/packages/react-native-sdk/package.json +++ b/packages/react-native-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@stream-io/video-react-native-sdk", - "version": "1.2.6", + "version": "1.2.7", "packageManager": "yarn@3.2.4", "main": "dist/commonjs/index.js", "module": "dist/module/index.js", From 6a41d14d22a77de4dc57602bf3d7e377cc1f1e14 Mon Sep 17 00:00:00 2001 From: GitHub Actions Bot <> Date: Wed, 30 Oct 2024 14:15:09 +0000 Subject: [PATCH 19/19] chore(@stream-io/video-react-native-dogfood): release version 4.4.7 --- sample-apps/react-native/dogfood/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sample-apps/react-native/dogfood/package.json b/sample-apps/react-native/dogfood/package.json index 245e283faa..49dde5fdfc 100644 --- a/sample-apps/react-native/dogfood/package.json +++ b/sample-apps/react-native/dogfood/package.json @@ -1,6 +1,6 @@ { "name": "@stream-io/video-react-native-dogfood", - "version": "4.4.6", + "version": "4.4.7", "private": true, "scripts": { "android": "react-native run-android",