View a markdown version of this page

Menggunakan Snap dengan IVS Broadcast SDK - Amazon IVS

Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.

Menggunakan Snap dengan IVS Broadcast SDK

Dokumen ini menjelaskan cara menggunakan SDK Kit Kamera Snap dengan SDK siaran IVS.

Web

Bagian ini mengasumsikan Anda sudah terbiasa dengan penerbitan dan berlangganan video menggunakan SDK Siaran Web.

Untuk mengintegrasikan SDK Kit Kamera Snap dengan SDK siaran Web streaming real-time IVS, Anda perlu:

  1. Instal Camera Kit SDK dan Webpack. (Contoh kami menggunakan Webpack sebagai bundler, tetapi Anda dapat menggunakan bundler pilihan Anda.)

  2. Buatindex.html.

  3. Tambahkan elemen pengaturan.

  4. Buatindex.css.

  5. Tampilkan dan atur peserta.

  6. Tampilkan kamera dan mikrofon yang terhubung.

  7. Buat sesi Camera Kit.

  8. Ambil lensa dan isi pemilih lensa.

  9. Render output dari sesi Camera Kit ke kanvas.

  10. Buat fungsi untuk mengisi dropdown Lens.

  11. Berikan Camera Kit dengan sumber media untuk rendering dan publikasi aLocalStageStream.

  12. Buatpackage.json.

  13. Buat file konfigurasi Webpack.

  14. Siapkan server HTTPS dan uji.

Masing-masing langkah ini dijelaskan di bawah ini.

Instal Camera Kit SDK dan Webpack

Dalam contoh ini kami menggunakan Webpack sebagai bundler kami; Namun, Anda dapat menggunakan bundler apa pun.

npm i @snap/camera-kit webpack webpack-cli

Buat index.html

Selanjutnya, buat boilerplate HTML dan impor SDK siaran Web sebagai tag skrip. Dalam kode berikut, pastikan untuk mengganti <SDK version> dengan versi SDK siaran yang Anda gunakan.

<!-- /*! Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Amazon IVS Real-Time Streaming Web Sample (HTML and JavaScript)</title> <!-- Fonts and Styling --> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300italic,700,700italic" /> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.css" /> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/milligram/1.4.1/milligram.css" /> <link rel="stylesheet" href="./index.css" /> <!-- Stages in Broadcast SDK --> <script src="https://web-broadcast.live-video.net/<SDK version>/amazon-ivs-web-broadcast.js"></script> </head> <body> <!-- Introduction --> <header> <h1>Amazon IVS Real-Time Streaming Web Sample (HTML and JavaScript)</h1> <p>This sample is used to demonstrate basic HTML / JS usage. <b><a href="https://docs.aws.amazon.com/ivs/latest/LowLatencyUserGuide/multiple-hosts.html">Use the AWS CLI</a></b> to create a <b>Stage</b> and a corresponding <b>ParticipantToken</b>. Multiple participants can load this page and put in their own tokens. You can <b><a href="https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-guides/stages#glossary" target="_blank">read more about stages in our public docs.</a></b></p> </header> <hr /> <!-- Setup Controls --> <!-- Display Local Participants --> <!-- Lens Selector --> <!-- Display Remote Participants --> <!-- Load All Desired Scripts -->

Tambahkan Elemen Pengaturan

Buat HTML untuk memilih kamera, mikrofon, dan lensa dan menentukan token peserta:

<!-- Setup Controls --> <div class="row"> <div class="column"> <label for="video-devices">Select Camera</label> <select disabled id="video-devices"> <option selected disabled>Choose Option</option> </select> </div> <div class="column"> <label for="audio-devices">Select Microphone</label> <select disabled id="audio-devices"> <option selected disabled>Choose Option</option> </select> </div> <div class="column"> <label for="token">Participant Token</label> <input type="text" id="token" name="token" /> </div> <div class="column" style="display: flex; margin-top: 1.5rem"> <button class="button" style="margin: auto; width: 100%" id="join-button">Join Stage</button> </div> <div class="column" style="display: flex; margin-top: 1.5rem"> <button class="button" style="margin: auto; width: 100%" id="leave-button">Leave Stage</button> </div> </div>

Tambahkan HTML tambahan di bawahnya untuk menampilkan umpan kamera dari peserta lokal dan jarak jauh:

<!-- Local Participant --> <div class="row local-container"> <canvas id="canvas"></canvas> <div class="column" id="local-media"></div> <div class="static-controls hidden" id="local-controls"> <button class="button" id="mic-control">Mute Mic</button> <button class="button" id="camera-control">Mute Camera</button> </div> </div> <hr style="margin-top: 5rem"/> <!-- Remote Participants --> <div class="row"> <div id="remote-media"></div> </div>

Muat logika tambahan, termasuk metode pembantu untuk mengatur kamera dan JavaScript file yang dibundel. (Kemudian di bagian ini, Anda akan membuat file- JavaScript file ini dan menggabungkannya menjadi satu file, sehingga Anda dapat mengimpor Camera Kit sebagai modul. JavaScript File yang dibundel akan berisi logika untuk mengatur Kit Kamera, menerapkan Lensa, dan menerbitkan umpan kamera dengan Lensa yang diterapkan ke panggung.) Tambahkan tag penutup untuk html elemen body dan untuk menyelesaikan pembuatanindex.html.

<!-- Load all Desired Scripts --> <script src="./helpers.js"></script> <script src="./media-devices.js"></script> <!-- <script type="module" src="./stages-simple.js"></script> --> <script src="./dist/bundle.js"></script> </body> </html>

Buat index.css

Buat file sumber CSS untuk menata halaman. Kami tidak akan membahas kode ini untuk fokus pada logika untuk mengelola Stage dan mengintegrasikan dengan SDK Camera Kit Snap.

/*! Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ html, body { margin: 2rem; box-sizing: border-box; height: 100vh; max-height: 100vh; display: flex; flex-direction: column; } hr { margin: 1rem 0; } table { display: table; } canvas { margin-bottom: 1rem; background: green; } video { margin-bottom: 1rem; background: black; max-width: 100%; max-height: 150px; } .log { flex: none; height: 300px; } .content { flex: 1 0 auto; } .button { display: block; margin: 0 auto; } .local-container { position: relative; } .static-controls { position: absolute; margin-left: auto; margin-right: auto; left: 0; right: 0; bottom: -4rem; text-align: center; } .static-controls button { display: inline-block; } .hidden { display: none; } .participant-container { display: flex; align-items: center; justify-content: center; flex-direction: column; margin: 1rem; } video { border: 0.5rem solid #555; border-radius: 0.5rem; } .placeholder { background-color: #333333; display: flex; text-align: center; margin-bottom: 1rem; } .placeholder span { margin: auto; color: white; } #local-media { display: inline-block; width: 100vw; } #local-media video { max-height: 300px; } #remote-media { display: flex; justify-content: center; align-items: center; flex-direction: row; width: 100%; } #lens-selector { width: 100%; margin-bottom: 1rem; }

Menampilkan dan Mengatur Peserta

Selanjutnya, buathelpers.js, yang berisi metode pembantu yang akan Anda gunakan untuk menampilkan dan mengatur peserta:

/*! Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ function setupParticipant({ isLocal, id }) { const groupId = isLocal ? 'local-media' : 'remote-media'; const groupContainer = document.getElementById(groupId); const participantContainerId = isLocal ? 'local' : id; const participantContainer = createContainer(participantContainerId); const videoEl = createVideoEl(participantContainerId); participantContainer.appendChild(videoEl); groupContainer.appendChild(participantContainer); return videoEl; } function teardownParticipant({ isLocal, id }) { const groupId = isLocal ? 'local-media' : 'remote-media'; const groupContainer = document.getElementById(groupId); const participantContainerId = isLocal ? 'local' : id; const participantDiv = document.getElementById( participantContainerId + '-container' ); if (!participantDiv) { return; } groupContainer.removeChild(participantDiv); } function createVideoEl(id) { const videoEl = document.createElement('video'); videoEl.id = id; videoEl.autoplay = true; videoEl.playsInline = true; videoEl.srcObject = new MediaStream(); return videoEl; } function createContainer(id) { const participantContainer = document.createElement('div'); participantContainer.classList = 'participant-container'; participantContainer.id = id + '-container'; return participantContainer; }

Tampilan Kamera dan Mikrofon yang Terhubung

Selanjutnya, buatmedia-devices.js, yang berisi metode pembantu untuk menampilkan kamera dan mikrofon yang terhubung ke perangkat Anda:

/*! Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ /** * Returns an initial list of devices populated on the page selects */ async function initializeDeviceSelect() { const videoSelectEl = document.getElementById('video-devices'); videoSelectEl.disabled = false; const { videoDevices, audioDevices } = await getDevices(); videoDevices.forEach((device, index) => { videoSelectEl.options[index] = new Option(device.label, device.deviceId); }); const audioSelectEl = document.getElementById('audio-devices'); audioSelectEl.disabled = false; audioDevices.forEach((device, index) => { audioSelectEl.options[index] = new Option(device.label, device.deviceId); }); } /** * Returns all devices available on the current device */ async function getDevices() { // Prevents issues on Safari/FF so devices are not blank await navigator.mediaDevices.getUserMedia({ video: true, audio: true }); const devices = await navigator.mediaDevices.enumerateDevices(); // Get all video devices const videoDevices = devices.filter((d) => d.kind === 'videoinput'); if (!videoDevices.length) { console.error('No video devices found.'); } // Get all audio devices const audioDevices = devices.filter((d) => d.kind === 'audioinput'); if (!audioDevices.length) { console.error('No audio devices found.'); } return { videoDevices, audioDevices }; } async function getCamera(deviceId) { // Use Max Width and Height return navigator.mediaDevices.getUserMedia({ video: { deviceId: deviceId ? { exact: deviceId } : null, }, audio: false, }); } async function getMic(deviceId) { return navigator.mediaDevices.getUserMedia({ video: false, audio: { deviceId: deviceId ? { exact: deviceId } : null, }, }); }

Membuat Sesi Kit Kamera

Buatstages.js, yang berisi logika untuk menerapkan Lens ke umpan kamera dan menerbitkan umpan ke panggung. Kami merekomendasikan menyalin dan menempelkan blok kode berikut ke dalamstages.js. Anda kemudian dapat meninjau kode sepotong demi sepotong untuk memahami apa yang terjadi di bagian berikut.

/*! Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ const { Stage, LocalStageStream, SubscribeType, StageEvents, ConnectionState, StreamType, } = IVSBroadcastClient; import { bootstrapCameraKit, createMediaStreamSource, Transform2D, } from '@snap/camera-kit'; let cameraButton = document.getElementById('camera-control'); let micButton = document.getElementById('mic-control'); let joinButton = document.getElementById('join-button'); let leaveButton = document.getElementById('leave-button'); let controls = document.getElementById('local-controls'); let videoDevicesList = document.getElementById('video-devices'); let audioDevicesList = document.getElementById('audio-devices'); let lensSelector = document.getElementById('lens-selector'); let session; let availableLenses = []; // Stage management let stage; let joining = false; let connected = false; let localCamera; let localMic; let cameraStageStream; let micStageStream; const liveRenderTarget = document.getElementById('canvas'); const init = async () => { await initializeDeviceSelect(); const cameraKit = await bootstrapCameraKit({ apiToken: 'INSERT_YOUR_API_TOKEN_HERE', }); session = await cameraKit.createSession({ liveRenderTarget }); const { lenses } = await cameraKit.lensRepository.loadLensGroups([ 'INSERT_YOUR_LENS_GROUP_ID_HERE', ]); availableLenses = lenses; populateLensSelector(lenses); const snapStream = liveRenderTarget.captureStream(); lensSelector.addEventListener('change', handleLensChange); lensSelector.disabled = true; cameraButton.addEventListener('click', () => { const isMuted = !cameraStageStream.isMuted; cameraStageStream.setMuted(isMuted); cameraButton.innerText = isMuted ? 'Show Camera' : 'Hide Camera'; }); micButton.addEventListener('click', () => { const isMuted = !micStageStream.isMuted; micStageStream.setMuted(isMuted); micButton.innerText = isMuted ? 'Unmute Mic' : 'Mute Mic'; }); joinButton.addEventListener('click', () => { joinStage(session, snapStream); }); leaveButton.addEventListener('click', () => { leaveStage(); }); }; async function setCameraKitSource(session, mediaStream) { const source = createMediaStreamSource(mediaStream); await session.setSource(source); source.setTransform(Transform2D.MirrorX); session.play(); } const populateLensSelector = (lenses) => { lensSelector.innerHTML = '<option selected disabled>Choose Lens</option>'; lenses.forEach((lens, index) => { const option = document.createElement('option'); option.value = index; option.text = lens.name || `Lens ${index + 1}`; lensSelector.appendChild(option); }); }; const handleLensChange = (event) => { const selectedIndex = parseInt(event.target.value); if (session && availableLenses[selectedIndex]) { session.applyLens(availableLenses[selectedIndex]); } }; const joinStage = async (session, snapStream) => { if (connected || joining) { return; } joining = true; const token = document.getElementById('token').value; if (!token) { window.alert('Please enter a participant token'); joining = false; return; } // Retrieve the User Media currently set on the page localCamera = await getCamera(videoDevicesList.value); localMic = await getMic(audioDevicesList.value); await setCameraKitSource(session, localCamera); // Create StageStreams for Audio and Video cameraStageStream = new LocalStageStream(snapStream.getVideoTracks()[0]); micStageStream = new LocalStageStream(localMic.getAudioTracks()[0]); const strategy = { stageStreamsToPublish() { return [cameraStageStream, micStageStream]; }, shouldPublishParticipant() { return true; }, shouldSubscribeToParticipant() { return SubscribeType.AUDIO_VIDEO; }, }; stage = new Stage(token, strategy); // Other available events: // https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-guides/stages#events stage.on(StageEvents.STAGE_CONNECTION_STATE_CHANGED, (state) => { connected = state === ConnectionState.CONNECTED; if (connected) { joining = false; controls.classList.remove('hidden'); lensSelector.disabled = false; } else { controls.classList.add('hidden'); lensSelector.disabled = true; } }); stage.on(StageEvents.STAGE_PARTICIPANT_JOINED, (participant) => { console.log('Participant Joined:', participant); }); stage.on( StageEvents.STAGE_PARTICIPANT_STREAMS_ADDED, (participant, streams) => { console.log('Participant Media Added: ', participant, streams); let streamsToDisplay = streams; if (participant.isLocal) { // Ensure to exclude local audio streams, otherwise echo will occur streamsToDisplay = streams.filter( (stream) => stream.streamType === StreamType.VIDEO ); } const videoEl = setupParticipant(participant); streamsToDisplay.forEach((stream) => videoEl.srcObject.addTrack(stream.mediaStreamTrack) ); } ); stage.on(StageEvents.STAGE_PARTICIPANT_LEFT, (participant) => { console.log('Participant Left: ', participant); teardownParticipant(participant); }); try { await stage.join(); } catch (err) { joining = false; connected = false; console.error(err.message); } }; const leaveStage = async () => { stage.leave(); joining = false; connected = false; cameraButton.innerText = 'Hide Camera'; micButton.innerText = 'Mute Mic'; controls.classList.add('hidden'); }; init();

Di bagian pertama file ini, kami mengimpor SDK siaran dan Camera Kit Web SDK dan menginisialisasi variabel yang akan kami gunakan dengan setiap SDK. Kami membuat sesi Camera Kit dengan memanggil createSession setelah melakukan bootstrap pada Camera Kit Web SDK. Perhatikan bahwa objek elemen kanvas diteruskan ke sesi; ini memberitahu Camera Kit untuk merender ke kanvas itu.

/*! Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ const { Stage, LocalStageStream, SubscribeType, StageEvents, ConnectionState, StreamType, } = IVSBroadcastClient; import { bootstrapCameraKit, createMediaStreamSource, Transform2D, } from '@snap/camera-kit'; let cameraButton = document.getElementById('camera-control'); let micButton = document.getElementById('mic-control'); let joinButton = document.getElementById('join-button'); let leaveButton = document.getElementById('leave-button'); let controls = document.getElementById('local-controls'); let videoDevicesList = document.getElementById('video-devices'); let audioDevicesList = document.getElementById('audio-devices'); let lensSelector = document.getElementById('lens-selector'); let session; let availableLenses = []; // Stage management let stage; let joining = false; let connected = false; let localCamera; let localMic; let cameraStageStream; let micStageStream; const liveRenderTarget = document.getElementById('canvas'); const init = async () => { await initializeDeviceSelect(); const cameraKit = await bootstrapCameraKit({ apiToken: 'INSERT_YOUR_API_TOKEN_HERE', }); session = await cameraKit.createSession({ liveRenderTarget });

Ambil Lensa dan Mengisi Pemilih Lensa

Untuk mengambil Lensa Anda, ganti placeholder untuk ID Grup Lensa dengan milik Anda sendiri, yang dapat ditemukan di Portal Pengembang Kit Kamera. Isi dropdown pemilihan lensa menggunakan populateLensSelector() fungsi yang akan kita buat nanti.

session = await cameraKit.createSession({ liveRenderTarget }); const { lenses } = await cameraKit.lensRepository.loadLensGroups([ 'INSERT_YOUR_LENS_GROUP_ID_HERE', ]); availableLenses = lenses; populateLensSelector(lenses);

Render Output dari Sesi Camera Kit ke Canvas

Gunakan metode CaptureStream untuk mengembalikan MediaStream konten kanvas. Kanvas akan berisi aliran video dari umpan kamera dengan Lensa yang diterapkan. Selain itu, tambahkan pendengar acara untuk tombol untuk mematikan kamera dan mikrofon serta pendengar acara untuk bergabung dan meninggalkan panggung. Dalam acara pendengar untuk bergabung dengan panggung, kami meneruskan sesi Kit Kamera dan MediaStream dari kanvas sehingga dapat dipublikasikan ke panggung.

const snapStream = liveRenderTarget.captureStream(); lensSelector.addEventListener('change', handleLensChange); lensSelector.disabled = true; cameraButton.addEventListener('click', () => { const isMuted = !cameraStageStream.isMuted; cameraStageStream.setMuted(isMuted); cameraButton.innerText = isMuted ? 'Show Camera' : 'Hide Camera'; }); micButton.addEventListener('click', () => { const isMuted = !micStageStream.isMuted; micStageStream.setMuted(isMuted); micButton.innerText = isMuted ? 'Unmute Mic' : 'Mute Mic'; }); joinButton.addEventListener('click', () => { joinStage(session, snapStream); }); leaveButton.addEventListener('click', () => { leaveStage(); }); };

Buat Fungsi untuk Mengisi Dropdown Lensa

Buat fungsi berikut untuk mengisi pem ilih Lensa dengan lensa yang diambil sebelumnya. Pem ilih Lensa adalah elemen UI pada halaman yang memungkinkan Anda memilih dari daftar lensa untuk diterapkan ke umpan kamera. Juga, buat fungsi handleLensChange callback untuk menerapkan lensa yang ditentukan saat dipilih dari dropdown Lensa.

const populateLensSelector = (lenses) => { lensSelector.innerHTML = '<option selected disabled>Choose Lens</option>'; lenses.forEach((lens, index) => { const option = document.createElement('option'); option.value = index; option.text = lens.name || `Lens ${index + 1}`; lensSelector.appendChild(option); }); }; const handleLensChange = (event) => { const selectedIndex = parseInt(event.target.value); if (session && availableLenses[selectedIndex]) { session.applyLens(availableLenses[selectedIndex]); } };

Menyediakan Camera Kit dengan Sumber Media untuk Rendering dan Publikasikan LocalStageStream

Untuk menerbitkan aliran video dengan Lens yang diterapkan, buat fungsi yang dipanggil setCameraKitSource untuk meneruskan yang MediaStream diambil dari kanvas sebelumnya. MediaStreamDari kanvas tidak melakukan apa-apa saat ini karena kami belum memasukkan umpan kamera lokal kami. Kami dapat menggabungkan umpan kamera lokal kami dengan memanggil metode pem getCamera bantu dan menetapkannyalocalCamera. Kami kemudian dapat meneruskan umpan kamera lokal kami (vialocalCamera) dan objek sesi kesetCameraKitSource. setCameraKitSourceFungsi ini mengubah umpan kamera lokal kami ke sumber media untuk men CameraKit eleponcreateMediaStreamSource. Sumber media untuk kemudian CameraKit diubah untuk mencerminkan kamera yang menghadap ke depan. Efek Lens kemudian diterapkan ke sumber media dan dirender ke kanvas keluaran dengan memanggilsession.play().

Dengan Lens sekarang diterapkan pada yang MediaStream diambil dari kanvas, kita kemudian dapat melanjutkan untuk menerbitkannya ke panggung. Kami melakukannya dengan membuat LocalStageStream dengan trek video dariMediaStream. Contoh dari kemudian LocalStageStream dapat diteruskan ke a StageStrategy untuk dipublikasikan.

async function setCameraKitSource(session, mediaStream) { const source = createMediaStreamSource(mediaStream); await session.setSource(source); source.setTransform(Transform2D.MirrorX); session.play(); } const joinStage = async (session, snapStream) => { if (connected || joining) { return; } joining = true; const token = document.getElementById('token').value; if (!token) { window.alert('Please enter a participant token'); joining = false; return; } // Retrieve the User Media currently set on the page localCamera = await getCamera(videoDevicesList.value); localMic = await getMic(audioDevicesList.value); await setCameraKitSource(session, localCamera); // Create StageStreams for Audio and Video // cameraStageStream = new LocalStageStream(localCamera.getVideoTracks()[0]); cameraStageStream = new LocalStageStream(snapStream.getVideoTracks()[0]); micStageStream = new LocalStageStream(localMic.getAudioTracks()[0]); const strategy = { stageStreamsToPublish() { return [cameraStageStream, micStageStream]; }, shouldPublishParticipant() { return true; }, shouldSubscribeToParticipant() { return SubscribeType.AUDIO_VIDEO; }, };

Kode yang tersisa di bawah ini adalah untuk membuat dan mengelola panggung kami:

stage = new Stage(token, strategy); // Other available events: // https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-guides/stages#events stage.on(StageEvents.STAGE_CONNECTION_STATE_CHANGED, (state) => { connected = state === ConnectionState.CONNECTED; if (connected) { joining = false; controls.classList.remove('hidden'); } else { controls.classList.add('hidden'); } }); stage.on(StageEvents.STAGE_PARTICIPANT_JOINED, (participant) => { console.log('Participant Joined:', participant); }); stage.on( StageEvents.STAGE_PARTICIPANT_STREAMS_ADDED, (participant, streams) => { console.log('Participant Media Added: ', participant, streams); let streamsToDisplay = streams; if (participant.isLocal) { // Ensure to exclude local audio streams, otherwise echo will occur streamsToDisplay = streams.filter( (stream) => stream.streamType === StreamType.VIDEO ); } const videoEl = setupParticipant(participant); streamsToDisplay.forEach((stream) => videoEl.srcObject.addTrack(stream.mediaStreamTrack) ); } ); stage.on(StageEvents.STAGE_PARTICIPANT_LEFT, (participant) => { console.log('Participant Left: ', participant); teardownParticipant(participant); }); try { await stage.join(); } catch (err) { joining = false; connected = false; console.error(err.message); } }; const leaveStage = async () => { stage.leave(); joining = false; connected = false; cameraButton.innerText = 'Hide Camera'; micButton.innerText = 'Mute Mic'; controls.classList.add('hidden'); }; init();

Buat package.json

Buat package.json dan tambahkan konfigurasi JSON berikut. File ini mendefinisikan dependensi kita dan menyertakan perintah skrip untuk menggabungkan kode kita.

{ "dependencies": { "@snap/camera-kit": "^0.10.0" }, "name": "ivs-stages-with-snap-camerakit", "version": "1.0.0", "main": "index.js", "scripts": { "build": "webpack" }, "keywords": [], "author": "", "license": "ISC", "description": "", "devDependencies": { "webpack": "^5.95.0", "webpack-cli": "^5.1.4" } }

Buat File Konfigurasi Webpack

Buat webpack.config.js dan tambahkan kode berikut. Ini menggabungkan kode yang kami buat sejauh ini sehingga kami dapat menggunakan pernyataan impor untuk menggunakan Camera Kit.

const path = require('path'); module.exports = { entry: ['./stage.js'], output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist'), }, };

Terakhir, jalankan npm run build untuk menggabungkan Anda JavaScript seperti yang didefinisikan dalam file konfigurasi Webpack. Untuk tujuan pengujian, Anda kemudian dapat menyajikan HTML dan JavaScript dari komputer lokal Anda. Dalam contoh ini, kita menggunakan http.server modul Python.

Menyiapkan Server HTTPS dan Uji

Untuk menguji kode kita, kita perlu mengatur server HTTPS. Menggunakan server HTTPS untuk pengembangan lokal dan pengujian integrasi aplikasi web Anda dengan Snap Camera Kit SDK akan membantu menghindari masalah CORS (Res Cross-Origin ource Sharing).

Buka terminal dan arahkan ke direktori tempat Anda membuat semua kode hingga titik ini. Jalankan perintah berikut untuk menghasilkan SSL/TLS sertifikat yang ditandatangani sendiri dan kunci pribadi:

openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes

Ini membuat dua file: key.pem (kunci pribadi) dan cert.pem (sertifikat yang ditandatangani sendiri). Buat file Python baru bernama https_server.py dan tambahkan kode berikut:

import http.server import ssl # Set the directory to serve files from DIRECTORY = '.' # Create the HTTPS server server_address = ('', 4443) httpd = http.server.HTTPServer( server_address, http.server.SimpleHTTPRequestHandler) # Wrap the socket with SSL/TLS context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) context.load_cert_chain('cert.pem', 'key.pem') httpd.socket = context.wrap_socket(httpd.socket, server_side=True) print(f'Starting HTTPS server on https://localhost:4443, serving {DIRECTORY}') httpd.serve_forever()

Buka terminal, navigasikan ke direktori tempat Anda membuat https_server.py file, dan jalankan perintah berikut:

python3 https_server.py

Ini memulai server HTTPS di: 4443https://localhost, melayani file dari direktori saat ini. Pastikan key.pem file cert.pem dan berada di direktori yang sama dengan https_server.py file.

Buka browser Anda dan arahkan ke: 4443. https://localhost Karena ini adalah SSL/TLS sertifikat yang ditandatangani sendiri, itu tidak akan dipercaya oleh browser web Anda, jadi Anda akan mendapatkan peringatan. Karena ini hanya untuk tujuan pengujian, Anda dapat melewati peringatan. Anda kemudian akan melihat efek AR untuk Snap Lens yang Anda tentukan sebelumnya diterapkan ke umpan kamera Anda di layar.

Perhatikan bahwa pengaturan ini menggunakan built-in http.server dan ssl modul Python cocok untuk pengembangan lokal dan tujuan pengujian, tetapi tidak disarankan untuk lingkungan produksi. SSL/TLS Sertifikat yang ditandatangani sendiri yang digunakan dalam pengaturan ini tidak dipercaya oleh browser web dan klien lain, yang berarti pengguna akan menemukan peringatan keamanan saat mengakses server. Juga, meskipun kami menggunakan modul http.server dan ssl bawaan Python dalam contoh ini, Anda dapat memilih untuk menggunakan solusi server HTTPS lain.

Android

Untuk mengintegrasikan SDK Kit Kamera Snap dengan IVS Android broadcast SDK, Anda harus menginstal Camera Kit SDK, menginisialisasi sesi Camera Kit, menerapkan Lensa, dan memasukkan output sesi Camera Kit ke sumber input gambar khusus.

Untuk menginstal Camera Kit SDK, tambahkan yang berikut ini ke build.gradle file modul Anda. Ganti $cameraKitVersion dengan versi SDK Kit Kamera terbaru.

implementation "com.snap.camerakit:camerakit:$cameraKitVersion"

Inisialisasi dan dapatkan acameraKitSession. Camera Kit juga menyediakan pembungkus yang nyaman untuk API CameraX Android, sehingga Anda tidak perlu menulis logika rumit untuk menggunakan CameraX dengan Camera Kit. Anda dapat menggunakan CameraXImageProcessorSource objek sebagai Sumber untuk ImageProcessor, yang memungkinkan Anda memulai bingkai streaming pratinjau kamera.

protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Camera Kit support implementation of ImageProcessor that is backed by CameraX library: // https://developer.android.com/training/camerax CameraXImageProcessorSource imageProcessorSource = new CameraXImageProcessorSource( this /*context*/, this /*lifecycleOwner*/ ); imageProcessorSource.startPreview(true /*cameraFacingFront*/); cameraKitSession = Sessions.newBuilder(this) .imageProcessorSource(imageProcessorSource) .attachTo(findViewById(R.id.camerakit_stub)) .build(); }

Ambil dan Terapkan Lensa

Anda dapat mengonfigurasi Lensa dan pemesanannya di carousel di Portal Pengembang Kit Kamera:

// Fetch lenses from repository and apply them // Replace LENS_GROUP_ID with Lens Group ID from https://camera-kit.snapchat.com cameraKitSession.getLenses().getRepository().get(new Available(LENS_GROUP_ID), available -> { Log.d(TAG, "Available lenses: " + available); Lenses.whenHasFirst(available, lens -> cameraKitSession.getLenses().getProcessor().apply(lens, result -> { Log.d(TAG, "Apply lens [" + lens + "] success: " + result); })); });

Untuk menyiarkan, kirim bingkai yang Surface diproses ke dasar sumber gambar khusus. Gunakan DeviceDiscovery objek dan buat CustomImageSource untuk mengembalikan aSurfaceSource. Anda kemudian dapat merender output dari CameraKit sesi ke yang mendasarinya yang Surface disediakan olehSurfaceSource.

val publishStreams = ArrayList<LocalStageStream>() val deviceDiscovery = DeviceDiscovery(applicationContext) val customSource = deviceDiscovery.createImageInputSource(BroadcastConfiguration.Vec2(720f, 1280f)) cameraKitSession.processor.connectOutput(outputFrom(customSource.inputSurface)) val customStream = ImageLocalStageStream(customSource) // After rendering the output from a Camera Kit session to the Surface, you can // then return it as a LocalStageStream to be published by the Broadcast SDK val customStream: ImageLocalStageStream = ImageLocalStageStream(surfaceSource) publishStreams.add(customStream) @Override fun stageStreamsToPublishForParticipant(stage: Stage, participantInfo: ParticipantInfo): List<LocalStageStream> = publishStreams