Add sounds for ringing (#3490)

* add wait for pickup overlay

Signed-off-by: Timo K <toger5@hotmail.de>

* refactor and leave logic

Signed-off-by: Timo K <toger5@hotmail.de>

* recursive play sound logic

Signed-off-by: Timo K <toger5@hotmail.de>

* review

Signed-off-by: Timo K <toger5@hotmail.de>

* text color

Signed-off-by: Timo K <toger5@hotmail.de>

* overlay styling and interval fixes

Signed-off-by: Timo K <toger5@hotmail.de>

* fix permissions and styling

Signed-off-by: Timo K <toger5@hotmail.de>

* fix always getting pickup sound

Signed-off-by: Timo K <toger5@hotmail.de>

* Add sound effects for declined,timeout and ringtone

* better ringtone

* Integrate sounds

* Ensure leave sound does not play

* Remove unused blocked sound

* fix test

* Improve tests

* Loop ring sound inside Audio context for better perf.

* lint

* better ringtone

* Update to delay ringtone logic.

* lint + fix test

* Tidy up ring sync and add comments.

* lint

* Refactor onLeave to take a sound so we don't need to repeat the sound

* fix import

---------

Signed-off-by: Timo K <toger5@hotmail.de>
Co-authored-by: Timo K <toger5@hotmail.de>
This commit is contained in:
Will Hunt
2025-09-15 15:41:15 +01:00
committed by GitHub
parent 76465d0e63
commit e201258af3
18 changed files with 207 additions and 54 deletions

View File

@@ -49,6 +49,7 @@ import {
race,
scan,
skip,
skipWhile,
startWith,
switchAll,
switchMap,
@@ -853,17 +854,6 @@ export class CallViewModel extends ViewModel {
throttleTime(THROTTLE_SOUND_EFFECT_MS),
);
public readonly leaveSoundEffect$ = this.userMedia$.pipe(
pairwise(),
filter(
([prev, current]) =>
current.length <= MAX_PARTICIPANT_COUNT_FOR_SOUND &&
current.length < prev.length,
),
map(() => {}),
throttleTime(THROTTLE_SOUND_EFFECT_MS),
);
/**
* The number of participants currently in the call.
*
@@ -963,7 +953,9 @@ export class CallViewModel extends ViewModel {
* - "success": Someone else joined. The call is in a normal state. No audiovisual feedback.
* - null: EC is configured to never show any waiting for answer state.
*/
public readonly callPickupState$ = this.options.waitForCallPickup
public readonly callPickupState$: Behavior<
"unknown" | "ringing" | "timeout" | "decline" | "success" | null
> = this.options.waitForCallPickup
? this.scope.behavior<
"unknown" | "ringing" | "timeout" | "decline" | "success"
>(
@@ -983,6 +975,24 @@ export class CallViewModel extends ViewModel {
)
: constant(null);
public readonly leaveSoundEffect$ = combineLatest([
this.callPickupState$,
this.userMedia$,
]).pipe(
// Until the call is successful, do not play a leave sound.
// If callPickupState$ is null, then we always play the sound as it will not conflict with a decline sound.
skipWhile(([c]) => c !== null && c !== "success"),
map(([, userMedia]) => userMedia),
pairwise(),
filter(
([prev, current]) =>
current.length <= MAX_PARTICIPANT_COUNT_FOR_SOUND &&
current.length < prev.length,
),
map(() => {}),
throttleTime(THROTTLE_SOUND_EFFECT_MS),
);
/**
* List of MediaItems that we want to display, that are of type ScreenShare
*/