From 5332970dcf526b538ea2d3f01320f7eb0c262efe Mon Sep 17 00:00:00 2001 From: Timo Date: Tue, 3 Jun 2025 13:39:21 +0200 Subject: [PATCH] add onAudioTrackReady callback for controls --- docs/controls.md | 2 ++ src/controls.ts | 9 ++++++++- src/livekit/MatrixAudioRenderer.tsx | 3 ++- src/useAudioContext.tsx | 2 ++ 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/docs/controls.md b/docs/controls.md index bb457237..e5bb3f90 100644 --- a/docs/controls.md +++ b/docs/controls.md @@ -19,3 +19,5 @@ On mobile platforms (iOS, Android), web views do not reliably support selecting - `controls.setAudioEnabled(enabled: boolean)` Enables/disables all audio output from the application. Output is enabled by default. - `showNativeAudioDevicePicker: (() => void) | undefined`. Callback called whenever the user presses the output button in the settings menu. This button is only shown on iOS. (`userAgent.includes("iPhone")`) +- `controls.onAudioPlaybackStarted: ((id: string) => void) | undefined`: This will be called the first time we start + playing audio in the webview. It can be helpful to do device setup on the native app when the webviews audio is ready. diff --git a/src/controls.ts b/src/controls.ts index 320f41ca..b5209ab0 100644 --- a/src/controls.ts +++ b/src/controls.ts @@ -20,6 +20,7 @@ export interface Controls { /** @deprecated use onAudioDeviceSelect instead*/ onOutputDeviceSelect?: (id: string) => void; onAudioDeviceSelect?: (id: string) => void; + onAudioPlaybackStarted?: () => void; /** @deprecated use setAudioEnabled instead*/ setOutputEnabled(enabled: boolean): void; setAudioEnabled(enabled: boolean): void; @@ -54,7 +55,13 @@ export const outputDevice$ = new BehaviorSubject(undefined); * This should also be used to display a darkened overlay screen letting the user know that audio is muted. */ export const setAudioEnabled$ = new Subject(); - +let playbackStartedEmitted = false; +export const setPlaybackStarted = (): void => { + if (!playbackStartedEmitted) { + playbackStartedEmitted = true; + window.controls.onAudioPlaybackStarted?.(); + } +}; window.controls = { canEnterPip(): boolean { return setPipEnabled$.observed; diff --git a/src/livekit/MatrixAudioRenderer.tsx b/src/livekit/MatrixAudioRenderer.tsx index 18f09106..3e7a3e89 100644 --- a/src/livekit/MatrixAudioRenderer.tsx +++ b/src/livekit/MatrixAudioRenderer.tsx @@ -18,7 +18,7 @@ import { logger } from "matrix-js-sdk/lib/logger"; import { useEarpieceAudioConfig } from "./MediaDevicesContext"; import { useReactiveState } from "../useReactiveState"; - +import * as controls from "../controls"; export interface MatrixAudioRendererProps { /** * The list of participants to render audio for. @@ -204,6 +204,7 @@ function AudioTrackWithAudioNodes({ useContext ? [audioNodes.gain!, audioNodes.pan!] : [], ); setTrackReady(true); + controls.setPlaybackStarted(); }, [audioContext, audioNodes, setTrackReady, trackReady, trackRef]); return ( diff --git a/src/useAudioContext.tsx b/src/useAudioContext.tsx index 00cea2fc..39e221ef 100644 --- a/src/useAudioContext.tsx +++ b/src/useAudioContext.tsx @@ -19,6 +19,7 @@ import { import { type PrefetchedSounds } from "./soundUtils"; import { useUrlParams } from "./UrlParams"; import { useInitial } from "./useInitial"; +import * as controls from "./controls"; /** * Play a sound though a given AudioContext. Will take @@ -43,6 +44,7 @@ async function playSound( src.buffer = buffer; src.connect(gain).connect(pan).connect(ctx.destination); const p = new Promise((r) => src.addEventListener("ended", () => r())); + controls.setPlaybackStarted(); src.start(); return p; }