Skip to content

Commit

Permalink
Merge branch 'main' into expose-android-push-utils
Browse files Browse the repository at this point in the history
# Conflicts:
#	sample-apps/react-native/dogfood/ios/Podfile.lock
  • Loading branch information
santhoshvai committed Nov 11, 2024
2 parents e99ddf2 + fae292a commit 0329aa0
Show file tree
Hide file tree
Showing 52 changed files with 912 additions and 127 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/react-native-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ jobs:
name: Deploy iOS
needs: build_ios
timeout-minutes: 60
if: ${{ github.ref == 'refs/heads/main' }}
if: ${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/PBE-5855-feat/react-native-video-design-v2' }}
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
Expand Down
42 changes: 42 additions & 0 deletions packages/client/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,48 @@

This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).

## [1.10.5](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.10.4...@stream-io/video-client-1.10.5) (2024-11-07)


### Bug Fixes

* ignore maxSimulcastLayers override for SVC codecs ([#1564](https://github.com/GetStream/stream-video-js/issues/1564)) ([48f8abe](https://github.com/GetStream/stream-video-js/commit/48f8abe5fd5b48c367a04696febd582573def828))

## [1.10.4](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.10.3...@stream-io/video-client-1.10.4) (2024-11-07)


### Bug Fixes

* max simulcast layers preference ([#1560](https://github.com/GetStream/stream-video-js/issues/1560)) ([2b0bf28](https://github.com/GetStream/stream-video-js/commit/2b0bf2824dce41c2709e361e0521cf85e1b2fd16))

## [1.10.3](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.10.2...@stream-io/video-client-1.10.3) (2024-11-05)


### Bug Fixes

* camera flip did not work in react-native ([#1554](https://github.com/GetStream/stream-video-js/issues/1554)) ([423890c](https://github.com/GetStream/stream-video-js/commit/423890cb2d1925366d8a63c29f93c4c92c8104ad)), closes [#1521](https://github.com/GetStream/stream-video-js/issues/1521)

## [1.10.2](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.10.1...@stream-io/video-client-1.10.2) (2024-11-01)


### Bug Fixes

* camera not enabled on foreground notifications ([#1546](https://github.com/GetStream/stream-video-js/issues/1546)) ([67c920a](https://github.com/GetStream/stream-video-js/commit/67c920ac4bca35a414b88f6c9829b08396a6260b))

## [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)


### 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)


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ const subscription = call.state.participants$.subscribe((participants) => {
subscription.unsubscribe();
```

In a call with many participants, the value of the `participants$` call state observable is truncated to 250 participants. The participants who are publishing video, audio, or screen sharing have priority over the other participants in the list. This means, for example, that in a livestream with one host and many viewers, the host is guaranteed to be in the list.

## Client state

The client state can be accessed by `client.state`.
Expand Down
2 changes: 1 addition & 1 deletion packages/client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@stream-io/video-client",
"version": "1.9.3",
"version": "1.10.5",
"packageManager": "[email protected]",
"main": "dist/index.cjs.js",
"module": "dist/index.es.js",
Expand Down
3 changes: 3 additions & 0 deletions packages/client/src/Call.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down
2 changes: 1 addition & 1 deletion packages/client/src/coordinator/connection/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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/',
);
}

Expand Down
4 changes: 3 additions & 1 deletion packages/client/src/devices/BrowserPermission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export class BrowserPermission {

this.ready = (async () => {
const assumeGranted = (error?: unknown) => {
this.setState('granted');
this.setState('prompt');
};

if (!canQueryPermissions()) {
Expand Down Expand Up @@ -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;
Expand Down
14 changes: 12 additions & 2 deletions packages/client/src/devices/CameraManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { getVideoDevices, getVideoStream } from './devices';
import { TrackType } from '../gen/video/sfu/models/models';
import { PreferredCodec } from '../types';
import { isMobile } from '../compatibility';
import { isReactNative } from '../helpers/platforms';

export class CameraManager extends InputMediaDeviceManager<CameraManagerState> {
private targetResolution = {
Expand All @@ -22,13 +23,17 @@ export class CameraManager extends InputMediaDeviceManager<CameraManagerState> {
super(call, new CameraManagerState(), TrackType.VIDEO);
}

private isDirectionSupportedByDevice() {
return isReactNative() || isMobile();
}

/**
* Select the camera direction.
*
* @param direction the direction of the camera to select.
*/
async selectDirection(direction: Exclude<CameraDirection, undefined>) {
if (isMobile()) {
if (this.isDirectionSupportedByDevice()) {
this.state.setDirection(direction);
// Providing both device id and direction doesn't work, so we deselect the device
this.state.setDevice(undefined);
Expand Down Expand Up @@ -102,7 +107,12 @@ export class CameraManager extends InputMediaDeviceManager<CameraManagerState> {
constraints.height = this.targetResolution.height;
// We can't set both device id and facing mode
// Device id has higher priority
if (!constraints.deviceId && this.state.direction && isMobile()) {

if (
!constraints.deviceId &&
this.state.direction &&
this.isDirectionSupportedByDevice()
) {
constraints.facingMode =
this.state.direction === 'front' ? 'user' : 'environment';
}
Expand Down
6 changes: 3 additions & 3 deletions packages/client/src/devices/InputMediaDeviceManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,10 @@ export abstract class InputMediaDeviceManager<
* Starts stream.
*/
async enable() {
this.state.prevStatus = this.state.optimisticStatus;
if (this.state.optimisticStatus === 'enabled') {
return;
}

this.state.setPendingStatus('enabled');

await withCancellation(this.statusChangeConcurrencyTag, async (signal) => {
Expand All @@ -97,7 +97,7 @@ export abstract class InputMediaDeviceManager<
* @param {boolean} [forceStop=false] when true, stops the tracks regardless of the state.disableMode
*/
async disable(forceStop: boolean = false) {
this.state.prevStatus = this.state.status;
this.state.prevStatus = this.state.optimisticStatus;
if (!forceStop && this.state.optimisticStatus === 'disabled') {
return;
}
Expand Down Expand Up @@ -131,7 +131,7 @@ export abstract class InputMediaDeviceManager<
async resume() {
if (
this.state.prevStatus === 'enabled' &&
this.state.status === 'disabled'
this.state.status !== 'enabled'
) {
await this.enable();
}
Expand Down
7 changes: 7 additions & 0 deletions packages/client/src/devices/__tests__/CameraManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ vi.mock('../../compatibility.ts', () => {
};
});

vi.mock('../../helpers/platforms', () => {
console.log('MOCKING mobile device');
return {
isReactNative: () => false,
};
});

describe('CameraManager', () => {
let manager: CameraManager;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,29 @@ describe('InputMediaDeviceManager.test', () => {
expect(manager.enable).toHaveBeenCalledOnce();
});

it(`should resume if enable was cancelled due to disable call`, async () => {
vi.spyOn(manager, 'enable');

manager.enable();

expect(manager.enable).toHaveBeenCalledOnce();

// enable was not awaited so cancelled by disabled
await manager.disable();

manager.resume();

expect(manager.enable).toBeCalledTimes(2);

// this disable is not awaited, but will cancel the enable anyway
// so resume must work here too
manager.disable();

manager.resume();

expect(manager.enable).toBeCalledTimes(3);
});

it('should provide default constraints to `getStream` method', () => {
manager.setDefaultConstraints({
echoCancellation: true,
Expand Down
25 changes: 19 additions & 6 deletions packages/client/src/devices/devices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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',
);
})(),
);
};
Expand Down Expand Up @@ -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(),
Expand All @@ -134,15 +140,15 @@ export const getVideoDevices = () => {
concatMap(() => getDevices(getVideoBrowserPermission(), 'videoinput')),
shareReplay(1),
);
};
});

/**
* Prompts the user for a permission to use video devices (if not already granted
* and was not prompted before) and lists the available 'audiooutput' devices,
* 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(),
Expand All @@ -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;
};

/**
Expand Down
Loading

0 comments on commit 0329aa0

Please sign in to comment.