Skip to content

Commit

Permalink
feat: handle multiple audio streams
Browse files Browse the repository at this point in the history
  • Loading branch information
martinstark committed Apr 10, 2024
1 parent b476854 commit 57afadc
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 76 deletions.
12 changes: 3 additions & 9 deletions src/components/production-line/production-line.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { useAudioInput } from "./use-audio-input.ts";
import { useRtcConnection } from "./use-rtc-connection.ts";
import { useEstablishSession } from "./use-establish-session.ts";
import { ActionButton } from "../landing-page/form-elements.tsx";
import { useAudioElement } from "./use-audio-element.ts";
import { UserList } from "./user-list.tsx";
import { API } from "../../api/api.ts";
import { noop } from "../../helpers.ts";
Expand All @@ -23,10 +22,6 @@ export const ProductionLine: FC = () => {
{ name: string; sessionid: string }[] | null
>(null);

const { playbackState, audioElement } = useAudioElement({
audioContainerRef,
});

const inputAudioStream = useAudioInput({
inputId: joinProductionOptions?.audioinput ?? null,
});
Expand All @@ -35,12 +30,11 @@ export const ProductionLine: FC = () => {
joinProductionOptions,
});

const { connectionState } = useRtcConnection({
const { connectionState, audioElements } = useRtcConnection({
inputAudioStream,
sdpOffer,
joinProductionOptions,
sessionId,
audioElement,
});

// Participant list, TODO extract hook to separate file
Expand Down Expand Up @@ -91,8 +85,8 @@ export const ProductionLine: FC = () => {
</TempDiv>
<TempDiv>Production View</TempDiv>
<TempDiv ref={audioContainerRef} />
{playbackState && (
<TempDiv>Audio Playback State: {playbackState}</TempDiv>
{audioElements.length && (
<TempDiv>Incoming Audio Channels: {audioElements.length}</TempDiv>
)}
{connectionState && (
<TempDiv>RTC Connection State: {connectionState}</TempDiv>
Expand Down
51 changes: 0 additions & 51 deletions src/components/production-line/use-audio-element.ts

This file was deleted.

55 changes: 39 additions & 16 deletions src/components/production-line/use-rtc-connection.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Dispatch, useEffect, useState } from "react";
import { Dispatch, SetStateAction, useEffect, useState } from "react";
import { noop } from "../../helpers";
import { API } from "../../api/api.ts";
import { TJoinProductionOptions } from "./types.ts";
Expand All @@ -11,16 +11,15 @@ type TRtcConnectionOptions = {
sdpOffer: string | null;
joinProductionOptions: TJoinProductionOptions | null;
sessionId: string | null;
audioElement: HTMLAudioElement;
};

type TEstablishConnection = {
rtcPeerConnection: RTCPeerConnection;
sdpOffer: string;
joinProductionOptions: TJoinProductionOptions;
sessionId: string;
audioElement: HTMLAudioElement;
dispatch: Dispatch<TGlobalStateAction>;
setAudioElements: Dispatch<SetStateAction<HTMLAudioElement[]>>;
};

type TAttachAudioStream = {
Expand All @@ -41,20 +40,30 @@ const establishConnection = ({
sdpOffer,
joinProductionOptions,
sessionId,
audioElement,
dispatch,
setAudioElements,
}: TEstablishConnection): { teardown: () => void } => {
const onRtcTrack = ({ streams }: RTCTrackEvent) => {
// We can count on there being only a single stream for now.
// Needs updating if a video stream is also added.
// We can count on there being only a single stream per event for now.
const selectedStream = streams[0];

if (selectedStream) {
if (selectedStream.getAudioTracks().length !== 0) {
// Add incoming stream to output audio element
// eslint-disable-next-line no-param-reassign
audioElement.srcObject = selectedStream;
}
if (selectedStream && selectedStream.getAudioTracks().length !== 0) {
const audioElement = new Audio();

audioElement.controls = false;
audioElement.autoplay = true;
audioElement.onerror = () => {
dispatch({
type: "ERROR",
payload: new Error(
`Audio Error: ${audioElement.error?.code} - ${audioElement.error?.message}`
),
});
};

audioElement.srcObject = selectedStream;

setAudioElements((prevArray) => [audioElement, ...prevArray]);
} else {
// TODO handle error case of 0 available streams
}
Expand Down Expand Up @@ -139,14 +148,27 @@ export const useRtcConnection = ({
sdpOffer,
joinProductionOptions,
sessionId,
audioElement,
}: TRtcConnectionOptions) => {
const [rtcPeerConnection] = useState<RTCPeerConnection>(
() => new RTCPeerConnection()
);
const [, dispatch] = useGlobalState();
const [connectionState, setConnectionState] =
useState<RTCPeerConnectionState | null>(null);
const [audioElements, setAudioElements] = useState<HTMLAudioElement[]>([]);

// Teardown
useEffect(
() => () => {
audioElements.forEach((el) => {
console.log("Tearing down audio element");
el.pause();
// eslint-disable-next-line no-param-reassign
el.srcObject = null;
});
},
[audioElements]
);

useEffect(() => {
if (
Expand All @@ -158,6 +180,8 @@ export const useRtcConnection = ({
return noop;
}

console.log("Setting up RTC Peer Connection");

const onConnectionStateChange = () => {
setConnectionState(rtcPeerConnection.connectionState);
};
Expand All @@ -181,8 +205,8 @@ export const useRtcConnection = ({
sdpOffer,
joinProductionOptions,
sessionId,
audioElement,
dispatch,
setAudioElements,
});

return () => {
Expand All @@ -201,7 +225,6 @@ export const useRtcConnection = ({
sessionId,
joinProductionOptions,
rtcPeerConnection,
audioElement,
dispatch,
]);

Expand Down Expand Up @@ -268,5 +291,5 @@ export const useRtcConnection = ({
};
}, [rtcPeerConnection]);

return { connectionState };
return { connectionState, audioElements };
};

0 comments on commit 57afadc

Please sign in to comment.