Статьи

Видеозвонки с Android через CrossWalk и PeerJS

Создание приложения видеозвонка в Android с помощью CrossWalk и PeerJS

В этом уроке я собираюсь показать, как создать приложение для видеовызовов в Android. Он будет реализован с использованием Ionic , Cordova , Crosswalk и PeerJS .

Что мы будем строить

Вот несколько скриншотов того, что мы собираемся построить в этом уроке. Страницей по умолчанию является страница входа.

Экран входа

И как только звонок начнется, приложение отобразит прямую трансляцию видео другого пользователя.

Скриншот приложения

Настроить

Я предполагаю, что вы уже разрабатывали гибридные мобильные приложения с использованием Cordova. Если вы новичок в Cordova, я предлагаю вам сначала прочитать Руководство по платформе Cordova . Вернитесь сюда, как только вы установите Android SDK и Cordova на своем компьютере.

Если вы ранее не использовали Ionic для проектов, установите его с помощью npm .

npm install -g ionic 

Создайте новое приложение Ionic.

 ionic start VideoKoler blank 

Установка внешних активов

Установите бауэр, если у вас его еще нет на вашем компьютере. Он будет использоваться для установки внешних пакетов, необходимых для этого проекта.

 npm install -g bower 

Затем перейдите в каталог VideoKoler и установите Angular Localstorage и PeerJS.

 bower install angular-local-storage peerjs --save 

Angular Localstorage используется для сохранения данных в браузере или локальном хранилище WebView. PeerJS — это библиотека JavaScript, которая облегчает реализацию WebRTC.

Установка пешеходного перехода

По умолчанию Ionic использует WebView браузера по умолчанию для Android. WebRTC не поддерживается в этом браузере, поэтому мы используем Crosswalk для придания ему сверхспособностей. Crosswalk устанавливает более свежую версию Chrome в ваше приложение, чтобы вы могли использовать API-интерфейсы JavaScript, которые обычно не доступны в браузере Android по умолчанию. Это делает WebView, в котором приложение отображается одинаково для всех устройств. Это означает, что вам не придется терять беспокойство, если конкретная функция, которую вы использовали в своем приложении, не реализована.

Вы можете просмотреть список доступных браузеров, используя следующую команду.

 ionic browser list 

Это должно привести к выводу, подобному следующему.

список ионных браузеров

Я всегда придерживаюсь последней версии, которая не Canary. Это потому, что Canary — новейшая версия Chrome, и она еще не стабильна. Затем вы можете добавить версию с помощью ionic browser add .

 ionic browser add [email protected] 

Наконец, добавьте Android в качестве платформы.

 ionic platform add android 

PeerServer

Приложение будет использовать облачный сервис PeerServer . На момент написания, это бесплатно для 50 одновременных подключений.

облачный сервис peerserver

Нажмите на Developer — бесплатно , это откроет модальный, который позволяет вам зарегистрироваться на сервис.

регистрация peerserver

Как только ваша учетная запись будет создана, вы будете перенаправлены на панель инструментов. Нажмите кнопку Создать новый ключ API , чтобы создать новый ключ.

создать новый ключ API

Затем вас спросят «Максимальное число одновременных пиров» и «Максимальное количество одновременных пиров на IP», значения по умолчанию в порядке, вы можете обновить значения позже, если это будет необходимо.

основные настройки

Если вы хотите запустить PeerServer на своем собственном сервере, вы можете выполнить следующие шаги. Обратите внимание, что ограничения облачной службы PeerServer не применяются при запуске вашего собственного сервера.

Сначала создайте новую папку вне каталога www и назовите ее videokoler-server . Перейдите в этот каталог и установите PeerServer и Express .

 npm install peer express --save 

Создайте файл server.js и добавьте следующее.

 var express = require('express'); var express_peer_server = require('peer').ExpressPeerServer; var peer_options = { debug: true }; var app = express(); var port = 3000; var server = app.listen(port); app.use('/peerjs', express_peer_server(server, peer_options)); 

Приведенный выше код создает новый PeerServer с экспресс-сервера. Вы можете запустить сервер через узел.

 node server.js 

Чтобы проверить, правильно ли работает peerserver, перейдите по следующему URL в вашем браузере, заменив localhost именем домена.

Http: // Localhost: 3000 / peerjs

Вывод должен быть примерно таким:

 {"name":"PeerJS Server","description":"A server side element to broker connections between PeerJS clients.","website":"http://peerjs.com/"} 

Если у вас нет сервера для тестирования, вы можете использовать ngrok для показа локального хоста в Интернете. Скачайте ngrok и выполните его, используя следующую команду.

 ngrok http 3000 

Ngrok назначит URL-адрес, который мы можем использовать позже для конфигурации однорангового узла.

Сборка приложения

Вы можете найти весь код, используемый в этом приложении, на Github-репо .

Перейдите в каталог VideoKoler и откройте index.html . Добавьте следующее после тега script который включает файл cordova.js . Это пути к установленным ранее библиотекам Angular Localstorage и PeerJS.

 <script src="lib/angular-local-storage/dist/angular-local-storage.js"></script> <script src="lib/peerjs/peer.min.js"></script> 

Добавьте нужные нам контроллеры после тега script который ссылается на файл app.js. Есть 2 контроллера, один для обработки логина и один для звонков.

 <script src="js/controllers/IndexController.js"></script> <script src="js/controllers/CallController.js"></script> 

Внутри тега body добавьте директиву ion-nav-view . Это позволяет отображать различные шаблоны в зависимости от текущего состояния. Замените текущее содержимое тега body на следующее.

 <body ng-app="starter"> <ion-nav-view></ion-nav-view> </body> 

Создайте папку с шаблонами внутри www и добавьте файл index.html и файл videocall.html .

Файл index.html содержит шаблон для домашней страницы приложения. Имеет текстовое поле для ввода имени пользователя и кнопку входа. Запомните имя контроллера, название модели, назначенной текстовому полю, и функцию, вызываемую при нажатии кнопки входа в систему. Они будут объявлены и использованы позже в контроллере.

 <ion-header-bar class="bar-stable"> <h1 class="title">VideoKoler</h1> </ion-header-bar> <ion-content class="padding has-header" ng-controller="IndexController"> <div class="list"> <label class="item item-input"> <span class="input-label">Your Username</span> <input type="text" ng-model="username"> </label> </div> <button class="button button-positive button-block" ng-click="login()"> Login </button> </ion-content> 

videocall.html содержит шаблон для вызова другого пользователя. В верхней части макета находится контейнер с видео, который по умолчанию пуст. Видео будет добавлено после начала звонка. Он отображает имя пользователя, выбранное пользователем, и запрашивает имя пользователя для вызова.

В нижней части макета находится кнопка для инициирования вызова. Как и в предыдущем шаблоне, обратите внимание на значения, данные атрибутам ng-controller , ng-model и ng-click .

 <ion-header-bar class="bar-stable"> <h1 class="title">VideoKoler</h1> </ion-header-bar> <ion-content class="padding has-header" ng-controller="CallController"> <div class="card"> <video id="contact-video" autoplay></video> </div> <div class="card"> <div class="item item-text-wrap"> Your Username: <strong>{{ username }}</strong> </div> </div> <div class="list"> <label class="item item-input"> <span class="input-label">Contact Username</span> <input type="text" ng-model="contact_username"> </label> </div> <button class="button button-positive button-block" ng-click="startCall()"> Call </button> </ion-content> 

Переход на сторону JavaScript приложения. Откройте js/app.js и добавьте Angular Localstorage в качестве зависимости. ionic добавляется по умолчанию, поэтому добавьте LocalStorageModule после него.

 angular.module('starter', ['ionic', 'LocalStorageModule']) 

Добавьте конфигурацию состояния. Для этого приложения есть 2 состояния. вход в систему, которая является страницей по умолчанию, и приложение, которое является главной страницей приложения, где происходят видеозвонки.

Состояние устанавливается с помощью метода state предоставляемого $stateProvider . Этот метод принимает имя состояния в качестве первого аргумента и объект, содержащий параметры, в качестве второго.

Для опций, url и templateUrl — это все, что нужно. Где url — это URL, к которому осуществляется доступ для активированного состояния. templateUrl — путь файловой системы к шаблону, используемому этим состоянием.

 .config(function ($stateProvider, $urlRouterProvider) { $stateProvider .state('login', { url: '/login', templateUrl: 'templates/index.html' }) .state('app', { url: '/app', templateUrl: 'templates/videocall.html' }); $urlRouterProvider.otherwise('/login'); //set default page }); 

Затем создайте файл IndexController.js в каталоге js / controllers и добавьте следующее.

 (function(){ angular.module('starter') .controller('IndexController', ['localStorageService', '$scope', '$state', IndexController]); function IndexController(localStorageService, $scope, $state){ $scope.login = function(){ var username = $scope.username; localStorageService.set('username', username); $state.go('app'); }; } })(); 

Разбить этот код. Все обернуто в немедленно вызванное выражение функции.

 (function(){ })() 

Присоедините контроллер к модулю starter . Этот модуль был создан ранее в файле js / app.js. Контроллер использует localStorageService который доступен модулем Angular Localstorage. Помимо этого, есть $scope который используется в этом контроллере для установки и получения переменных и функций в текущую область. Наконец, есть $state который используется для перехода в другое состояние.

  angular.module('starter') .controller('IndexController', ['localStorageService', '$scope', '$state', IndexController]); 

Контроллер делает одну вещь. Это где функция login в login прикреплена к $scope . После нажатия кнопки входа в систему эта функция выполняется.

Он получает текущее значение переменной username в $scope , сохраняет его в localstorage и перенаправляет на главную страницу приложения.

 function IndexController(localStorageService, $scope, $state){ $scope.login = function(){ var username = $scope.username; if(username){ localStorageService.set('username', username); $state.go('app'); } }; } 

Находясь в каталоге js / controllers , создайте файл CallController.js и добавьте следующее.

 (function(){ angular.module('starter') .controller('CallController', ['localStorageService', '$scope', '$ionicPopup', CallController]); function CallController(localStorageService, $scope, $ionicPopup){ $scope.username = localStorageService.get('username'); var peer = new Peer($scope.username, { key: 'your peerserver cloud key', config: {'iceServers': [ { url: 'stun:stun1.l.google.com:19302' }, { url: 'turn:numb.viagenie.ca', credential: 'muazkh', username: '[email protected]' } ]} }); /* if you run your own peerserver var peer = new Peer($scope.username, { host: 'your-peerjs-server.com', port: 3000, path: '/peerjs', config: {'iceServers': [ { url: 'stun:stun1.l.google.com:19302' }, { url: 'turn:numb.viagenie.ca', credential: 'muazkh', username: '[email protected]' } ]} }); */ function getVideo(successCallback, errorCallback){ navigator.webkitGetUserMedia({audio: true, video: true}, successCallback, errorCallback); } function onReceiveCall(call){ $ionicPopup.alert({ title: 'Incoming Call', template: 'Someone is calling you. Connecting now..' }); getVideo( function(MediaStream){ call.answer(MediaStream); }, function(err){ $ionicPopup.alert({ title: 'Error', template: 'An error occurred while try to connect to the device mic and camera' }); } ); call.on('stream', onReceiveStream); } function onReceiveStream(stream){ var video = document.getElementById('contact-video'); video.src = window.URL.createObjectURL(stream); video.onloadedmetadata = function(){ $ionicPopup.alert({ title: 'Call Ongoing', template: 'Call has started. You can speak now' }); }; } $scope.startCall = function(){ var contact_username = $scope.contact_username; getVideo( function(MediaStream){ var call = peer.call(contact_username, MediaStream); call.on('stream', onReceiveStream); }, function(err){ $ionicPopup.alert({ title: 'Error', template: 'An error occurred while try to connect to the device mic and camera' }); } ); }; peer.on('call', onReceiveCall); } })(); 

Взломать код Сначала мы получаем имя пользователя из локального хранилища.

 $scope.username = localStorageService.get('username'); 

Создайте новый узел, который использует имя пользователя в качестве идентификатора узла. Затем укажите ключ облака равноправного сервера в качестве значения параметра key . (Вы можете найти свой ключ на панели инструментов PeerJS .)

Затем добавьте конфигурацию сервера ICE (Interactive Connectivity Establishment) с помощью параметра config . Это важно, поскольку облако peerserver служит только в качестве сервера сигнализации. Это означает, что он используется только для обмена данными между пирами. Сервер ICE необходим для прохождения через NAT (сеть) и межсетевые экраны. Вы можете найти список свободно доступных серверов ICE здесь .

 var peer = new Peer($scope.username, { key: 'your peerserver cloud key', config: {'iceServers': [ { url: 'stun:stun1.l.google.com:19302' }, { url: 'turn:numb.viagenie.ca', credential: 'muazkh', username: '[email protected]' } ]} }); 

Если вы используете свой собственный сервер, вы должны указать host , port и path вместо key . Тогда вы можете использовать те же значения для config .

 var peer = new Peer($scope.username, { host: 'your-peerjs-server.com', port: 3000, path: '/peerjs', config: {'iceServers': [ { url: 'stun:stun1.l.google.com:19302' }, { url: 'turn:numb.viagenie.ca', credential: 'muazkh', username: '[email protected]' } ]} } ); 

Создайте функцию для запроса микрофона и камеры из браузера. Это использует Media Capture API . Его можно использовать в Chrome с помощью navigator.webkitGetUserMedia . Это принимает объект, содержащий ограничения, в качестве первого аргумента. В приведенном ниже примере для audio и video установлено значение true . Это говорит браузеру запрашивать доступ как к микрофону, так и к камере. Второй и третий аргументы — это обратные вызовы об успехе и ошибке. Они передаются в функцию после ее вызова.

 function getVideo(successCallback, errorCallback){ navigator.webkitGetUserMedia({audio: true, video: true}, successCallback, errorCallback); } 

Создайте функцию, которая будет выполняться при получении вызова от другого партнера. Объект, содержащий текущий вызов, передается в качестве аргумента. Внутри функции он информирует пользователя о том, что вызов получен с помощью ионного оповещения. Затем продолжается вызов функции getVideo . Когда успешный обратный вызов выполняется, он возвращает MediaStream который затем может быть использован для ответа на вызов. Если обратный вызов ошибки выполнен, он сообщает пользователю, что произошла ошибка. Наконец, прослушайте stream событие на вызове. Когда это событие происходит, onReceiveStream функция onReceiveStream .

 function onReceiveCall(call){ $ionicPopup.alert({ title: 'Incoming Call', template: 'Someone is calling you. Connecting now..' }); getVideo( function(MediaStream){ call.answer(MediaStream); }, function(err){ $ionicPopup.alert({ title: 'Error', template: 'An error occurred while try to connect to the device mic and camera' }); } ); call.on('stream', onReceiveStream); } 

Функция onReceiveStream выполняется, когда поток мультимедиа получен от другого партнера. Поток может затем использоваться в качестве источника для элемента видео. Как только все метаданные будут загружены, сообщите пользователю, что вызов начался.

 function onReceiveStream(stream){ var video = document.getElementById('contact-video'); video.src = window.URL.createObjectURL(stream); video.onloadedmetadata = function(){ $ionicPopup.alert({ title: 'Call Ongoing', template: 'Call has started. You can speak now' }); }; } 

Объявите функцию для инициирования вызова. Это принимает текущее значение contact_username в $scope . Это имя пользователя, используемое другим пользователем при getVideo в систему. Затем getVideo функция getVideo и она возвращает медиапоток, который используется для инициирования вызова другому партнеру. Это делается с помощью метода call в одноранговой сети. Это принимает имя пользователя другого узла в качестве первого аргумента и поток мультимедиа в качестве второго. Затем он возвращает объект, который вы можете использовать для прослушивания события stream . Как и в onReceiveCall функции onReceiveCall , onReceiveStream вызывается, как только происходит это событие. Это позволяет инициатору вызова получать поток от другого партнера.

 $scope.startCall = function(){ var contact_username = $scope.contact_username; getVideo( function(MediaStream){ var call = peer.call(contact_username, MediaStream); call.on('stream', onReceiveStream); }, function(err){ $ionicPopup.alert({ title: 'Error', template: 'An error occurred while try to connect to the device mic and camera' }); } ); }; 

развертывание

Теперь мы готовы развернуть приложение на устройстве Android. Перейдите в каталог platform / android и откройте файл AndroidManifest.xml . Добавьте следующее как manifest тега manifest если они еще не существуют.

 <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> 

Выполните следующее, чтобы построить приложение.

 ionic build android 

После завершения сборки вы можете получить файл apk в каталоге platform / android / build / output / apk . Поскольку используется Crosswalk, для процессоров ARM и x86 создаются отдельные apk. Вы уже знаете, что Crosswalk устанавливает веб-вид последней версии Chrome. Это означает, что apk становится больше по размеру, чем обычный (по умолчанию Android WebView). Это причина, почему отдельный apk генерируется для каждой архитектуры. Потому что, если он объединен в один файл apk, который работает на обоих процессорах, он будет еще больше. Вы можете выбрать любой из следующих файлов в зависимости от вашего устройства.
— android-armv7-debug.apk
— android-x86-debug.apk

Вывод

Это оно! Из этого руководства вы узнали, как создать приложение для видеовызовов для Android с использованием Ionic, Crosswalk и PeerJS. Пожалуйста, дайте мне знать, если у вас есть какие-либо вопросы, комментарии или проблемы в комментариях ниже.