Platform
Amazon IVS Integration
Overview
Integrate the Camera Kit Web SDK seamlessly with Amazon IVS for an enhanced live streaming and interactive camera experience.
index.html
<html>
<head>
<title>Snap Camera Kit + Amazon IVS</title>
</head>
<body>
<div class="container">
<h1>Snap Camera Kit + Amazon IVS</h1>
<canvas id="canvas"></canvas>
<div class="settings">
<div class="item">
<label for="endpoint">Ingest Endpoint</label>
<input id="endpoint" placeholder="Enter your ingest endpoint" />
</div>
<div class="item">
<label for="key">Stream Key</label>
<input id="key" placeholder="Enter your stream key" />
</div>
<div class="item">
<label for="mics">Microphone</label>
<select id="mics"></select>
</div>
<div class="item">
<label for="cameras">Camera</label>
<select id="cameras"></select>
</div>
<div class="item">
<label for="lenses">Lens</label>
<select id="lenses"></select>
</div>
</div>
<div class="buttons">
<button disabled id="start">Start Broadcast</button>
<button disabled id="stop">Stop Broadcast</button>
</div>
</div>
<script type="module" src="./script.ts"></script>
</body>
</html>
script.ts
import IVSBroadcastClient from 'amazon-ivs-web-broadcast';
import {
bootstrapCameraKit,
CameraKitSession,
createMediaStreamSource,
Transform2D,
Lens,
} from '@snap/camera-kit';
// Element Selection
const liveRenderTarget = document.getElementById('canvas') as HTMLCanvasElement;
const lensSelect = document.getElementById('lenses') as HTMLSelectElement;
const cameraSelect = document.getElementById('cameras') as HTMLSelectElement;
const micSelect = document.getElementById('mics') as HTMLSelectElement;
const start = document.getElementById('start') as HTMLButtonElement;
const stop = document.getElementById('stop') as HTMLButtonElement;
const endpoint = document.getElementById('endpoint') as HTMLInputElement;
const key = document.getElementById('key') as HTMLInputElement;
// Camera Kit Setup
let mediaStream: MediaStream;
async function initCameraKit(): Promise<MediaStream> {
const cameraKit = await bootstrapCameraKit({
apiToken: '<API_TOKEN>',
});
const session = await cameraKit.createSession({ liveRenderTarget });
const { lenses } = await cameraKit.lensRepository.loadLensGroups([
'<LENS_GROUP_ID>',
]);
session.applyLens(lenses[0]);
attachCamerasToSelect(session);
attachLensesToSelect(lenses, session);
return liveRenderTarget.captureStream();
}
async function setCameraKitSource(session: CameraKitSession, deviceId: string) {
if (mediaStream) {
session.pause();
mediaStream.getVideoTracks()[0].stop();
}
mediaStream = await navigator.mediaDevices.getUserMedia({
video: {
deviceId,
width: {
ideal: IVSBroadcastClient.BASIC_LANDSCAPE.maxResolution.width,
max: IVSBroadcastClient.BASIC_LANDSCAPE.maxResolution.width,
},
height: {
ideal: IVSBroadcastClient.BASIC_LANDSCAPE.maxResolution.height,
max: IVSBroadcastClient.BASIC_LANDSCAPE.maxResolution.height,
},
},
audio: false,
});
const source = createMediaStreamSource(mediaStream);
await session.setSource(source);
source.setTransform(Transform2D.MirrorX);
session.play();
}
async function attachCamerasToSelect(session: CameraKitSession) {
const devices = await navigator.mediaDevices.enumerateDevices();
const cameras = devices.filter(({ kind }) => kind === 'videoinput');
cameras.forEach((camera) => {
const option = document.createElement('option');
option.value = camera.deviceId;
option.text = camera.label;
cameraSelect.appendChild(option);
});
await setCameraKitSource(session, cameras[0].deviceId);
cameraSelect.addEventListener('change', (event) => {
const deviceId = (event.target as HTMLSelectElement).selectedOptions[0]
.value;
setCameraKitSource(session, deviceId);
});
}
async function attachLensesToSelect(lenses: Lens[], session: CameraKitSession) {
lenses.forEach((lens) => {
const option = document.createElement('option');
option.value = lens.id;
option.text = lens.name;
lensSelect.appendChild(option);
});
lensSelect.addEventListener('change', (event) => {
const lensId = (event.target as HTMLSelectElement).selectedOptions[0].value;
const lens = lenses.find((lens) => lens.id === lensId);
if (lens) session.applyLens(lens);
});
}
// Amazon IVS Setup
async function initAmazonIVS(videoMediaStream: MediaStream) {
const client = IVSBroadcastClient.create({
streamConfig: IVSBroadcastClient.BASIC_LANDSCAPE,
});
await attachAudioDevicesToSelect(client);
client.on(
IVSBroadcastClient.BroadcastClientEvents.ACTIVE_STATE_CHANGE,
// @ts-expect-error
(active: boolean) => {
start.disabled = active;
stop.disabled = !active;
}
);
client.addVideoInputDevice(videoMediaStream, 'camera1', { index: 0 });
start.addEventListener('click', () => startBroadcast(client));
stop.addEventListener('click', () => stopBroadcast(client));
key.addEventListener('input', handleAmazonConfigChange, true);
endpoint.addEventListener('input', handleAmazonConfigChange, true);
}
async function attachAudioDevicesToSelect(
client: IVSBroadcastClient.AmazonIVSBroadcastClient
) {
const devices = await navigator.mediaDevices.enumerateDevices();
const mics = devices.filter(({ kind }) => kind === 'audioinput');
mics.forEach((mic) => {
const option = document.createElement('option');
option.value = mic.deviceId;
option.text = mic.label;
micSelect.appendChild(option);
});
addAudioInputDevice(mics[0].deviceId);
micSelect.addEventListener('change', async (event) => {
const deviceId = (event.target as HTMLSelectElement).selectedOptions[0]
.value;
await addAudioInputDevice(deviceId);
});
async function addAudioInputDevice(deviceId: string) {
const audioMediaStream = await navigator.mediaDevices.getUserMedia({
audio: {
deviceId,
},
});
client.addAudioInputDevice(audioMediaStream, 'mic1');
}
}
function handleAmazonConfigChange() {
start.disabled = !(key.value && endpoint.value);
}
function startBroadcast(client: IVSBroadcastClient.AmazonIVSBroadcastClient) {
client.startBroadcast(key.value, endpoint.value);
}
function stopBroadcast(client: IVSBroadcastClient.AmazonIVSBroadcastClient) {
client.stopBroadcast();
}
// Init
initCameraKit().then(initAmazonIVS);
Was this page helpful?