Direct Streaming: Viewer
Introduction
Direct Streaming facilitates personalized, real-time video interactions between a broadcaster and select viewers. This guide provides a comprehensive walkthrough for integrating the viewer component of Direct Streaming into your application using Native Frame's SDK.
Key Concepts
- Direct Streaming: A private broadcast where selected viewers can join and broadcast themselves simultaneously.
- Encoder: Handles video capture and broadcasting for the viewer.
- Manifest Player: Displays the broadcaster's stream to the viewer.
- VideoClient: Manages the connection and streaming process.
Prerequisites
Before you begin, ensure you have the following:
- Native Frame SDK installed in your project
- Basic understanding of React and React Hooks
- Familiarity with TypeScript (optional but recommended)
- A valid
callId
from an active Direct Streaming broadcast
Implementation Steps
Step 1: Set Up the VideoClient
First, create a custom hook to manage the VideoClient instance:
import { useEffect, useState } from 'react';
import { types, VideoClient, CallState } from "@video/video-client-web";
export function useVideoClient() {
const [vc, setVc] = useState<types.VideoClient | null>(null);
const [callState, setCallState] = useState<CallState | null>(null);
useEffect(() => {
if (!vc) {
const vcViewerOptions: types.VideoClientOptions = {
backendEndpoints: [backendEndpoint],
token: tokenRefresher({
backendEndpoint,
authUrl: `${backendEndpoint}/api/demo/v1/access-token`,
streamKey,
scope: "private-viewer",
clientReferrer,
}),
};
const newVc = new VideoClient(vcViewerOptions);
setVc(newVc);
setCallState(new CallState());
}
return () => {
if (vc) {
vc.dispose();
setVc(null);
}
};
}, [backendEndpoint, streamKey, clientReferrer]);
return { vc, callState };
}
Step 2: Create the Encoder UI State
Set up the EncoderUiState for the viewer's broadcast:
import { EncoderUiState, mediaController } from "@video/video-client-web";
export function useEncoderUi() {
const [encoderUi, setEncoderUi] = useState<EncoderUiState | null>(null);
useEffect(() => {
if (!encoderUi) {
(async () => {
await mediaController.init();
const mediaStreamController = await mediaController.requestController();
setEncoderUi(new EncoderUiState(mediaStreamController));
})();
}
return () => {
if (encoderUi) {
encoderUi.dispose();
setEncoderUi(null);
}
};
}, [encoderUi]);
return encoderUi;
}
Step 3: Create the Encoder Component
Implement the Encoder
component for the viewer's broadcast:
import React from 'react';
import {
CameraButton,
ControlBar,
EncoderVideo,
JoinBroadcastButton,
MediaContainer,
MicrophoneButton,
VideoClientContext,
EncoderUiContext,
CallContext,
} from "@video/video-client-web";
const Encoder: React.FC<{
encoderUi: EncoderUiState;
videoclient: types.VideoClient | null;
callId: string;
callState: CallState | null;
}> = ({ encoderUi, videoclient, callId, callState }) => {
return (
<VideoClientContext.Provider value={videoclient}>
<CallContext.Provider value={callState}>
<EncoderUiContext.Provider value={encoderUi}>
<MediaContainer>
<EncoderVideo />
<ControlBar variant="encoder">
<JoinBroadcastButton
callId={callId}
broadcastOptions={{
streamName: "demo",
}}
/>
<CameraButton />
<MicrophoneButton />
</ControlBar>
</MediaContainer>
</EncoderUiContext.Provider>
</CallContext.Provider>
</VideoClientContext.Provider>
);
};
export default Encoder;
Step 4: Create the Custom Manifest Player Component
Implement the CustomManifest
component to display the broadcaster's stream:
import React, { useEffect, useState } from 'react';
import {
ControlBar,
PlayerUiContext,
MediaContainer,
PlayerAudioButton,
PlayerGetSoundButton,
PlayerPlayButton,
PlayerUiState,
PlayerVideo,
PlayerVolumeRange,
types,
} from "@video/video-client-web";
const CustomManifest: React.FC<{
vc: types.VideoClient | null,
manifestUrl: string
}> = ({ vc, manifestUrl }) => {
const [playerUi, setPlayerUi] = useState<PlayerUiState | null>(null);
useEffect(() => {
if (manifestUrl && !playerUi && vc) {
const player = vc.requestPlayer(manifestUrl);
setPlayerUi(new PlayerUiState(player));
}
return () => {
if (playerUi) {
playerUi.dispose();
setPlayerUi(null);
}
};
}, [manifestUrl, playerUi, vc]);
if (!playerUi) return null;
return (
<PlayerUiContext.Provider value={playerUi}>
<MediaContainer>
<PlayerGetSoundButton />
<PlayerVideo />
<ControlBar variant="player">
<PlayerVolumeRange />
<PlayerAudioButton />
<PlayerPlayButton />
</ControlBar>
</MediaContainer>
</PlayerUiContext.Provider>
);
};
export default CustomManifest;
Step 5: Implement the Broadcast Viewer Component
Create a BroadcastViewer
component that utilizes the hooks we've created:
import React from 'react';
import { PlayerUiState } from "@video/video-client-web";
import Encoder from './Encoder';
import CustomManifest from './CustomManifest';
const BroadcastViewer: React.FC<{ callId: string, manifestUrl: string }> = ({ callId, manifestUrl }) => {
const { vc, callState } = useVideoClient();
const encoderUi = useEncoderUi();
return (
<>
{encoderUi && (
<Encoder
callId={callId}
encoderUi={encoderUi}
videoclient={vc}
callState={callState}
/>
)}
<CustomManifest vc={vc} manifestUrl={manifestUrl} />
</>
);
};
export default BroadcastViewer;
Usage
To use the Direct Streaming Viewer in your application:
- Import the
BroadcastViewer
component into your main application file. - Render the
BroadcastViewer
component where you want the viewing interface to appear, providing the necessarycallId
andmanifestUrl
.
import React from 'react';
import BroadcastViewer from './BroadcastViewer';
const App: React.FC = () => {
const callId = "your-call-id";
const manifestUrl = "your-manifest-url";
return (
<div className="App">
<h1>Direct Streaming Viewer</h1>
<BroadcastViewer callId={callId} manifestUrl={manifestUrl} />
</div>
);
};
export default App;