diff --git a/packages/client/src/Call.ts b/packages/client/src/Call.ts index 47228c55b3..68ee53ecfa 100644 --- a/packages/client/src/Call.ts +++ b/packages/client/src/Call.ts @@ -1172,6 +1172,27 @@ export class Call { }); }; + /** + * Updates the audio output level for a given sessionId (participant session) or, + * the master volume if `sessionId` is omitted. + * + * @param level the audio level [0 - 1]. + * @param sessionId an optional session id. + */ + setAudioOutputLevel = (level: number, sessionId?: string) => { + if (level < 0 || level > 1) { + throw new Error(`Audio output level must be in the [0-1] range`); + } + + if (sessionId) { + this.state.updateParticipant(sessionId, { + audioOutputLevel: level, + }); + } else { + this.state.setMasterAudioOutputLevel(level); + } + }; + /** * Sets the `audioDeviceId` property of the [`localParticipant$`](./StreamVideoClient.md/#readonlystatestore)). * diff --git a/packages/client/src/store/CallState.ts b/packages/client/src/store/CallState.ts index 2eef0974c7..9617826c15 100644 --- a/packages/client/src/store/CallState.ts +++ b/packages/client/src/store/CallState.ts @@ -82,6 +82,10 @@ export enum CallingState { * @react You don't have to use this class directly, as we are exposing the state through Hooks. */ export class CallState { + /** + * The speaker volume level that is set, if `StreamVideoParticipant.audioOutputLevel` is undefined. + */ + private masterAudioOutputLevelSubject = new BehaviorSubject(1); /** * The raw call metadata object, as defined on the backend. * @@ -165,8 +169,12 @@ export class CallState { */ private callRecordingListSubject = new BehaviorSubject([]); - // Derived state + /** + * Emits the default audio output level value in form of decimal number in range of 0-1. + */ + masterAudioOutputLevel$: Observable; + // Derived state /** * The time the call session actually started. * Useful for displaying the call duration. @@ -303,6 +311,8 @@ export class CallState { distinctUntilChanged(), ); + this.masterAudioOutputLevel$ = + this.masterAudioOutputLevelSubject.asObservable(); this.startedAt$ = this.startedAtSubject.asObservable(); this.participantCount$ = this.participantCountSubject.asObservable(); this.anonymousParticipantCount$ = @@ -473,6 +483,27 @@ export class CallState { return this.setCurrentValue(this.callingStateSubject, state); }; + /** + * Retrieves the current value of the default audio output level. + * + * @internal + */ + get masterAudioOutputLevel() { + return this.getCurrentValue(this.masterAudioOutputLevel$); + } + + /** + * Sets the current value of the default audio output level. + * + * @internal + */ + setMasterAudioOutputLevel = (level: number) => { + if (level < 0 || level > 1) { + throw new Error(`Audio output level must be in the [0-1] range`); + } + return this.setCurrentValue(this.masterAudioOutputLevelSubject, level); + }; + /** * The list of call recordings. */ diff --git a/packages/client/src/types.ts b/packages/client/src/types.ts index 73c8454ca1..8d55cdb7d0 100644 --- a/packages/client/src/types.ts +++ b/packages/client/src/types.ts @@ -34,7 +34,13 @@ export enum DebounceType { export interface StreamVideoParticipant extends Participant { /** - * The participant's audio stream, if they are publishing audio and + * The speaker volume in range 0 - 1 set by the participant. + * If not set, then CallState.masterAudioOutputLevel should be reflected. + */ + audioOutputLevel?: number; + + /** + * The participant's audio stream, if they are publishing audio, and * we have subscribed to it. */ audioStream?: MediaStream; diff --git a/packages/react-bindings/src/hooks/call.ts b/packages/react-bindings/src/hooks/call.ts index 9d07a4ea60..467b705bd5 100644 --- a/packages/react-bindings/src/hooks/call.ts +++ b/packages/react-bindings/src/hooks/call.ts @@ -131,3 +131,13 @@ export const useCallStartedAt = () => { const { startedAt$ } = useCallState(); return useObservableValue(startedAt$); }; + +/** + * Utility hook providing the default audio output level in a given call. + * + * @category Call State + */ +export const useMasterAudioOutputLevel = () => { + const { masterAudioOutputLevel$ } = useCallState(); + return useObservableValue(masterAudioOutputLevel$); +}; diff --git a/packages/react-native-sdk/docusaurus/docs/reactnative/03-core/03-call-and-participant-state.mdx b/packages/react-native-sdk/docusaurus/docs/reactnative/03-core/03-call-and-participant-state.mdx index 3796c53d96..18c8a794df 100644 --- a/packages/react-native-sdk/docusaurus/docs/reactnative/03-core/03-call-and-participant-state.mdx +++ b/packages/react-native-sdk/docusaurus/docs/reactnative/03-core/03-call-and-participant-state.mdx @@ -44,43 +44,46 @@ The `StreamCall` component uses the `StreamCallProvider` under the hood. Here are all the call-related state hooks: -| Name | Description | -| --------------------------------- | ------------------------------------------------------------------------------------------------------------- | -| `useCall` | The `Call` instance that is registered with `StreamCall`. You need the `Call` instance to initiate API calls. | -| `useIsCallRecordingInProgress` | It's' `true` if the call is being recorded. | -| `useIsCallBroadcastingInProgress` | It's `true` if the call is being broadcasted. | -| `useIsCallLive` | It's `true` if the call is currently live. | -| `useCallMembers` | The list of call members | -| `useCallCallingState` | Provides information about the call state. For example, `RINGING`, `JOINED` or `RECONNECTING`. | -| `useCallStartedAt` | The actual start time of the current call session. | -| `useCallStatsReport` | When stats gathering is enabled, this observable will emit a new value at a regular (configurable) interval. | -| `useCallMetadata` | The `CallResponse`, see below for more information. | -| `useCallRecordings` | The latest list of recordings performed during the call. | -| `useHasOngoingScreenShare` | It will return `true` if at least one participant is sharing their screen. | -| `useDominantSpeaker` | The participant that is the current dominant speaker of the call. | -| `useOwnCapabilities` | The capabilities of the local participant. | -| `useHasPermissions` | Returns `true` if the local participant has all the given permissions. | -| `useCallPermissionRequest` | The latest call permission request. | +| Name | Description | +|-----------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `useCall` | The `Call` instance that is registered with `StreamCall`. You need the `Call` instance to initiate API calls. | +| `useCallCallingState` | Provides information about the call state. For example, `RINGING`, `JOINED` or `RECONNECTING`. | +| `useCallMembers` | The list of call members | +| `useCallMetadata` | The `CallResponse`, see below for more information. | +| `useCallRecordings` | The latest list of recordings performed during the call. | +| `useCallStartedAt` | The actual start time of the current call session. | +| `useCallStatsReport` | When stats gathering is enabled, this observable will emit a new value at a regular (configurable) interval. | +| `useDominantSpeaker` | The participant that is the current dominant speaker of the call. | +| `useHasOngoingScreenShare` | It will return `true` if at least one participant is sharing their screen. | +| `useHasPermissions` | Returns `true` if the local participant has all the given permissions. | +| `useIsCallRecordingInProgress` | It's' `true` if the call is being recorded. | +| `useIsCallBroadcastingInProgress` | It's `true` if the call is being broadcasted. | +| `useIsCallLive` | It's `true` if the call is currently live. | +| `useMasterAudioOutputLevel` | The audio output level applied to all participants if `StreamVideoParticipant.audioOutputLevel` is not explicitly set. Stored as decimal number in the range of 0 - 1. Managed locally. | +| `useOwnCapabilities` | The capabilities of the local participant. | The `CallResponse` object contains the following information: -| Name | Description | -| ------------------ | ------------------------------------------------------- | -| `backstage` | It's `true` if the call is in backstage mode. | -| `blocked_user_ids` | The users who are blocked from this call. | -| `created_at` | The time the call was created. | -| `created_by` | The creator of the call. | -| `custom` | Custom data attached to the call. | -| `egress` | Broadcasting related information. | -| `ended_at` | When the call was ended. | -| `ingress` | RTMP publishing related information. | -| `recording` | It's `true` if the call is being recorded. | -| `session` | Information related to the current session of the call. | -| `settings` | The settings for this call. | -| `starts_at` | The scheduled start time of the call. | -| `team` | Team that the call is restricted to. | -| `type` | The type of the call. | -| `updated_at` | When the call was updated. | +| Name | Description | +|----------------------|---------------------------------------------------------| +| `backstage` | It's `true` if the call is in backstage mode. | +| `blocked_user_ids` | The users who are blocked from this call. | +| `cid` | The unique identifier for a call (`:`). | +| `created_at` | The time the call was created. | +| `created_by` | The creator of the call. | +| `current_session_id` | The unique identifier of the current call session. | +| `custom` | Custom data attached to the call. | +| `egress` | Broadcasting related information. | +| `ended_at` | When the call was ended. | +| `id` | The unique call identifier within the given call type. | +| `ingress` | RTMP publishing related information. | +| `recording` | It's `true` if the call is being recorded. | +| `session` | Information related to the current session of the call. | +| `settings` | The settings for this call. | +| `starts_at` | The scheduled start time of the call. | +| `team` | Team that the call is restricted to. | +| `type` | The type of the call. | +| `updated_at` | When the call was updated. | ## Participant state @@ -123,21 +126,29 @@ const CallUI = () => { The `StreamVideoParticipant` object contains the following information: -| Name | Description | -| -------------------- | --------------------------------------------------------------------------- | -| `user` | The user object for this participant. | -| `publishedTracks` | The track types the participant is currently publishing | -| `joinedAt` | The time the participant joined the call. | -| `connectionQuality` | The participant's connection quality. | -| `isSpeaking` | It's `true` if the participant is currently speaking. | -| `isDominantSpeaker` | It's `true` if the participant is the current dominant speaker in the call. | -| `audioLevel` | The audio level of the participant. | -| `audioStream` | The published audio `MediaStream`. | -| `videoStream` | The published video `MediaStream`. | -| `screenShareStream` | The published screen share `MediaStream`. | -| `isLocalParticipant` | It's `true` if the participant is the local participant. | -| `pinnedAt` | The time the participant was pinned. | -| `reaction` | The last reaction this user has sent to this call. | +| Name | Description | +|---------------------------|---------------------------------------------------------------------------------------------| +| `audioLevel` | The audio level of the participant. | +| `audioOutputLevel` | The speaker volume in range 0 - 1 set by the participant. | +| `audioStream` | The published audio `MediaStream`. | +| `connectionQuality` | The participant's connection quality. | +| `image` | The profile image of the user. | +| `isDominantSpeaker` | It's `true` if the participant is the current dominant speaker in the call. | +| `isLocalParticipant` | It's `true` if the participant is the local participant. | +| `isSpeaking` | It's `true` if the participant is currently speaking. | +| `joinedAt` | The time the participant joined the call. | +| `name` | The participant name. | +| `pinnedAt` | The time the participant was pinned. | +| `publishedTracks` | The track types the participant is currently publishing | +| `reaction` | The last reaction this user has sent to this call. | +| `roles` | The array of role names assigned to the participant in the active call. | +| `screenShareStream` | The published screen share `MediaStream`. | +| `screenShareDimension` | The preferred screen share dimensions for this participant. | +| `sessionId` | Participant's session ID. | +| `userId` | Participant's user ID. | +| `videoStream` | The published video `MediaStream`. | +| `videoDimension` | The preferred video dimensions for this participant. | +| `viewportVisibilityState` | The visibility state of the participant's video element within the pre-configured viewport. | The `StreamVideoLocalParticipant` has these additional properties: @@ -199,7 +210,6 @@ The `UserResponse` contains the following properties: | `created_at` | The time the user was created. | | `custom` | Custom user data. | | `deleted_at` | The time the user was deleted. | -| `devices` | The registered push notification devices of the user. | | `id` | The id of the user. | | `image` | The profile image of the user. | | `name` | The name of the user. | diff --git a/packages/react-sdk/docusaurus/docs/React/02-guides/03-call-and-participant-state.mdx b/packages/react-sdk/docusaurus/docs/React/02-guides/03-call-and-participant-state.mdx index 63af38f2f8..07ec42c77a 100644 --- a/packages/react-sdk/docusaurus/docs/React/02-guides/03-call-and-participant-state.mdx +++ b/packages/react-sdk/docusaurus/docs/React/02-guides/03-call-and-participant-state.mdx @@ -42,48 +42,52 @@ The `StreamCall` component uses the `StreamCallProvider` under the hood. Here are all the call-related state hooks: | Name | Description | -| --------------------------------- | ------------------------------------------------------------------------------------------------------------- | +|-----------------------------------|---------------------------------------------------------------------------------------------------------------| | `useCall` | The `Call` instance that is registered with `StreamCall`. You need the `Call` instance to initiate API calls. | -| `useIsCallRecordingInProgress` | It's' `true` if the call is being recorded. | -| `useIsCallBroadcastingInProgress` | It's `true` if the call is being broadcasted. | -| `useIsCallLive` | It's `true` if the call is currently live. | -| `useCallMembers` | The list of call members | | `useCallCallingState` | Provides information about the call state. For example, `RINGING`, `JOINED` or `RECONNECTING`. | -| `useCallStartedAt` | The actual start time of the current call session. | -| `useCallStatsReport` | When stats gathering is enabled, this observable will emit a new value at a regular (configurable) interval. | +| `useCallMembers` | The list of call members | | `useCallMetadata` | The `CallResponse`, see below for more information. | | `useCallRecordings` | The latest list of recordings performed during the call. | -| `useHasOngoingScreenShare` | It will return `true` if at least one participant is sharing their screen. | +| `useCallStartedAt` | The actual start time of the current call session. | +| `useCallStatsReport` | When stats gathering is enabled, this observable will emit a new value at a regular (configurable) interval. | | `useDominantSpeaker` | The participant that is the current dominant speaker of the call. | -| `useOwnCapabilities` | The capabilities of the local participant. | +| `useHasOngoingScreenShare` | It will return `true` if at least one participant is sharing their screen. | | `useHasPermissions` | Returns `true` if the local participant has all the given permissions. | +| `useIsCallRecordingInProgress` | It's' `true` if the call is being recorded. | +| `useIsCallBroadcastingInProgress` | It's `true` if the call is being broadcasted. | +| `useIsCallLive` | It's `true` if the call is currently live. | +| `useMasterAudioOutputLevel` | The default audio output level applied to all participants (decimal number in the range of 0 - 1). | +| `useOwnCapabilities` | The capabilities of the local participant. | The `CallResponse` object contains the following information: -| Name | Description | -| ------------------ | ------------------------------------------------------- | -| `backstage` | It's `true` if the call is in backstage mode. | -| `blocked_user_ids` | The users who are blocked from this call. | -| `created_at` | The time the call was created. | -| `created_by` | The creator of the call. | -| `custom` | Custom data attached to the call. | -| `egress` | Broadcasting related information. | -| `ended_at` | When the call was ended. | -| `ingress` | RTMP publishing related information. | -| `recording` | It's `true` if the call is being recorded. | -| `session` | Information related to the current session of the call. | -| `settings` | The settings for this call. | -| `starts_at` | The scheduled start time of the call. | -| `team` | Team that the call is restricted to. | -| `type` | The type of the call. | -| `updated_at` | When the call was updated. | +| Name | Description | +|----------------------|---------------------------------------------------------| +| `backstage` | It's `true` if the call is in backstage mode. | +| `blocked_user_ids` | The users who are blocked from this call. | +| `cid` | The unique identifier for a call (`:`). | +| `created_at` | The time the call was created. | +| `created_by` | The creator of the call. | +| `current_session_id` | The unique identifier of the current call session. | +| `custom` | Custom data attached to the call. | +| `egress` | Broadcasting related information. | +| `ended_at` | When the call was ended. | +| `id` | The unique call identifier within the given call type. | +| `ingress` | RTMP publishing related information. | +| `recording` | It's `true` if the call is being recorded. | +| `session` | Information related to the current session of the call. | +| `settings` | The settings for this call. | +| `starts_at` | The scheduled start time of the call. | +| `team` | Team that the call is restricted to. | +| `type` | The type of the call. | +| `updated_at` | When the call was updated. | ## Participant state If you want to display information about the joined participants of the call you can use these hooks: | Name | Description | -| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|--------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `useLocalParticipant` | The local participant is the logged-in user. | | `useRemoteParticipants` | All participants except the local participant. | | `useParticipants` | All participants, including local and remote participants. | @@ -116,21 +120,29 @@ const CallUI = () => { The `StreamVideoParticipant` object contains the following information: -| Name | Description | -| -------------------- | --------------------------------------------------------------------------- | -| `user` | The user object for this participant. | -| `publishedTracks` | The track types the participant is currently publishing | -| `joinedAt` | The time the participant joined the call. | -| `connectionQuality` | The participant's connection quality. | -| `isSpeaking` | It's `true` if the participant is currently speaking. | -| `isDominantSpeaker` | It's `true` if the participant is the current dominant speaker in the call. | -| `audioLevel` | The audio level of the participant. | -| `audioStream` | The published audio `MediaStream`. | -| `videoStream` | The published video `MediaStream`. | -| `screenShareStream` | The published screen share `MediaStream`. | -| `isLocalParticipant` | It's `true` if the participant is the local participant. | -| `pinnedAt` | The time the participant was pinned. | -| `reaction` | The last reaction this user has sent to this call. | +| Name | Description | +|---------------------------|---------------------------------------------------------------------------------------------| +| `audioLevel` | The audio level of the participant. | +| `audioOutputLevel` | The speaker volume in range 0 - 1 set by the participant. | +| `audioStream` | The published audio `MediaStream`. | +| `connectionQuality` | The participant's connection quality. | +| `image` | The profile image of the user. | +| `isDominantSpeaker` | It's `true` if the participant is the current dominant speaker in the call. | +| `isLocalParticipant` | It's `true` if the participant is the local participant. | +| `isSpeaking` | It's `true` if the participant is currently speaking. | +| `joinedAt` | The time the participant joined the call. | +| `name` | The participant name. | +| `pinnedAt` | The time the participant was pinned. | +| `publishedTracks` | The track types the participant is currently publishing | +| `reaction` | The last reaction this user has sent to this call. | +| `roles` | The array of role names assigned to the participant in the active call. | +| `screenShareStream` | The published screen share `MediaStream`. | +| `screenShareDimension` | The preferred screen share dimensions for this participant. | +| `sessionId` | Participant's session ID. | +| `userId` | Participant's user ID. | +| `videoStream` | The published video `MediaStream`. | +| `videoDimension` | The preferred video dimensions for this participant. | +| `viewportVisibilityState` | The visibility state of the participant's video element within the pre-configured viewport. | The `StreamVideoLocalParticipant` has these additional properties: @@ -182,7 +194,6 @@ The `UserResponse` contains the following properties: | `created_at` | The time the user was created. | | `custom` | Custom user data. | | `deleted_at` | The time the user was deleted. | -| `devices` | The registered push notification devices of the user. | | `id` | The id of the user. | | `image` | The profile image of the user. | | `name` | The name of the user. | diff --git a/packages/react-sdk/docusaurus/docs/React/02-guides/04-camera-and-microphone.mdx b/packages/react-sdk/docusaurus/docs/React/02-guides/04-camera-and-microphone.mdx index e2a1e09e4c..d59b979d0b 100644 --- a/packages/react-sdk/docusaurus/docs/React/02-guides/04-camera-and-microphone.mdx +++ b/packages/react-sdk/docusaurus/docs/React/02-guides/04-camera-and-microphone.mdx @@ -181,6 +181,36 @@ console.log('Audio output devices: ', audioOutputDevices); switchDevice('audiooutput', ''); ``` +### Speaker device volume + +The speaker device volume can be set on the master level for all the participants as well as for a selected participant. The master audio output level is stored in `Call` state and can be retrieved using the `useMasterAudioOutputLevel` hook. The level for a specific participant should be retrieved per `StreamVideoParticipant.audioOutputLevel`. + +The volume can then be set to SDK's `Audio` component: + +```tsx +const CustomComponent = ({participant}: {participant: StreamVideoParticipant}) => { + const masterAudioOutputLevel = useMasterAudioOutputLevel(); + const localParticipant = useLocalParticipant(); + + return ( +