Прямые трансляции стали одним из самых популярных способов обмена информацией и общения с аудиторией в режиме реального времени. Являетесь ли вы владельцем бизнеса, музыкантом или учителем. Прямая трансляция может быть мощным инструментом для взаимодействия с вашей аудиторией, чтобы поделиться своим сообщением.
Выбор правильной платформы для прямых трансляций является наиболее важным решением, так как оно может повлиять на качество вашей трансляции, размер вашей аудитории и общий успех вашей прямой трансляции. Вот несколько факторов, которые следует учитывать при выборе платформы для прямых трансляций:
- Возможности: Ищите платформы прямых трансляций, которые предлагают функции, необходимые для создания высококачественных трансляций. Например, вам может понадобиться платформа, которая поддерживает несколько ракурсов камеры, позволяет вам делиться своим экраном или позволяет использовать несколько вещателей.
- Интеграция: интеграция платформы потокового вещания должна быть простой и быстрой.
- Бюджет: хотя платформы для потокового вещания стоят дорого, важно выбрать платформу, которая соответствует вашему бюджету.
Почему стоит выбрать Video SDK?
Video SDK — идеальный выбор для тех, кто ищет платформу для прямых трансляций, которая предлагает необходимые функции для создания высококачественных потоков. Платформа поддерживает совместное использование экрана, обмен сообщениями в режиме реального времени, позволяет вещателям приглашать зрителей на сцену и поддерживает более 100 000 000 участников, гарантируя, что ваши прямые трансляции будут интерактивными и увлекательными. С помощью Video SDK вы также можете использовать собственный шаблон макета для прямых трансляций.
Что касается интеграции, Video SDK предлагает простой и быстрый процесс интеграции, позволяющий легко интегрировать прямую трансляцию в ваше приложение. Это гарантирует, что вы сможете пользоваться преимуществами прямой трансляции без каких-либо технических трудностей или длительных процессов внедрения.
Кроме того, Video SDK является бюджетным, что делает его доступным вариантом для предприятий любого размера. Вы можете пользоваться преимуществами многофункциональной платформы для прямых трансляций, не разоряя банк, что делает ее идеальным выбором для стартапов и малого бизнеса.
5 шагов для создания живого потокового приложения React Native
Следующие шаги дадут вам всю информацию для быстрого создания приложения интерактивной прямой трансляции. Пожалуйста, внимательно следите за новостями, а если у вас возникнут трудности, сразу сообщите нам об этом в Discord, и мы будем рады вам помочь.
Предпосылки
Прежде чем продолжить, убедитесь, что ваша среда разработки соответствует следующим требованиям:
- Учетная запись разработчика Video SDK (еще нет? Следите за Панель управления Video SDK)
- Базовое понимание React Native.
- Node.js v12+
- NPM v6+ (поставляется с более новыми версиями Node)
- Android Studio или Xcode установлены
Для создания токена необходимо иметь учетную запись VideoSDK. Посетите панель управления VideoSDK, чтобы сгенерировать токен
Архитектура приложения
Это приложение будет содержать два экрана:
Join Screen
: Этот экран позволяетSPEAKER
создать студию или присоединиться к предварительно определенной студии иVIEWER
присоединиться к предварительно определенной студии.Speaker Screen
: Этот экран в основном содержит список выступающих и некоторые элементы управления студией, такие как «Включить/отключить микрофон и камеру» и «Покинуть студию».Viewer Screen
: Этот экран в основном содержит проигрыватель прямых трансляций, в котором зритель будет воспроизводить трансляцию.
Начало работы с кодом!
Создать приложение
Создайте новое реагирующее приложение, применив приведенные ниже команды.
npx react-native init AppName
Для реактивной установки вы можете следовать Официальным документам.
Установка видео SDK
Установите Video SDK, выполнив следующую команду. Перед запуском этой команды убедитесь, что вы находитесь в каталоге проекта.
Для NPM:
npm install "@videosdk.live/react-native-sdk"
Для пряжи:
yarn add "@videosdk.live/react-native-sdk"
Структура проекта
root ├── node_modules ├── android ├── ios ├── App.js ├── api.js ├── index.jsCopy
Настройка Android
Шаг 1. Добавьте необходимое разрешение в файл AndroidManifest.xml.
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.cool.app" > <!-- Give all the required permissions to app --> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <!-- Needed to communicate with already-paired Bluetooth devices. (Legacy up to Android 11) --> <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" /> <!-- Needed to communicate with already-paired Bluetooth devices. (Android 12 upwards)--> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> <uses-permission android:name="android.permission.WAKE_LOCK" /> <application> <meta-data android:name="live.videosdk.rnfgservice.notification_channel_name" android:value="Meeting Notification" /> <meta-data android:name="live.videosdk.rnfgservice.notification_channel_description" android:value="Whenever meeting started notification will appear." /> <meta-data android:name="live.videosdk.rnfgservice.notification_color" android:resource="@color/red" /> <service android:name="live.videosdk.rnfgservice.ForegroundService" android:foregroundServiceType="mediaProjection"></service> <service android:name="live.videosdk.rnfgservice.ForegroundServiceTask"></service> </application> </manifest>
Шаг 2. Свяжите пару зависимостей внутренней библиотеки в файле android/app/build.gradle
dependencies { compile project(':rnfgservice') compile project(':rnwebrtc') compile project(':rnincallmanager') }
Включить зависимости в android/settings.gradle
include ':rnwebrtc' project(':rnwebrtc').projectDir = new File(rootProject.projectDir, '../node_modules/@videosdk.live/react-native-webrtc/android') include ':rnincallmanager' project(':rnincallmanager').projectDir = new File(rootProject.projectDir, '../node_modules/@videosdk.live/react-native-incallmanager/android') include ':rnfgservice' project(':rnfgservice').projectDir = new File(rootProject.projectDir, '../node_modules/@videosdk.live/react-native-foreground-service/android')
Обновите MainApplication.java, чтобы использовать InCallManager и запускать некоторые службы переднего плана.
import live.videosdk.rnfgservice.ForegroundServicePackage; import live.videosdk.rnincallmanager.InCallManagerPackage; import live.videosdk.rnwebrtc.WebRTCModulePackage; public class MainApplication extends Application implements ReactApplication { private static List<ReactPackage> getPackages() { return Arrays.<ReactPackage>asList( /* Initialise foreground service, incall manager and webrtc module */ new ForegroundServicePackage(), new InCallManagerPackage(), new WebRTCModulePackage(), ); } }
Некоторые устройства могут столкнуться с проблемой WebRTC. Чтобы решить эту проблему, обновите файл android/gradle.properties, указав следующее.
/* This one fixes a weird WebRTC runtime problem on some devices. */ android.enableDexingArtifactTransform.desugaring=falseCopy
Если вы используете proguard, внесите указанные ниже изменения в файл android/app/proguard-rules.pro (это необязательно)
-keep class org.webrtc.** { *; }
Шаг 3. Обновите файл colors.xml новыми цветами для внутренних зависимостей.
<resources> <item name="red" type="color">#FC0303</item> <integer-array name="androidcolors"> <item>@color/red</item> </integer-array> </resources>
Настройка iOS
Шаг 1: Установите react-native-incallmanager
$ yarn add @videosdk.live/react-native-incallmanager
Шаг 2: Убедитесь, что вы используете CocoaPods 1.10 или выше. Чтобы обновить CocoaPods, вы можете просто снова установить гем.
$[sudo] gem install cocoapods
Шаг 3: Связывание вручную (если react-native-incall-manager не связывается автоматически)
- Перетащите node_modules/@videosdk.live/react-native-incall-manager/ios/RNInCallManager.xcodeproj в раздел ‹your_xcode_project›/Libraries.
- Выберите ‹your_xcode_project› --› Фазы сборки --› Связать двоичный файл с библиотеками
- Перетащите Libraries/RNInCallManager.xcodeproj/Products/libRNInCallManager.a, чтобы связать двоичный файл с библиотеками.
- Выберите ‹your_xcode_project› --› Настройки сборки В пути поиска заголовков добавьте $(SRCROOT)/../node_modules/@videosdk.live/react-native-incall-manager/ios/RNInCallManager
Шаг 4: Измените путь к react-native-webrtc
pod ‘react-native-webrtc’, :path => ‘../node_modules/@videosdk.live/react-native-webrtc’
Шаг 5: Измените версию вашей платформы
- Вы должны изменить поле платформы подфайла на 11.0 или выше, так как react-native-webrtc не поддерживает платформу IOS ‹ 11: ios, «11.0»
Шаг 6: После обновления версии необходимо установить модули
Pod install
Шаг 7: Затем добавьте «libreact-native-webrtc.a в Link Binary с библиотеками. В целевой папке основного проекта.»
Шаг 8: Теперь добавьте следующие разрешения в info.plist (папка проекта/IOS/имя проекта/info.plist):
<key>NSCameraUsageDescription</key> <string>Camera permission description</string> <key>NSMicrophoneUsageDescription</key> <string>Microphone permission description</string>
Регистрация службы
Зарегистрируйте службы Video SDK в корневом файле index.js для службы инициализации.
import { register } from '@videosdk.live/react-native-sdk'; import { AppRegistry } from 'react-native'; import { name as appName } from './app.json'; import App from './src/App.js'; // Register the service register(); AppRegistry.registerComponent(appName, () => App);
Начните писать свой код прямо сейчас
Шаг 1. Начните работу с API.js
Прежде чем переходить к чему-либо еще, мы должны написать API для создания уникального идентификатора встречи. Вам потребуется токен авторизации, вы можете сгенерировать его либо с помощью videosdk-rtc-api-server-examples, либо сгенерировать его из Video SDK Dashboard для разработчика.
// Auth token we will use to generate a meeting and connect to it export const authToken = "<Generated-from-dashbaord>"; // API call to create meeting export const createMeeting = async ({ token }) => { const res = await fetch(`https://api.videosdk.live/v1/meetings`, { method: "POST", headers: { authorization: `${token}`, "Content-Type": "application/json", }, body: JSON.stringify({ region: "sg001" }), }); const { meetingId } = await res.json(); return meetingId; };
Шаг 2: Wireframe App.js со всеми компонентами
Чтобы создать каркас App.js, мы будем использовать хуки Video SDK и поставщики контекста. Video SDK предоставляет перехватчики MeetingProvider, MeetingConsumer, useMeeting и useParticipant. Давайте разберемся в каждом из них.
Сначала мы рассмотрим Context Provider и Consumer. Контекст в основном используется, когда некоторые данные должны быть доступны многим компонентам на разных уровнях вложенности.
- MeetingProvider. Это поставщик контекста. Он принимает значения
config
иtoken
в качестве реквизита. Компонент Provider принимает свойство value для передачи потребляющим компонентам, которые являются потомками этого Provider. Один провайдер может быть подключен ко многим потребителям. Провайдеры могут быть вложены друг в друга, чтобы переопределять значения, расположенные глубже в дереве. - MeetingConsumer : это потребитель контекста. Все потребители, которые являются потомками провайдера, будут перерисовываться всякий раз, когда изменяется свойство значения провайдера.
- useMeeting : это API-интерфейс ответного хука для встречи. Он включает в себя всю информацию, связанную с собранием, такую как присоединение, выход, включение/отключение микрофона или веб-камеры и т. д.
- useParticipant : это API-интерфейс хука участника. Хук useParticipant отвечает за обработку всех событий и реквизитов, связанных с одним конкретным участником, таких как имя, webcamStream, micStream и т. д.
Контекст собрания помогает прослушивать все изменения, когда участник присоединяется к собранию или меняет микрофон или камеру и т. д.
Давайте начнем с изменения пары строк кода в App.js.
import React, { useState, useMemo, useRef, useEffect } from "react"; import { SafeAreaView, TouchableOpacity, Text, TextInput, View, FlatList, Clipboard, } from "react-native"; import { MeetingProvider, useMeeting, useParticipant, MediaStream, RTCView, Constants, } from "@videosdk.live/react-native-sdk"; import { createMeeting, authToken } from "./api"; // Responsible for either schedule new meeting or to join existing meeting as a host or as a viewer. function JoinScreen({ getMeetingAndToken, setMode }) { return null; } // Responsible for managing participant video stream function ParticipantView(props) { return null; } // Responsible for managing meeting controls such as toggle mic / webcam and leave function Controls() { return null; } // Responsible for Speaker side view, which contains Meeting Controls(toggle mic/webcam & leave) and Participant list function SpeakerView() { return null; } // Responsible for Viewer side view, which contains video player for streaming HLS and managing HLS state (HLS_STARTED, HLS_STOPPING, HLS_STARTING, etc.) function ViewerView() { return null; } // Responsible for managing two view (Speaker & Viewer) based on provided mode (`CONFERENCE` & `VIEWER`) function Container(props) { return null; } function App() { const [meetingId, setMeetingId] = useState(null); //State to handle the mode of the participant i.e. CONFERNCE or VIEWER const [mode, setMode] = useState("CONFERENCE"); //Getting MeetingId from the API we created earlier const getMeetingAndToken = async (id) => { const meetingId = id == null ? await createMeeting({ token: authToken }) : id; setMeetingId(meetingId); }; return authToken && meetingId ? ( <MeetingProvider config={{ meetingId, micEnabled: true, webcamEnabled: true, name: "C.V. Raman", //These will be the mode of the participant CONFERENCE or VIEWER mode: mode, }} token={authToken} > <Container /> </MeetingProvider> ) : ( <JoinScreen getMeetingAndToken={getMeetingAndToken} setMode={setMode} /> ); } export default App;
Шаг 3: Реализуйте экран присоединения
Экран присоединения будет работать как средство планирования новой встречи или присоединения к существующей встрече в качестве организатора или зрителя.
У них будет 3 кнопки:
- Присоединиться как организатор: при нажатии этой кнопки человек присоединится к введенному `meetingId` как `HOST`.
- Присоединиться как зритель: при нажатии этой кнопки человек присоединится к введенному `meetingId` как `ПРОСМОТРИТЕЛЬ`.
- Создать комнату-студию: при нажатии этой кнопки человек присоединится к новой встрече как «ХОЗЯИН».
function JoinScreen({ getMeetingAndToken, setMode }) { const [meetingVal, setMeetingVal] = useState(""); const JoinButton = ({ value, onPress }) => { return ( <TouchableOpacity style={{ backgroundColor: "#1178F8", padding: 12, marginVertical: 8, borderRadius: 6, }} onPress={onPress} > <Text style={{ color: "white", alignSelf: "center", fontSize: 18 }}> {value} </Text> </TouchableOpacity> ); }; return ( <SafeAreaView style={{ flex: 1, backgroundColor: "black", justifyContent: "center", paddingHorizontal: 6 * 10, }} > <TextInput value={meetingVal} onChangeText={setMeetingVal} placeholder={"XXXX-XXXX-XXXX"} placeholderTextColor={"grey"} style={{ padding: 12, borderWidth: 1, borderColor: "white", borderRadius: 6, color: "white", marginBottom: 16, }} /> <JoinButton onPress={() => { getMeetingAndToken(meetingVal); }} value={"Join as Host"} /> <JoinButton onPress={() => { setMode("VIEWER"); getMeetingAndToken(meetingVal); }} value={"Join as Viewer"} /> <Text style={{ alignSelf: "center", fontSize: 22, marginVertical: 16, fontStyle: "italic", color: "grey", }} > ---------- OR ---------- </Text> <JoinButton onPress={() => { getMeetingAndToken(); }} value={"Create Studio Room"} /> </SafeAreaView> ); }
Шаг 4: Реализуйте компонент-контейнер
- Следующим шагом является создание контейнера, который будет управлять компонентами
Join screen
,SpeakerView
иViewerView
на основеmode
. - Мы проверим режим
localParticipant
, если этоCONFERENCE
, мы покажемSpeakerView
, иначе мы покажемViewerView
.
function Container() { const { join, changeWebcam, localParticipant } = useMeeting({ onError: (error) => { console.log(error.message); }, }); return ( <View style={{ flex: 1 }}> {localParticipant?.mode == Constants.modes.CONFERENCE ? ( <SpeakerView /> ) : localParticipant?.mode == Constants.modes.VIEWER ? ( <ViewerView /> ) : ( <View style={{ flex: 1, justifyContent: "center", alignItems: "center", backgroundColor: "black", }} > <Text style={{ fontSize: 20, color: "white" }}> Press Join button to enter studio. </Text> <Button btnStyle={{ marginTop: 8, paddingHorizontal: 22, padding: 12, borderWidth: 1, borderColor: "white", borderRadius: 8, }} buttonText={"Join"} onPress={() => { join(); setTimeout(() => { changeWebcam(); }, 300); }} /> </View> )} </View> ); } // Common Component which will also be used in Controls Component const Button = ({ onPress, buttonText, backgroundColor, btnStyle }) => { return ( <TouchableOpacity onPress={onPress} style={{ ...btnStyle, backgroundColor: backgroundColor, padding: 10, borderRadius: 8, }} > <Text style={{ color: "white", fontSize: 12 }}>{buttonText}</Text> </TouchableOpacity> ); };
Шаг 5: Реализуйте SpeakerView
Следующим шагом является создание компонентов SpeakerView
и Controls
для управления такими функциями, как присоединение, выход, отключение и включение звука.
- Мы получим все
participants
из хукаuseMeeting
и отфильтруем их для режима, установленного наCONFERENCE
, чтобы на экране отображались только динамики.
function SpeakerView() { // Get the Participant Map and meetingId const { meetingId, participants } = useMeeting({}); // For getting speaker participant, we will filter out `CONFERENCE` mode participant const speakers = useMemo(() => { const speakerParticipants = [...participants.values()].filter( (participant) => { return participant.mode == Constants.modes.CONFERENCE; } ); return speakerParticipants; }, [participants]); return ( <SafeAreaView style={{ backgroundColor: "black", flex: 1 }}> {/* Render Header for copy meetingId and leave meeting*/} <HeaderView /> {/* Render Participant List */} {speakers.length > 0 ? ( <FlatList data={speakers} renderItem={({ item }) => { return <ParticipantView participantId={item.id} />; }} /> ) : null} {/* Render Controls */} <Controls /> </SafeAreaView> ); } function HeaderView() { const { meetingId, leave } = useMeeting(); return ( <View style={{ flexDirection: "row", padding: 16, justifyContent: "space-evenly", alignItems: "center", }} > <Text style={{ fontSize: 24, color: "white" }}>{meetingId}</Text> <Button btnStyle={{ borderWidth: 1, borderColor: "white", }} onPress={() => { Clipboard.setString(meetingId); alert("MeetingId copied successfully"); }} buttonText={"Copy MeetingId"} backgroundColor={"transparent"} /> <Button onPress={() => { leave(); }} buttonText={"Leave"} backgroundColor={"#FF0000"} /> </View> ); } function Container(){ ... const mMeeting = useMeeting({ onMeetingJoined: () => { // We will pin the local participant if he joins in CONFERENCE mode if (mMeetingRef.current.localParticipant.mode == "CONFERENCE") { mMeetingRef.current.localParticipant.pin(); } }, ... }); // We will create a ref to meeting object so that when used inside the // Callback functions, meeting state is maintained const mMeetingRef = useRef(mMeeting); useEffect(() => { mMeetingRef.current = mMeeting; }, [mMeeting]); return <>...</>; }
2. Мы создадим ParticipantView
, чтобы показать участникам медиа. Для этого будет использоваться webcamStream
из хука useParticipant
для воспроизведения мультимедиа участника.
function ParticipantView({ participantId }) { const { webcamStream, webcamOn } = useParticipant(participantId); return webcamOn && webcamStream ? ( <RTCView streamURL={new MediaStream([webcamStream.track]).toURL()} objectFit={"cover"} style={{ height: 300, marginVertical: 8, marginHorizontal: 8, }} /> ) : ( <View style={{ backgroundColor: "grey", height: 300, justifyContent: "center", alignItems: "center", marginVertical: 8, marginHorizontal: 8, }} > <Text style={{ fontSize: 16 }}>NO MEDIA</Text> </View> ); }
3. Мы добавим компонент Controls
, который позволит динамику переключать медиа и запускать/останавливать HLS.
function Controls() { const { toggleWebcam, toggleMic, startHls, stopHls, hlsState } = useMeeting( {} ); const _handleHLS = async () => { if (!hlsState || hlsState === "HLS_STOPPED") { startHls({ layout: { type: "SPOTLIGHT", priority: "PIN", gridSize: 4, }, theme: "DARK", orientation: "portrait", }); } else if (hlsState === "HLS_STARTED" || hlsState === "HLS_PLAYABLE") { stopHls(); } }; return ( <View style={{ padding: 24, flexDirection: "row", justifyContent: "space-between", }} > <Button onPress={() => { toggleWebcam(); }} buttonText={"Toggle Webcam"} backgroundColor={"#1178F8"} /> <Button onPress={() => { toggleMic(); }} buttonText={"Toggle Mic"} backgroundColor={"#1178F8"} /> {hlsState === "HLS_STARTED" || hlsState === "HLS_STOPPING" || hlsState === "HLS_STARTING" || hlsState === "HLS_PLAYABLE" ? ( <Button onPress={() => { _handleHLS(); }} buttonText={ hlsState === "HLS_STARTED" ? `Live Starting` : hlsState === "HLS_STOPPING" ? `Live Stopping` : hlsState === "HLS_PLAYABLE" ? `Stop Live` : `Loading...` } backgroundColor={"#FF5D5D"} /> ) : ( <Button onPress={() => { _handleHLS(); }} buttonText={`Go Live`} backgroundColor={"#1178F8"} /> )} </View> ); }
Шаг 6: Реализуйте ViewerView
Когда ХОЗЯИН (участник режима «КОНФЕРЕНЦИЯ») запускает прямую трансляцию, зритель сможет ее увидеть.
Для реализации просмотра плеера мы будем использовать react-native-video. Будет полезно воспроизвести HLS-поток.
Давайте сначала добавим этот пакет.
Для NPM:
npm install react-native-video
Для пряжи:
yarn add react-native-video
С установленным react-native-video
мы получим hlsUrls
и isHlsPlayable
из хука useMeeting
, который будет использоваться для воспроизведения HLS в плеере.
//Add imports // imports react-native-video import Video from "react-native-video"; function ViewerView({}) { const { hlsState, hlsUrls } = useMeeting(); return ( <SafeAreaView style={{ flex: 1, backgroundColor: "black" }}> {hlsState == "HLS_PLAYABLE" ? ( <> {/* Render Header for copy meetingId and leave meeting*/} <HeaderView /> {/* Render VideoPlayer that will play `downstreamUrl`*/} <Video controls={true} source={{ uri: hlsUrls.downstreamUrl, }} resizeMode={"stretch"} style={{ flex: 1, backgroundColor: "black", }} onError={(e) => console.log("error", e)} /> </> ) : ( <SafeAreaView style={{ flex: 1, justifyContent: "center", alignItems: "center" }} > <Text style={{ fontSize: 20, color: "white" }}> HLS is not started yet or is stopped </Text> </SafeAreaView> )} </SafeAreaView> ); }
Запустите свой код сейчас
//for android npx react-native run-android //for ios npx react-native run-ios
Застрял где-нибудь? Посмотрите этот пример кода на GitHub
Заключение
Благодаря этому мы успешно создали приложение React Native Live Streaming, используя видео SDK в React-Native. Если вы хотите добавить такие функции, как обмен сообщениями в чате и совместное использование экрана, вы всегда можете ознакомиться с нашей документацией. Если у вас возникнут трудности с реализацией, вы можете связаться с нами в нашем дискорд-сообществе.
Ресурсы
- React Interactive Live Streaming с Video SDK — YouTube
- Создайте нативное приложение для видеозвонков React с помощью Video SDK
- Создайте приложение для видеозвонков React Native Android с 📞 Callkeep, используя 🔥 Firebase и Video SDK
- Руководство по приложению React Native для групповых видеозвонков — YouTube
- Как создать приложение для видеозвонков React Native IOS с помощью CallKeep, используя Firebase и Video SDK, часть 2