WebRTC Cookbook

Post on 31-Jan-2017

331 views 15 download

Transcript of WebRTC Cookbook

WebRTCCookbook

TableofContents

WebRTCCookbook

Credits

AbouttheAuthor

AbouttheReviewers

www.PacktPub.com

Supportfiles,eBooks,discountoffers,andmore

WhySubscribe?

FreeAccessforPacktaccountholders

Preface

Whatthisbookcovers

Whatyouneedforthisbook

Whothisbookisfor

Conventions

Readerfeedback

Customersupport

Downloadingtheexamplecode

Downloadingthecolorimagesofthisbook

Errata

Piracy

Questions

1.PeerConnections

Introduction

BuildingasignalingserverinErlang

Gettingready

Howtodoit…

Howitworks…

There’smore…

Seealso

BuildingasignalingserverinJava

Gettingready

Howtodoit…

Howitworks…

There’smore…

Seealso

DetectingWebRTCfunctionssupportedbyabrowser

Gettingready

Howtodoit…

Howitworks…

There’smore…

Seealso

Makingandansweringcalls

Gettingready

Howtodoit…

Makingacall

Answeringacall

Howitworks…

There’smore…

Seealso

Implementingachatusingdatachannels

Gettingready

Howtodoit…

CreatingthemainHTMLpageoftheapplication

CreatingtheJavaScripthelperlibrary

Howitworks…

There’smore…

Seealso

Implementingachatusingasignalingserver

Howtodoit…

Howitworks…

There’smore…

Seealso

ConfiguringandusingSTUN

Gettingready

Howtodoit…

Howitworks…

There’smore…

Seealso

ConfiguringandusingTURN

Gettingready

Howtodoit…

InstallingtheTURNserver

UsingTURNinWebRTCapplication

Howitworks…

There’smore…

Seealso

2.SupportingSecurity

Introduction

Generatingaself-signedcertificate

Gettingready

Howtodoit…

Howitworks…

There’smore…

Seealso

ConfiguringaTURNserverwithauthentication

Gettingready

Howtodoit…

Implementingtheclient-sidecode

Implementingtheserver-sidecode

Howitworks…

There’smore…

Seealso

ConfiguringawebservertoworkoverHTTPS

Gettingready

Howtodoit…

ConfiguringNginx

ConfiguringApache

ConfiguringIIS

There’smore…

Seealso

ConfiguringaWebSocketsproxyonthewebserver

Gettingready

Howtodoit…

ConfiguringNginx

ConfiguringApache

ConfiguringIIS

Howitworks…

There’smore…

Seealso

Configuringafirewall

Gettingready

Howtodoit…

Configuringafirewallonaserver

Configuringafirewallonaclient

Seealso

3.IntegratingWebRTC

Introduction

IntegratingWebRTCwithAsterisk

Gettingready

Howtodoit…

InstallinglibSRTP

InstallingAsterisk

Howitworks…

There’smore…

Seealso

IntegratingWebRTCwithFreeSWITCH

Gettingready

Howtodoit…

InstallingFreeSWITCH

EnablingWebRTC

StartingFreeSWITCH

Howitworks…

There’smore…

Seealso

Makingcallsfromawebpage

Gettingready

Howtodoit…

InstallingsipML5

Howitworks…

There’smore…

Seealso

IntegrationofWebRTCwithwebcameras

Gettingready

Howtodoit…

Configuringthewebcam

InstallingWebRTCmediaserver

Timeformagic

Howitworks…

There’smore…

4.DebuggingaWebRTCApplication

Introduction

WorkingwithaWebRTCstatisticsAPI

Gettingready

Howtodoit…

Checkingestimatedbandwidth

Checkingpacketloss

Howitworks…

There’smore…

Seealso

DebuggingwithChrome

Gettingready

Howtodoit…

Usingwebrtc-internals

UsingChromeloggingmechanism

Howitworks…

There’smore…

Seealso

DebuggingTURN

Gettingready

Howtodoit…

Howitworks…

There’smore…

Seealso

DebuggingusingWireshark

Gettingready

Howtodoit…

Howitworks…

There’smore…

Seealso

5.WorkingwithFilters

Introduction

Workingwithcolorsandgrayscale

Howtodoit…

Howitworks…

Workingwithbrightness

Howtodoit…

Howitworks…

Workingwithcontrast

Howtodoit…

Howitworks…

Workingwithsaturation

Howtodoit…

Howitworks…

Workingwithhue

Howtodoit…

Howitworks…

Usingthesepiafilter

Howtodoit…

Howitworks…

Usingtheopacityfilter

Howtodoit…

Howitworks…

Invertingcolors

Howtodoit…

Howitworks…

Implementingtheblureffect

Howtodoit…

Howitworks…

Implementingthedroppedshadoweffect

Howtodoit…

Howitworks…

Combiningfilters

Howtodoit…

Howitworks…

Customvideoprocessing

Howtodoit…

Howitworks…

6.NativeApplications

Introduction

BuildingacustomizedWebRTCdemoforiOS

Gettingready

Howtodoit…

There’smore…

BuildingademoprojectforaiOSsimulator

Seealso

CompilingandrunninganoriginaldemoforiOS

Gettingready

Howtodoit…

BuildingademoprojectforaniOSdevice

BuildingademoprojectforaniOSsimulator

There’smore…

Seealso

CompilingandrunningademoforAndroid

Gettingready

Preparingthesystem

InstallingOracleJDK

GettingtheWebRTCsourcecode

InstallingAndroidDeveloperTools

Howtodoit…

RunningontheAndroidsimulator

FixingabugwithGLSurfaceView

RunningonaphysicalAndroiddevice

There’smore…

Seealso

BuildinganOpenWebRTClibrary

Gettingready

Howtodoit…

There’smore…

7.Third-partyLibraries

Introduction

BuildingavideoconferenceusingSimpleWebRTC

Gettingready

Howtodoit…

Howitworks…

There’smore…

CreatinganapplicationusingRTCMultiConnection

Gettingready

Howtodoit…

Howitworks…

There’smore…

DevelopingasimpleWebRTCchatusingPeerJS

Gettingready

Howtodoit…

Howitworks…

There’smore…

Makingasimplevideochatwithrtc.io

Gettingready

Howtodoit…

Howitworks…

There’smore…

UsingOpenToktocreateaWebRTCapplication

Gettingready

Howtodoit…

Howitworks…

There’smore…

CreatingamultiuserconferenceusingWebRTCO

Gettingready

Howtodoit…

Howitworks…

There’smore…

8.AdvancedFunctions

Introduction

Visualizingamicrophone’ssoundlevel

Gettingready

Howtodoit…

Howitworks…

Seealso

Mutingamicrophone

Gettingready

Howtodoit…

Howitworks…

There’smore…

Seealso

Pausingavideo

Gettingready

Howtodoit…

Howitworks…

Seealso

Takingascreenshot

Gettingready

Howtodoit…

Howitworks…

Seealso

Streamingmedia

Gettingready

Howtodoit…

Howitworks…

Seealso

Index

WebRTCCookbook

WebRTCCookbookCopyright©2015PacktPublishing

Allrightsreserved.Nopartofthisbookmaybereproduced,storedinaretrievalsystem,ortransmittedinanyformorbyanymeans,withoutthepriorwrittenpermissionofthepublisher,exceptinthecaseofbriefquotationsembeddedincriticalarticlesorreviews.

Everyefforthasbeenmadeinthepreparationofthisbooktoensuretheaccuracyoftheinformationpresented.However,theinformationcontainedinthisbookissoldwithoutwarranty,eitherexpressorimplied.Neithertheauthor,norPacktPublishing,anditsdealersanddistributorswillbeheldliableforanydamagescausedorallegedtobecauseddirectlyorindirectlybythisbook.

PacktPublishinghasendeavoredtoprovidetrademarkinformationaboutallofthecompaniesandproductsmentionedinthisbookbytheappropriateuseofcapitals.However,PacktPublishingcannotguaranteetheaccuracyofthisinformation.

Firstpublished:February2015

Productionreference:1200215

PublishedbyPacktPublishingLtd.

LiveryPlace

35LiveryStreet

BirminghamB32PB,UK.

ISBN978-1-78328-445-0

www.packtpub.com

CreditsAuthor

AndriiSergiienko

Reviewers

PasqualeBoemio

JoseLópez

MarcosdeVeraPiquero

CommissioningEditor

UshaIyer

AcquisitionEditor

SamWood

ContentDevelopmentEditor

RahulNair

TechnicalEditor

SiddhiRane

CopyEditor

NehaVyas

ProjectCoordinator

JudieJose

Proofreaders

TingBaker

SimranBhogal

MariaGould

PaulHindle

Indexer

HemanginiBari

ProductionCoordinator

MelwynDsa

CoverWork

MelwynDsa

AbouttheAuthorAndriiSergiienkoisacomputersoftwaredeveloperfromUkraineandispassionateaboutinformationtechnologies.Fromhisearlychildhood,hewasinterestedincomputerprogrammingandhardware.Hetookhisfirststepintothesefieldsmorethan20yearsago.HehasexperienceofawidesetoflanguagesandtechnologiesincludingC,C++,Java,assemblylanguage,Erlang,JavaScript,PHP,Riak,shellscripting,computernetworks,andsecurity.

Duringhiscareerheworkedforbothsmall,localcompaniessuchasdomesticISPandlarge,worldwidecorporationssuchasHewlettPackard.Healsostartedhisownprojects—someofthemwererelativelysuccessful.

Today,heistheownerandinspirerofOSLIKASOÜ,acomputersoftwarecompanywithheadquartersinEstonia.Thecompany(http://www.oslikas.com)focusesonmodernITtechnologiesandsolutions.

Workingonthisbookwasareallygreatandinterestingexperienceforme.Allthiswouldbeimpossiblewithoutthehelpofcertainpeople.Andnowisthetimeformetosaythankyoutothem.

Firstofall,IwouldliketothankmyparentsOlgaandAlexanderformyhappychildhoodthatestablishedthefoundationformylifeandcareer.

IwouldliketosaythankyoutomywifeInnaforherpatience,encouragement,andsupportduringthisprocess.

IwouldliketothankthePacktPublishingteamaswell.Theseguysaredoingreallygreatworkandmakingtheworldabetterplace.Wecontactedsomeofthemdirectlyduringthework,andothersstayedbehindthescenes.However,Iknowthatalotofpeoplespentpartoftheirlivestomakethisbookpossible.Thankyouall.

AbouttheReviewersPasqualeBoemiofellinlovewithLinuxandtheopensourcephilosophyattheageof12.Followingthispassion,hestudiedcomputerengineeringatUniversityofNaplesFedericoIIfromwherehegraduatedwithamaster’sdegree.

Currently,heisworkingasaresearcherintheDepartmentofElectricalEngineeringandInformationTechnology(DIETI)intheUniversityofNaplesFedericoII,contributingtothedevelopmentofreal-timecommunicationtechnologies.HiseffortsinthisfieldareconcretizedbysupportingtheMeetechoproject(www.meetecho.com).

Meetechoisauniversityspin-offandatoolforthecollaborativeworkcurrentlyusedbytheInternetEngineeringTaskForce(IETF)toprovideremoteparticipationtotheworkinggroups.Meetecholeveragessomestate-of-the-arttechnologies(suchasWebRTCandDocker)toimplementacomprehensivearchitecturethatcanbelightweightandportable.Meetecho’sbestprojectistheJanusWebRTCGateway(http://janus.conf.meetecho.com/),mentionedlaterinthisbook,whichallowsausertheabilitytointegratedifferent,real-timetechnologieswithoutanypains.

Inhissparetime,Pasqualeworksonsomepersonalopensourceprojects(https://github.com/helloIAmPau)andhelpsthecommunitybygivinghiscontributionstocoolprojectsfoundontheGitHubplatform.

HehasalreadyworkedwithPacktPublishingbyreviewingWebRTCIntegrator’sGuide,ausefulguideforanyonewhoneedstointegrateWebRTCwitharetrotechnologysuchasSIP.

JoseLópezwasborninGalicia,Spain.Heisatelecommunicationsengineerwithalargeamountofexperienceinsoftwaredevelopment,andisalsofocusedonreal-timeaudio/videocommunications.HestartedworkingforQuobisNetworksin2013,aleadingcompanyinWebRTCsolutions.

MarcosdeVeraPiqueroisasoftwareengineerwhohasmainlyworkedwithPythonandCoffeeScript.Hisareaofdevelopmentisnowfocusedontheserversideofreal-timemultimediaapplicationsatQuobis,hiscurrentemployer.He’salsoafreesoftwareenthusiastandistryingtomakeitarealalternative.

www.PacktPub.com

Supportfiles,eBooks,discountoffers,andmoreForsupportfilesanddownloadsrelatedtoyourbook,pleasevisitwww.PacktPub.com.

DidyouknowthatPacktofferseBookversionsofeverybookpublished,withPDFandePubfilesavailable?YoucanupgradetotheeBookversionatwww.PacktPub.comandasaprintbookcustomer,youareentitledtoadiscountontheeBookcopy.Getintouchwithusat<service@packtpub.com>formoredetails.

Atwww.PacktPub.com,youcanalsoreadacollectionoffreetechnicalarticles,signupforarangeoffreenewslettersandreceiveexclusivediscountsandoffersonPacktbooksandeBooks.

https://www2.packtpub.com/books/subscription/packtlib

DoyouneedinstantsolutionstoyourITquestions?PacktLibisPackt’sonlinedigitalbooklibrary.Here,youcansearch,access,andreadPackt’sentirelibraryofbooks.

WhySubscribe?FullysearchableacrosseverybookpublishedbyPacktCopyandpaste,print,andbookmarkcontentOndemandandaccessibleviaawebbrowser

FreeAccessforPacktaccountholdersIfyouhaveanaccountwithPacktatwww.PacktPub.com,youcanusethistoaccessPacktLibtodayandview9entirelyfreebooks.Simplyuseyourlogincredentialsforimmediateaccess.

PrefaceWebRTCisarelativelynewandrevolutionarytechnologythatopensnewhorizonsintheareaofinteractiveapplicationsandservices.Mostofthepopularwebbrowserssupportitnatively(suchasChromeandFirefox)orviaextensions(suchasSafari).MobileplatformssuchasAndroidandiOSallowyoutodevelopnativeWebRTCapplications.

ThisbookcoversawidesetoftopicsonhowtodevelopsoftwareusingaWebRTCstack.Usingpracticalrecipes,itconsidersbasicconcepts,security,debugging,integrationwithothertechnologies,andotherimportantthemesofthedevelopmentprocessinafriendlymanner.

YouwillnotonlylearnaboutWebRTC-specificfeatures,butalsoattendanttechnologies(CSS3,HTML5,andWebSockets),andhowtousethemalongwithWebRTC.

WhatthisbookcoversChapter1,PeerConnections,introducesyoutotheverybasicconceptsofWebRTC.Thisincludespracticalrecipesonpeerconnections.Youwillalsofindsimpledemoapplicationsinthischapter.

Chapter2,SupportingSecurity,leadsyouthroughvarioussecurity-relatedtopicsandcovershowtosecureatypicalWebRTCapplication’sinfrastructurecomponents:SSL/TLScertificates,WebSockets,webservers,STUN/TURN,datachannels,andmore.

Chapter3,IntegratingWebRTC,considersintegratingaWebRTCapplicationwithothertechnologiesandthird-partysoftware.Thischapterdescribespracticalcasesandsolutionsonintegration.

Chapter4,DebuggingaWebRTCApplication,isdedicatedtoapplicationdebugging—animportanttopicofthesoftwaredevelopmentprocess.Inthischapter,youwilllearnaboutthetopicsrelatingtodebugginginthescopeofWebRTC.

Chapter5,WorkingwithFilters,teachesyouhowtouseCSS3filterswithWebRTCapplications.Thischapteralsocoverscustomimageprocessing.

Chapter6,NativeApplications,containspractical,step-by-steprecipesdedicatedtodevelopingnativeWebRTCapplicationsonmobileplatforms.

Chapter7,Third-partyLibraries,describesgeneralusecasesandpracticalsolutionsbasedonthird-partyWebRTCframeworksandservices.

Chapter8,AdvancedFunctions,covershowtouseadvancedWebRTCfeatures.Itcontainspracticalrecipesonfiletransferring,streaming,audio/videocontrolling,andmore.

WhatyouneedforthisbookTousetherecipesandcodesprovidedandconsideredinthisbook,youwillneedafewpiecesofsoftwareinstalled:

JavaSE7:NotethatforAndroid-relatedrecipesfromChapter6,NativeApplications,youneedJavaSE6aswell—theinstallationandconfigurationprocessisdescribedindetailinthischapter.ErlangOTP17:Ifyou’refamiliarwiththisprogramminglanguage,youcanusethis.Ifnot,youcanskipit—allErlangexamplesarealsoprovidedinJava.MacOSXandXcode:UsethisforrecipesdedicatedtodevelopingWebRTCapplicationsoniOS.AndroidandiOS:UsethisforChapter6,NativeApplications,whichcovershowtodevelopWebRTCapplicationsformobileplatforms.Linux:Ubuntuisrecommended.ChromeandFirefox:ThesearestillthemostWebRTC-friendlywebbrowsers.

Specificrequirementsandconfigurationsalongwithsuggestedsolutionsareconsideredinparticularchapters.

WhothisbookisforThisbookiswrittenasasetofready-to-use,practicalrecipesthatcoveravarietyoftopicsrelatedtodevelopingWebRTCapplicationsandservices.Itisassumedthatyouarefamiliar,ingeneral,withWebRTCanditsbasicconcepts.

MostoftheprovidedrecipesarewritteninJavaScript.However,server-sidepartsofapplicationsareimplementedinErlangandJava.So,youareassumedtohaveatleastbasicexperiencewithoneofthesetechnologies.

Workingonsomecasesdescribedinthisbook,youwillhavetodealwithaLinux-basedOS.Allrecipesareprovidedasastep-by-stepguide.Although,ifyouhaveexperienceofworkingwithandconfiguringLinux-basedboxes,itwouldbeuseful.

So,thisbookisforsomeonewhoisfamiliar,ingeneral,withtheWebRTCstack,andwhohasatleastbasicskillsinsoftwaredevelopment.

ConventionsInthisbook,youwillfindanumberofstylesoftextthatdistinguishbetweendifferentkindsofinformation.Herearesomeexamplesofthesestyles,andanexplanationoftheirmeaning.

Codewordsintext,databasetablenames,foldernames,filenames,fileextensions,pathnames,dummyURLs,userinput,andTwitterhandlesareshownasfollows:“WecanincludeourcustomJavaScriptlibrarylocatedinthemylib.jsfile.”

Ablockofcodeissetasfollows:

-module(sigserver_app).

-behaviour(application).

-export([start/2,stop/1,start/0]).

start()->

ok=application:start(ranch),

ok=application:start(crypto),

ok=application:start(cowlib),

ok=application:start(cowboy),

Whenwewishtodrawyourattentiontoaparticularpartofacodeblock,therelevantlinesoritemsaresetinbold:

privatestaticMap<Integer,Set<WebSocket>>Rooms=newHashMap<>();

privateintmyroom;

publicMain(){

super(newInetSocketAddress(30001));

}

Anycommand-lineinputoroutputiswrittenasfollows:

rebarcreate-appappid=sigserver

Newtermsandimportantwordsareshowninbold.Wordsthatyouseeonthescreen,inmenusordialogboxesforexample,appearinthetextlikethis:“WhenthecustomerentersamessageandclicksontheSubmitquerybutton,wewillwrapthemessageintoaJSONobjectandsenditviathedatachannel.”

NoteWarningsorimportantnotesappearinaboxlikethis.

TipTipsandtricksappearlikethis.

ReaderfeedbackFeedbackfromourreadersisalwayswelcome.Letusknowwhatyouthinkaboutthisbook—whatyoulikedordisliked.Readerfeedbackisimportantforusasithelpsusdeveloptitlesthatyouwillreallygetthemostoutof.

Tosendusgeneralfeedback,simplye-mail<feedback@packtpub.com>,andmentionthebook’stitleinthesubjectofyourmessage.

Ifthereisatopicthatyouhaveexpertiseinandyouareinterestedineitherwritingorcontributingtoabook,seeourauthorguideatwww.packtpub.com/authors.

CustomersupportNowthatyouaretheproudownerofaPacktbook,wehaveanumberofthingstohelpyoutogetthemostfromyourpurchase.

DownloadingtheexamplecodeYoucandownloadtheexamplecodefilesfromyouraccountathttp://www.packtpub.comforallthePacktPublishingbooksyouhavepurchased.Ifyoupurchasedthisbookelsewhere,youcanvisithttp://www.packtpub.com/supportandregistertohavethefilese-maileddirectlytoyou.

DownloadingthecolorimagesofthisbookWealsoprovideyouwithaPDFfilethathascolorimagesofthescreenshots/diagramsusedinthisbook.Thecolorimageswillhelpyoubetterunderstandthechangesintheoutput.Youcandownloadthisfilefrom:https://www.packtpub.com/sites/default/files/downloads/4450OS_ColoredImages.pdf.

ErrataAlthoughwehavetakeneverycaretoensuretheaccuracyofourcontent,mistakesdohappen.Ifyoufindamistakeinoneofourbooks—maybeamistakeinthetextorthecode—wewouldbegratefulifyoucouldreportthistous.Bydoingso,youcansaveotherreadersfromfrustrationandhelpusimprovesubsequentversionsofthisbook.Ifyoufindanyerrata,pleasereportthembyvisitinghttp://www.packtpub.com/submit-errata,selectingyourbook,clickingontheErrataSubmissionFormlink,andenteringthedetailsofyourerrata.Onceyourerrataareverified,yoursubmissionwillbeacceptedandtheerratawillbeuploadedtoourwebsiteoraddedtoanylistofexistingerrataundertheErratasectionofthattitle.

Toviewthepreviouslysubmittederrata,gotohttps://www.packtpub.com/books/content/supportandenterthenameofthebookinthesearchfield.TherequiredinformationwillappearundertheErratasection.

PiracyPiracyofcopyrightedmaterialontheInternetisanongoingproblemacrossallmedia.AtPackt,wetaketheprotectionofourcopyrightandlicensesveryseriously.IfyoucomeacrossanyillegalcopiesofourworksinanyformontheInternet,pleaseprovideuswiththelocationaddressorwebsitenameimmediatelysothatwecanpursuearemedy.

Pleasecontactusat<copyright@packtpub.com>withalinktothesuspectedpiratedmaterial.

Weappreciateyourhelpinprotectingourauthorsandourabilitytobringyouvaluablecontent.

QuestionsIfyouhaveaproblemwithanyaspectofthisbook,youcancontactusat<questions@packtpub.com>,andwewilldoourbesttoaddresstheproblem.

Chapter1.PeerConnectionsInthischapter,wewillcoverthefollowingtopics:

BuildingasignalingserverinErlangBuildingasignalingserverinJavaDetectingWebRTCfunctionssupportedbyabrowserMakingandansweringcallsImplementingachatusingdatachannelsImplementingachatusingasignalingserverConfiguringandusingSTUNConfiguringandusingTURN

IntroductionThischaptercoversthebasicconceptsofhowtouseWebRTCwhendevelopingrichmediawebapplicationsandservices.

Withsimpleandshortrecipes,youwilllearnhowtocreateyourownsignalingserver.Thekeydatathatneedstobeexchangedbypeersbeforetheyestablishadirectconnectioniscalledthesessiondescription—itspecifiesthepeers’configuration.Signalingserverisacomponentinanapplication’sinfrastructurethatisaccessiblebyallpeersandservestoexchangemultimedia’ssessiondescription.ThewaypeersshouldexchangedataisnotdescribedbyWebRTCstandards,soyoushouldmakethedecisiononyourownregardingtheprotocolandmechanismyouwilluseforthistask.

Youcanbuildasignalingserverusinganyprogramminglanguageandtechnologyyoulike.Ingeneral,thesignalingprotocolcanbenon-technicalandispossibletoimplementinawaywherethepeerswouldusejustasheetofpapertoexchangenecessarydatabetweeneachother.Inthischapter,weuseWebSockettoimplementsignaling,althoughyoucanuseanyotherprotocol.

Thesignalingstageisrepresentedintheschemathatisshowninthefollowingdiagram:

Inthischapter,youwillfindtworecipesthatarededicatedtosignalingserverdevelopment:BuildingasignalingserverinErlangandBuildingasignalingserverinJava.Javaisprobablythemostpopularandknowntechnology,anditwouldbeeasytogetintothistopicusingJava,evenifyoudon’thaveprogrammingexperiencewiththistechnology.Erlangisnotwidelyknownyet.Nonetheless,thisisaverymaturetechnology,verysuitableforwritinglightweightandextremelyfastserverapplicationswithperfect

scalability.So,bylearningsignalingserver,youwillfindsimplesolutionsinErlangaswell.

ThischapteralsocoversthebasicusecaseofhowtouseWebRTCdatachannels:filetransferringandpeer-to-peerchat.

YouwillalsolearnhowtoconfigureanduseSessionTraversalUtilitiesforNAT(STUN)andTraversalUsingRelaysaroundNAT(TURN)services,andofcourse,thischaptercoversmakingpeer-to-peercallsusingWebRTC.

Notethatinthischapter,wewillcovertheprocessofmakingcomputer-to-computercalls.IfyouwanttoknowmoreabouthowtouseWebRTCwithVoIPandSIP,andhowtomakephonecallsfromawebpage,refertotheChapter3,IntegratingWebRTC.

BuildingasignalingserverinErlangThefollowingrecipeshowshowtobuildsignalingserverusingErlangprogramminglanguageandWebSocketsfortransportprotocol.WewillnotintroduceErlangprogramminginthisrecipe,soyoushouldhaveatleastbasicknowledgeofthisprogramminglanguageanditsrelevanttechnologies.

GettingreadyTousethissolution,youshouldhaveErlanginstalledonyoursystemtostartwith.YoucandownloadtheErlangdistributionrelevanttoyoursystemfromitshomepagehttp://www.erlang.org/download.html.Theinstallationprocessmightneedspecificactionsrelevanttospecificplatforms/OSes,sofollowtheofficialinstallationinstructionsathttp://www.erlang.org/doc/installation_guide/INSTALL.html.

TipForthisexample,I’veusedErlang17.YoumightneedtoaddsomeminorchangestothecodetomakeitworkunderfutureversionsofErlang.

WewillalsousetheGitversioningsystemtodownloadadditionalpacketsandcomponentsnecessaryforoursolution,soyoushoulddownloadandinstallGitdistributionrelevanttoyoursystem.Youcandownloadthisfromhttp://www.git-scm.com.Asabuildtoolfortheproject,wewilluseRebar;youshouldalsodownloadandinstallitfromhttps://github.com/basho/rebar.

Howtodoit…ThefollowingstepswillleadyouthroughtheprocessofbuildingasignalingserverusingErlang:

1. Createanewfolderforthesignalingserverapplicationandnavigatetoit.2. UsingtheRebartool,createabasicErlangapplication:

rebarcreate-appappid=sigserver

Thiscommandwillcreateansrcfolderandrelevantapplicationfilesinit.

3. Createtherebar.configfile,andputthefollowingRebarconfigurationinit:

{erl_opts,[warnings_as_errors]}.

{deps,

[

{'gproc',".*",{

git,"git://github.com/esl/gproc.git",{tag,"0.2.16"}

}},

{'jsonerl',".*",{

git,"git://github.com/fycth/jsonerl.git","master"

}},

{'cowboy',".*",{

git,"https://github.com/extend/cowboy.git","0.9.0"

}}

]}.

4. Openthesrc/sigserver.app.srcfileandaddthefollowingcomponentstotheapplication’ssectionlist:cowlib,cowboy,compiler,andgproc.

5. Openthesrc/sigserver_app.erlfileandaddthefollowingcode:

-module(sigserver_app).

-behaviour(application).

-export([start/2,stop/1,start/0]).

start()->

ok=application:start(ranch),

ok=application:start(crypto),

ok=application:start(cowlib),

ok=application:start(cowboy),

ok=application:start(gproc),

ok=application:start(compiler),

ok=application:start(sigserver).

start(_StartType,_StartArgs)->

Dispatch=cowboy_router:compile([

{'_',[

{"/",handler_websocket,[]}

]}

]),

{ok,_}=cowboy:start_http(websocket,100,[{ip,{127,0,0,1}},

{port,30001}],[

{env,[{dispatch,Dispatch}]},

{max_keepalive,50},

{timeout,500}]),

sigserver_sup:start_link().

stop(_State)->ok.

6. Createthesrc/handler_websocket.erlfileandputthefollowingcodeinit:

-module(handler_websocket).

-behaviour(cowboy_websocket_handler).

-export([init/3]).

-export([websocket_init/3,websocket_handle/3,

websocket_info/3,websocket_terminate/3]).

-record(state,{

client=undefined::undefined|binary(),

state=undefined::undefined|connected|running,

room=undefined::undefined|integer()

}).

init(_Any,_Req,_Opt)->

{upgrade,protocol,cowboy_websocket}.

websocket_init(_TransportName,Req,_Opt)->

{Client,Req1}=cowboy_req:header(<<"x-forwarded-for">>,Req),

State=#state{client=Client,state=connected},

{ok,Req1,State,hibernate}.

websocket_handle({text,Data},Req,State)->

StateNew=case(State#state.state)of

started->

State#state{state=running};

_->

State

end,

JSON=jsonerl:decode(Data),

{M,Type}=element(1,JSON),

caseMof

<<"type">>->

caseTypeof

<<"GETROOM">>->

Room=generate_room(),

R=iolist_to_binary(jsonerl:encode({{type,

<<"GETROOM">>},{value,Room}})),

gproc:reg({p,l,Room}),

S=(StateNew#state{room=Room}),

{reply,{text,<<R/binary>>},Req,S,hibernate};

<<"ENTERROOM">>->

{<<"value">>,Room}=element(2,JSON),

Participants=gproc:lookup_pids({p,l,Room}),

caselength(Participants)of

1->

gproc:reg({p,l,Room}),

S=(StateNew#state{room=Room}),

{ok,Req,S,hibernate};

_->

R=iolist_to_binary(jsonerl:encode({{type,

<<"WRONGROOM">>}})),

{reply,{text,<<R/binary>>},Req,

StateNew,hibernate}

end;

_->

reply2peer(Data,StateNew#state.room),

{ok,Req,StateNew,hibernate}

end;

_->

reply2peer(Data,State#state.room),

{ok,Req,StateNew,hibernate}

end;

websocket_handle(_Any,Req,State)->{ok,Req,State,hibernate}.

websocket_info(_Info,Req,State)->{reply,{text,_Info},Req,State,

hibernate}.

websocket_terminate(_Reason,_Req,_State)->ok.

reply2peer(R,Room)->

[P!<<R/binary>>||P<-gproc:lookup_pids({p,l,Room})—[self()]].

generate_room()->

random:seed(now()),

random:uniform(999999).

7. NowwecancompilethesolutionusingtheRebartool:

rebarget-deps

rebarcompile

Ifeverythingwassuccessful,youshouldnotseeanyerrors(warningsarenotcritical).

8. Afterwebuildoursignalingserver,wecanstartitusingthefollowingcommand:

erl-padeps/*/ebinebin-saslerrlog_typeerror-ssigserver_app

TipWindows-basedsystemscan’tuseastarsymbolinsuchconstructions,soifyou’reworkingunderWindows,youshouldusethefullpathnameasshowninthefollowingcommand:

erl-padeps/cowboy/ebindeps/cowlib/ebindeps/gproc/ebin

deps/jsonerl/ebindeps/ranch/ebinebin-saslerrlog_typeerror-s

sigserver_app

Nowyoursignalingservershouldberunning,andyouneedtolistenforincomingWebSocketconnectionsonport30001.

Notethatfullsourcecodesaresuppliedwiththisbook.

TipDownloadingtheexamplecode

Youcandownloadtheexamplecodefilesfromyouraccountathttp://www.packtpub.comforallthePacktPublishingbooksyouhavepurchased.Ifyoupurchasedthisbookelsewhere,youcanvisithttp://www.packtpub.com/supportandregistertohavethefilese-maileddirectlytoyou.

Howitworks…Inthisrecipe,weimplementedtheWebRTCsignalingserverinErlang.Theapplicationlistensonport30001forincomingWebSocketconnectionsfromthebrowserclients.

Thefirstpeerwillberegisteredbytheserverinavirtualroomandwillgettheroomnumber.Thesecondpeerafterthatcanusetheroomnumberinordertoconnecttothefirstpeer.Thesignalingserverwillcheckwhetherthevirtualroomexistsandifso,itwillroutecall/answerrequestsandanswersbetweenthepeersinordertomakethemestablishadirectpeer-to-peerWebRTCconnection.

There’smore…Basically,thisisaverysimplesignalingserver.Itdoesn’thaveanyadvancedfeatures,andthemaingoalofitistohelppeersestablishdirectconnectionbetweeneachother.Nevertheless,asignalingservercanserveadditionaltasks.Forexample,itcanserveforwebchats,filetransfers,servicedataexchanges,andotherfeaturesspecificforcertainsituations.Therearenocertainrequirementsforasignalingserver;youcanimplementitusingyourfavoriteprogramminglanguageandtechnology.

SeealsoFortipsonimplementingasignalingserverinJava,refertotheBuildingasignalingserverinJavarecipeYoucanalsorefertotheMakingandansweringcallsrecipeonhowtouseasignalingserverfromabrowserapplicationusingJavaScript

BuildingasignalingserverinJavaInthisrecipe,wewillcovertheimplementationofasignalingserverinJava.

GettingreadyThisrecipeusesJava,soyoushouldhaveJavaDeveloperKit(JDK)installedonyourmachine.YoucandownloadtheappropriateversionofJDKforyourplatformfromitswebpageathttp://www.java.com.

Java7hasitsownAPItoimplementaWebSocketapplication.PreviousversionsofJavadon’thavethenativesupportofWebSockets.Inthisrecipe,wewillcovertheuniversalsolutionthatworksindifferentJavaversionsandisbasedonthethird-partycomponent,whichyoucanfindonitshomepageathttp://java-websocket.org.ThisprojectisalsopresentonGitHubathttps://github.com/TooTallNate/Java-WebSocket.

YouneedtodownloadandinstalltheJava-WebSocketlibrary;itshouldthenbelinkedtoyourproject.

Inthisrecipe,wepacksignalingmessagesintotheJSONformatbeforesending,soweneedaJavalibrarytoworkwithJSONstructures.Forthispurpose,wewilluseJavaclassesfromJSON’shomepage,http://www.json.org/java/.

Downloadtheseclassesandlinkthemtoyourproject,oryoucanjustputtheseclassesintoyourproject’sfolderstructureandcompileitalltogether.

ItisassumedthatyouhaveexperienceofprogramminginJava,sowewillnotcoverthebasicquestionslikehowtostartaJavaapplicationandsoon.

Howtodoit…CreateanewprojectinyourJavaIDEandlinktheJSONlibrariesalongwiththeJava-WebSocketlibrary.

Thefollowingcoderepresentsasimplesignalingserver.CompileitandstartaJavaconsoleapplicationasusual:

packagecom.webrtcexample.signaler;

importorg.java_websocket.WebSocket;

importorg.java_websocket.handshake.ClientHandshake;

importorg.java_websocket.server.WebSocketServer;

importorg.json.JSONException;

importorg.json.JSONObject;

importjava.net.InetSocketAddress;

importjava.util.*;

publicclassMainextendsWebSocketServer{

privatestaticMap<Integer,Set<WebSocket>>Rooms=newHashMap<>();

privateintmyroom;

publicMain(){

super(newInetSocketAddress(30001));

}

@Override

publicvoidonOpen(WebSocketconn,ClientHandshakehandshake){

System.out.println("Newclientconnected:"+

conn.getRemoteSocketAddress()+"hash"+

conn.getRemoteSocketAddress().hashCode());

}

@Override

publicvoidonMessage(WebSocketconn,Stringmessage){

Set<WebSocket>s;

try{

JSONObjectobj=newJSONObject(message);

Stringmsgtype=obj.getString("type");

switch(msgtype){

case"GETROOM":

myroom=generateRoomNumber();

s=newHashSet<>();

s.add(conn);

Rooms.put(myroom,s);

System.out.println("Generatednewroom:"+myroom);

conn.send("{\"type\":\"GETROOM\",\"value\":"+myroom+

"}");

break;

case"ENTERROOM":

myroom=obj.getInt("value");

System.out.println("Newcliententeredroom"+

myroom);

s=Rooms.get(myroom);

s.add(conn);

Rooms.put(myroom,s);

break;

default:

sendToAll(conn,message);

break;

}

}catch(JSONExceptione){

sendToAll(conn,message);

}

System.out.println();

}

@Override

publicvoidonClose(WebSocketconn,intcode,Stringreason,boolean

remote){

System.out.println("Clientdisconnected:"+reason);

}

@Override

publicvoidonError(WebSocketconn,Exceptionexc){

System.out.println("Errorhappened:"+exc);

}

privateintgenerateRoomNumber(){

returnnewRandom(System.currentTimeMillis()).nextInt();

}

privatevoidsendToAll(WebSocketconn,Stringmessage){

Iteratorit=Rooms.get(myroom).iterator();

while(it.hasNext()){

WebSocketc=(WebSocket)it.next();

if(c!=conn)c.send(message);

}

}

publicstaticvoidmain(String[]args){

Mainserver=newMain();

server.start();

}

}

Oncetheapplicationstarts,itwilllistenontheTCPport30001forWebSocketmessagesfromclients.Youcanwritesimpleclientapplicationstotestthesignalingserver—refertotheMakingandansweringcallsrecipe.

NotethatyoucanfindaMaven-basedprojectforthisexamplesuppliedwiththisbook.

Howitworks…Firstofall,theclientsendsaGETROOMmessagetothesignalingserverthatislisteningonTCPport30001.Theservergeneratesanewvirtualroomnumber,storesit,andsendsitbacktotheclient.

TheclientconstructsanewaccessURLusingthevirtualroomnumberreceivedfromtheserver.Then,thesecondclientusesthisURLtoenterthevirtualroomandestablishacalltothefirstclient.

ThesecondclientsendstheroomnumberitgotfromtheURLtothesignalingserver.Theserverassociatestheclientwiththevirtualroomnumber.Then,theclientmakesacall,usingsignalingserver,whichforwardsitsmessagestothefirstclientthatispresentintheroomalready.Thefirstclientanswersthecall,alsousingthesignalingserverasthemiddlepoint.

Sobothclientsexchangethenecessarydata(includingnetworkdetails)andthenestablishdirectpeer-to-peerconnection.Aftertheconnectionisestablished,peersdon’tusetheserveranymore.

There’smore…TheWebSocketsignalingserverinJavacanbeimplementedusingaJavaEEstack.Formoredetails,takealookatthehomepageofJSR356athttp://www.oracle.com/technetwork/articles/java/jsr356-1937161.html.

Youcanalsofindanexampleathttps://github.com/hsilomedus/web-sockets-samples/tree/master/eesockets.

AnothersolutionistouseSpring4.IthasWebSocketsupportoutofthebox.Fordetailsonthissolution,takealookattheexampleonGitHubathttps://github.com/hsilomedus/web-sockets-samples/tree/master/springsockets.

SeealsoForanalternativesolution,youcanrefertotheBuildingasignalingserverinErlangrecipe

DetectingWebRTCfunctionssupportedbyabrowserWebRTCisnotfullysupportedbyallavailablewebbrowsersatthistime.Moreover,thereisachancethatyourapplicationwillberunningundersomekindofexoticenvironmentorwebbrowserthatdoesnotsupportWebRTC.SoyouneedtohavesomemechanismthatwouldenableyoutodetectwhethertheenvironmentinwhichyourwebapplicationisrunningsupportsthenecessaryWebRTCfeaturestheapplicationisgoingtouse.Inthisrecipe,wewillcoverthebasicmethodofdoingthat.

GettingreadyThistaskisrelevantfortheclientsideonly,soallthecodewillbewritteninJavaScript.Thus,nospecificpreparationisneeded.

Howtodoit…YoucanwriteaJavaScriptlibrarythatcanbeusedtodetectwhichWebRTCmethodsareavailableundertheenvironmentandbywhatnamestheyareknownforyourapplication.

Thefollowingcoderepresentsabasicbutproductiveexampleofsuchakindoflibrary:

varwebrtcDetectedVersion=null;

varwebrtcDetectedBrowser=null;

window.requestFileSystem=window.requestFileSystem||

window.webkitRequestFileSystem;

functioninitWebRTCAdapter(){

if(navigator.mozGetUserMedia){

webrtcDetectedBrowser="firefox";

webrtcDetectedVersion=

parseInt(navigator.userAgent.match(/Firefox\/([0-9]+)\./)[1],10);

RTCPeerConnection=mozRTCPeerConnection;

RTCSessionDescription=mozRTCSessionDescription;

RTCIceCandidate=mozRTCIceCandidate;

getUserMedia=navigator.mozGetUserMedia.bind(navigator);

attachMediaStream=

function(element,stream){

element.mozSrcObject=stream;

element.play();

};

reattachMediaStream=

function(to,from){

to.mozSrcObject=from.mozSrcObject;

to.play();

};

MediaStream.prototype.getVideoTracks=

function(){

return[];

};

MediaStream.prototype.getAudioTracks=

function(){

return[];

};

returntrue;

}elseif(navigator.webkitGetUserMedia){

webrtcDetectedBrowser="chrome";

webrtcDetectedVersion=

parseInt(navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)[2],10);

RTCPeerConnection=webkitRTCPeerConnection;

getUserMedia=navigator.webkitGetUserMedia.bind(navigator);

attachMediaStream=

function(element,stream){

element.src=webkitURL.createObjectURL(stream);

};

reattachMediaStream=

function(to,from){

to.src=from.src;

};

if(!webkitMediaStream.prototype.getVideoTracks){

webkitMediaStream.prototype.getVideoTracks=

function(){

returnthis.videoTracks;

};

webkitMediaStream.prototype.getAudioTracks=

function(){

returnthis.audioTracks;

};

}

if(!webkitRTCPeerConnection.prototype.getLocalStreams){

webkitRTCPeerConnection.prototype.getLocalStreams=

function(){

returnthis.localStreams;

};

webkitRTCPeerConnection.prototype.getRemoteStreams=

function(){

returnthis.remoteStreams;

};

}

returntrue;

}elsereturnfalse;

};

Howitworks…ThissolutiontestswhichWebRTCAPImethodsareavailableintheenvironmentandhowtheyarenamed.SoyourapplicationcanusecertainAPIfunctionnamesthatwillberelevantforanywebbrowser,withoutusingbrowser-specificfunctionnames.

There’smore…Thereisanotherwaytosolvethistask.Youdon’tnecessaryhavetowriteyourownadapter.YoucantaketheadapterpreparedbyGoogle.Itcanbefoundathttp://apprtc.webrtc.org/js/adapter.js.YoujustneedtoincludeitinyourJavaScriptcode.

Youcanalsoconsiderusingabrowser’spluginthatenablestheuseofWebRTCinSafariandInternetExplorer.Youcangettheseathttps://temasys.atlassian.net/wiki/display/TWPP/How+to+integrate+the+plugin+with+your+website

SeealsoYoucanfindmoreinformationontheadapteratthewebpagehttp://www.webrtc.org/web-apis/interop.

MakingandansweringcallsTheverybasicactionofanyWebRTCapplicationismakingandreceivingacall.Thisrecipeshowshowtomakecallstoaremotepeer.

GettingreadyAtthebeginning,peersdon’tknoweachother,andtheydon’tknowthenecessarynetworkinformationtomakedirectconnectionpossible.Beforeestablishingadirectconnection,peersshouldexchangenecessarydatausingsomemiddlepoint—usually,asignalingserver.Thisisamiddlepointthatisknowntoeachpeer.Soeachpeercanconnecttothesignalingserver,andthenonepeercancallanotherone—byaskingthesignalingservertoexchangespecificdatawithanotherpeerandmakepeersknoweachother.

So,youneedasignalingservertorun.

Howtodoit…Beforetwopeerscanestablishadirectconnection,theyshouldexchangespecificdata(ICEcandidatesandsessiondescriptions)usingamiddlepoint—thesignalingserver.Afterthat,onepeercancallanotherone,andthedirectpeer-to-peerconnectioncanbeestablished.

InteractiveConnectivityEstablishment(ICE)isatechniqueusedinNetworkAddressTranslator(NAT),whichbypassestheprocessofestablishingpeer-to-peerdirectcommunication.Usually,ICEcandidatesprovideinformationabouttheIPaddressandportofthepeer.Typically,anICEcandidatemessagemightlooklikethefollowing:a=candidate:11UDP4257021352192.168.0.101211typhost

SessionDescriptionProtocol(SDP)isusedbypeersinWebRTCtoconfigureexchanging(networkconfiguration,audio/videocodecsavailable,andsoon).Everypeersendsdetailsregardingitsconfigurationtoanotherpeerandgetsthesamedetailsfromitback.ThefollowingprintdepictsapartofanSDPpacketrepresentingtheaudioconfigurationoptionsofapeer:m=audio53275RTP/SAVPF121918100121029013116

c=INIP416.0.0.1

a=rtcp:53275INIP416.0.0.1

Intheschemarepresentedinthefollowingdiagram,youcanseethegenericflowofacallestablishingprocess:

NotethatTURNisnotshowedintheschema.IfyouusedTURN,itwouldbedepicted

justaftertheSTUNstage(beforethefirstandsecondstage).

MakingacallTomakeacall,weneedtotakesomestepstoprepare(suchasgettingaccesstothebrowser’smedia):

1. Getaccesstotheuser’smedia:

functiondoGetUserMedia(){

varconstraints={"audio":true,"video":{"mandatory":{},

"optional":[]}};

try{

getUserMedia(constraints,onUserMediaSuccess,

function(e){

console.log("getUserMediaerror"+e.toString());

});

}catch(e){

console.log(e.toString());

}

};

2. Ifyousucceed,createapeerconnectionobjectandmakeacall:

functiononUserMediaSuccess(stream){

attachMediaStream(localVideo,stream);

localStream=stream;

createPeerConnection();

pc.addStream(localStream);

if(initiator)doCall();

};

functioncreatePeerConnection(){

varpc_constraints={"optional":[{"DtlsSrtpKeyAgreement":

true}]};

try{

pc=newRTCPeerConnection(pc_config,pc_constraints);

pc.onicecandidate=onIceCandidate;

}catch(e){

console.log(e.toString());

pc=null;

return;

}

pc.onaddstream=onRemoteStreamAdded;

};

functiononIceCandidate(event){

if(event.candidate)

sendMessage({type:'candidate',label:

event.candidate.sdpMLineIndex,id:event.candidate.sdpMid,candidate:

event.candidate.candidate});

};

functiononRemoteStreamAdded(event){

attachMediaStream(remoteVideo,event.stream);

remoteStream=event.stream;

};

functiondoCall(){

varconstraints={"optional":[],"mandatory":

{"MozDontOfferDataChannel":true}};

if(webrtcDetectedBrowser==="chrome")

for(varpropinconstraints.mandatory)if

(prop.indexOf("Moz")!=-1)deleteconstraints.mandatory[prop];

constraints=mergeConstraints(constraints,sdpConstraints);

pc.createOffer(setLocalAndSendMessage,errorCallBack,

constraints);

};

AnsweringacallAssumingthatwewilluseWebSocketsasatransportprotocolforexchangingdatawithsignalingserver,everyclientapplicationshouldhaveafunctiontoprocessmessagescomingfromtheserver.Ingeneral,itlooksasfollows:

functionprocessSignalingMessage(message){

varmsg=JSON.parse(message);

if(msg.type==='offer'){

pc.setRemoteDescription(newRTCSessionDescription(msg));

doAnswer();

}elseif(msg.type==='answer'){

pc.setRemoteDescription(newRTCSessionDescription(msg));

}elseif(msg.type==='candidate'){

varcandidate=newRTCIceCandidate({sdpMLineIndex:msg.label,

candidate:msg.candidate});

pc.addIceCandidate(candidate);

}elseif(msg.type==='GETROOM'){

room=msg.value;

onRoomReceived(room);

}elseif(msg.type==='WRONGROOM'){

window.location.href="/";

}

};

ThisfunctionreceivesmessagesfromthesignalingserverusingtheWebSocketslayerandactsappropriately.Forthisrecipe,weareinterestedintheoffertypeofmessageanddoAnswerfunction.

ThedoAnswerfunctionispresentedinthefollowinglisting:

functiondoAnswer(){

pc.createAnswer(setLocalAndSendMessage,errorCallBack,sdpConstraints);

};

ThesdpConstraintsobjectdescribestheWebRTCconnectionoptionstobeused.Ingeneral,itlooksasfollows:

varsdpConstraints={'mandatory':{'OfferToReceiveAudio':true,

'OfferToReceiveVideo':true}};

Herewecansaythatwewouldliketousebothaudioandvideowhileestablishing

WebRTCpeer-to-peerconnection.

TheerrorCallbackmethodisacallbackfunctionthatiscalledincaseofanerrorduringthecallingofthecreateAnswerfunction.Inthiscallbackfunction,youcanprintamessagetotheconsolethatmighthelptodebugtheapplication.

ThesetLocalAndSendMessagefunctionsetsthelocalsessiondescriptionandsendsitbacktothesignalingserver.Thisdatawillbesentasananswertypeofmessage,andthenthesignalingserverwillroutethismessagetothecaller:

functionsetLocalAndSendMessage(sessionDescription){

pc.setLocalDescription(sessionDescription);

sendMessage(sessionDescription);

};

Notethatyoucanfindthefullsourcecodeforthisexamplesuppliedwiththisbook.

Howitworks…Firstly,wewillaskthewebbrowsertogainaccesstotheusermedia(audioandvideo).Thewebbrowserwillasktheuserfortheseaccessrights.Ifwegettheaccess,wecancreateaconnectionpeerentityandsendthecallmessagetothesignalingserver,whichwillroutethismessagetotheremotepeer.

Theworkflowofthecodeisverysimple.TheprocessSignalingMessagefunctionshouldbecalledeverytimewegetamessagefromthesignalingserver.Usually,youshouldsetitasanonmessageeventhandleroftheWebSocketJavaScriptobject.

Afterthemessageisreceived,thisfunctiondetectsthemessagetypeandactsappropriately.Toansweranincomingcall,itcallsthedoAnswerfunctionthatwilldotherestofthemagic—preparethesessiondescriptionandsenditbacktotheserver.

Thesignalingserverwillgetthisreplyasananswermessageandwillrouteittotheremotepeer.Afterthat,peerswillhaveallthenecessarydataoneachothertostartestablishingadirectconnection.

There’smore…ThisisthebasicfunctionalityofWebRTC.Mostofyourapplicationswillprobablyhavethesamecodeforthistask.Theonlybigdifferencemightbecommunicationwiththesignalingserver—youcanuseanyprotocolyoulike.

SeealsoRefertotheImplementingachatusingdatachannelsreciperegardingtheprocessofbuildingasimplewebchatapplicationusingWebRTCYoucanfindmoredetailsonICEontheRFC5245websiteathttps://tools.ietf.org/html/rfc5245MoreinformationregardingSDPcanbefoundonRFC4566athttps://tools.ietf.org/html/rfc4566

ImplementingachatusingdatachannelsInthisrecipe,wewillimplementapeer-to-peerprivatemessagingserviceusingWebRTCdatachannels.Thismethodallowsustosendmessagesdirectlyfrompeertopeer,usingsecureandsafedatachannelsprovidedbytheWebRTCstack.

Theschemarepresentedinthefollowingdiagramdepictsthegenericfeatureflow:

GettingreadyWewilldevelopasimpleapplication,soyoudon’tneedanyspecificpreparationsforthisrecipe.Asignalingserverisnecessaryforthisapplication,anditcanbetakenfromtheBuildingasignalingserverinErlangorBuildingasignalingserverinJavarecipe.

Howtodoit…Forsimplicity,wewillmaketwopartsoftheapplication:anindexwebpageandaJavaScriptlibrary.

CreatingthemainHTMLpageoftheapplication1. First,createanHTMLindex.htmlpage.Inthefollowingcode,youcanfindits

content.Notethatthelessimportantandobviouspartsmightbeskippedhere.

<!DOCTYPEhtml>

<html>

<head>

2. IncludeourJavaScriptlibrarythatisinaseparatefile:

<scripttype="text/javascript"src="myrtclib.js"></script>

3. IncludeGoogle’sWebRTCJavaScriptadapter:

<script

src="https://rawgit.com/GoogleChrome/webrtc/master/samples/web/js/adapt

er.js"></script>

</head>

<body>

4. Createadivtagwherewewillputinformationregardingtheconnection:

<divid="status"></div><br>

5. Createadivtagwherethereceivedmessagesfromaremotepeerwillbeplaced:

<divid="chat"></div>

6. Createaformwithaninputelementandabuttontosendmessagestotheremotepeer:

<formname="chat_form"

onsubmit="onChatSubmit(document.chat_form.msg.value);returnfalse;">

<inputtype="text"class="search-query"placeholder="chathere"

name="msg"id="chat_input">

<inputtype="submit"class="btn"id="chat_submit_btn"/>

</form>

<script>

7. CreateaconnectiontothesignalingserverandinitializetheWebRTCstack.ThefollowingfunctionisdeclaredintheJavaScriptlibrary,whichwewillconsiderfurtherintherecipe:

myrtclibinit("ws://localhost:30001");

Notethatthedomainnameandportmightbedifferentinyourcase;theyshouldbethesameasdeclaredinthesourcecodesofthesignalingsever.Bydefault,thesignalingserverislisteningonlocalhostandonport30001.

ThefollowingfunctionsendsamessagetotheremotepeerusingthesendDataMessagefunction—wewillwriteitaspartoftheJavaScriptlibrary:

functiononChatSubmit(txt){

varmsg=JSON.stringify({"type":"chatmessage","txt":txt});

sendDataMessage(msg);

};

Wewillalsodeclareacallbackfunctionforacatchingeventwhenanewvirtualroomiscreated:

functiononRoomReceived(room){

varst=document.getElementById("status");

Createalinktosharewiththeremotepeer,putthelinkinthedivstatus.

st.innerHTML="Now,ifsomebodywantstojoinyou,shouldusethis

link:<ahref=\""+window.location.href+"?

room="+room+"\">"+window.location.href+"?room="+room+"</a>";

};

Toshowthemessagesreceivedfromtheremotepeer,wewilldeclareanappropriatecallbackfunction.ThisfunctiongetsthemessageandputsitintheappropriateplaceontheHTMLpage:

functiononPrivateMessageReceived(txt){

vart=document.getElementById('chat').innerHTML;

t+="<br>"+txt;

document.getElementById('chat').innerHTML=t;

}

</script>

</body>

</html>

SavetheHTMLfile.Thiswillbethemainpageoftheapplications.

CreatingtheJavaScripthelperlibraryNow,createanemptymyrtclib.jsfileandputthefollowingcontentintoit.Notethatmanypartsofthefollowingcodemightbeusedinthenextchapters,sotheyshouldbewell-knowntoyoualready.Suchobviouspartsofthecodemightbeskippedinfurther.

varRTCPeerConnection=null;

varroom=null;

varinitiator;

varpc=null;

varsignalingURL;

Thefollowingvariablewillbeusedforhandlingthedatachannelobject:

vardata_channel=null;

varchannelReady;

varchannel;

varpc_config={"iceServers":

[{url:'stun:23.21.150.121'},

{url:'stun:stun.l.google.com:19302'}]};

functionmyrtclibinit(sURL){

signalingURL=sURL;

openChannel();

};

functionopenChannel(){

channelReady=false;

channel=newWebSocket(signalingURL);

channel.onopen=onChannelOpened;

channel.onmessage=onChannelMessage;

channel.onclose=onChannelClosed;

};

functiononChannelOpened(){

channelReady=true;

createPeerConnection();

if(location.search.substring(1,5)=="room"){

room=location.search.substring(6);

sendMessage({"type":"ENTERROOM","value":room*1});

initiator=true;

doCall();

}else{

sendMessage({"type":"GETROOM","value":""});

initiator=false;

}

};

functiononChannelMessage(message){

processSignalingMessage(message.data);

};

functiononChannelClosed(){

channelReady=false;

};

functionsendMessage(message){

varmsgString=JSON.stringify(message);

channel.send(msgString);

};

functionprocessSignalingMessage(message){

varmsg=JSON.parse(message);

if(msg.type==='offer'){

pc.setRemoteDescription(newRTCSessionDescription(msg));

doAnswer();

}elseif(msg.type==='answer'){

pc.setRemoteDescription(newRTCSessionDescription(msg));

}elseif(msg.type==='candidate'){

varcandidate=newRTCIceCandidate({sdpMLineIndex:msg.label,

candidate:msg.candidate});

pc.addIceCandidate(candidate);

}elseif(msg.type==='GETROOM'){

room=msg.value;

onRoomReceived(room);

}elseif(msg.type==='WRONGROOM'){

window.location.href="/";

}

};

functioncreatePeerConnection(){

try{

pc=newRTCPeerConnection(pc_config,null);

pc.onicecandidate=onIceCandidate;

Untilnow,thecodeisverysimilartowhatweusedinatypicalWebRTCexampleapplication.Although,nowwewilladdsomethingnew.WewillsetupahandlerfortheondatachanneleventofthePeerConnectionobject.Thiscallbackfunctionwillbecalledwhenthepeerasksustocreateadatachannelandestablishadataconnection:

pc.ondatachannel=onDataChannel;

}catch(e){

console.log(e);

pc=null;

return;

}

};

Thehandlerfunctionisprettysimple.Wewillstorethereferenceinthedatachannelandinitializeit:

functiononDataChannel(evt){

console.log('Receiveddatachannelcreatingrequest');

data_channel=evt.channel;

initDataChannel();

}

Byinitializingthedatachannel,Imeansettingupachannel’seventhandlers:

functioninitDataChannel(){

data_channel.onopen=onChannelStateChange;

data_channel.onclose=onChannelStateChange;

data_channel.onmessage=onReceiveMessageCallback;

}

Inthefollowingfunction,weneedtocreateanewdatachannel—notwhentheremotepeerisaskingus,butwhenwe’retheinitiatorofthepeerconnectionandwanttocreateanewdatachannel.Afterwehavecreatedanewdatachannel,weshouldasktheremotepeertodothesame:

functioncreateDataChannel(role){

try{

Whenwecreateanewdatachannel,wecansetupanameofthechannel.Inthefollowingpieceofcode,wewillusethenumberofthevirtualroomtonamethechannel:

data_channel=pc.createDataChannel("datachannel_"+room+role,

null);

}catch(e){

console.log('errorcreatingdatachannel'+e);

return;

}

initDataChannel();

}

functiononIceCandidate(event){

if(event.candidate)

sendMessage({type:'candidate',label:

event.candidate.sdpMLineIndex,id:event.candidate.sdpMid,candidate:

event.candidate.candidate});

};

functionfailureCallback(e){

console.log("failurecallback"+e.message);

}

functiondoCall(){

Whenweareplayingtheroleoftheconnectioninitiator(caller),wecreateanewdatachannel.Then,duringtheconnectionestablishment,theremotepeerwillbeaskedtodothesameandthedatachannelconnectionwillbeestablished:

createDataChannel("caller");

pc.createOffer(setLocalAndSendMessage,failureCallback,null);

};

functiondoAnswer(){

pc.createAnswer(setLocalAndSendMessage,failureCallback,null);

};

functionsetLocalAndSendMessage(sessionDescription){

pc.setLocalDescription(sessionDescription);

sendMessage(sessionDescription);

};

Tosendtextmessagesviathedatachannel,weneedtoimplementtheappropriatefunction.Asyoucanseeinthefollowingcode,sendingdatatothedatachannelisprettyeasy:

functionsendDataMessage(data){

data_channel.send(data);

};

Thefollowinghandlerisnecessarytoprintthestateofthedatachannelwhenitischanged:

functiononChannelStateChange(){

console.log('Datachannelstateis:'+data_channel.readyState);

}

Whentheremotepeersendsusamessageviathedatachannel,wewillparseitandcalltheappropriatefunctiontoshowthemessageonthewebpage:

functiononReceiveMessageCallback(event){

console.log(event);

try{

varmsg=JSON.parse(event.data);

if(msg.type==='chatmessage')

onPrivateMessageReceived(msg.txt);

}

catch(e){}

};

SavetheJavaScriptfile.

Now,startthesignalingserverandopentheHTMLfileinawebbrowser—youshouldseeaninputfieldandabuttononthepage.Atthetopofthepage,youshouldseeaURLtobesharedwiththeremotepeer.

Onanotherbrowser’swindow,openthesharinglink.Inthewebbrowser’sconsole,youshouldseetheDatachannelstateisopenmessage.Now,entersomethingintheinputboxandclickontheSubmitquerybutton.Youshouldseethemessageprintedonanotherbrowser’swindow.

Howitworks…Whentheapplicationstarts,itestablishesaconnectionwiththesignalingserverandgetsavirtualroomnumber.Then,anotherpeerstartstheapplicationandentersthevirtualroom.Thesecondpeeristhecaller.Whenthepeerconnectionisestablished,thecallercreatesanewdatachannelandanotherpeerreceivesthiseventnotification.So,bothpeersgetadatachannelreferenceandcanuseitfordataexchanging.

Inourexample,whenthecustomerentersamessageandclicksontheSubmitquerybutton,wewillwrapthemessageintoaJSONobjectandsenditviathedatachannel.TheremotepeergetstheJSONobject,parsesittothemessage,anddisplaysitonthepage.

There’smore…Usingdatachannels,peerscanexchangeanykindofdata.Itcanbeplaintext,forexample,orbinarydata.Moreover,thesamedatachannelcanbeusedtoexchangedifferentsortsofdatabetweenpeers.Inthisrecipe,weusedJSONtoformatmessages,andeverypackethasatypefield.Tosendtextmessages,weusedthechatmessagetype,butyoucanuseyourowncustomtypesystemtodistinguishmessages.YoucanalsousesomethingotherthanJSON.So,datachannelsareagoodtooltoexchangedatabetweenpeers,usingasecureandsafedirectconnection.

SeealsoPleaserefertotheImplementingachatusingasignalingserverrecipetolearntheotherwaythisfeaturecanbeimplemented

ImplementingachatusingasignalingserverInthisrecipe,wewillcovertheprocessofimplementingprivate,peer-to-peerwebchatusingsignalingserverasthemiddlepoint.Peerswillsendchatmessagesviathesignalingserver.Intheschemarepresentedinthefollowingdiagram,youcanseetheflow:

Howtodoit…Toimplementthechatfeatureviathesignalingserver,weneedtoaddsomemethodstotheclientcodewiththefollowingsteps:

1. Weneedtoaddappropriatecodetothefunctionthatprocessesthemessagesfromthesignalingserver:

functionprocessSignalingMessage(message){

varmsg=JSON.parse(message);

if(msg.type==='CHATMSG'){

onChatMsgReceived(msg.value);

}elseif(msg.type==='offer'){

pc.setRemoteDescription(newRTCSessionDescription(msg));

doAnswer();

}elseif(msg.type==='answer'){

pc.setRemoteDescription(newRTCSessionDescription(msg));

}elseif(msg.type==='candidate'){

varcandidate=new

RTCIceCandidate({sdpMLineIndex:msg.label,candidate:msg.candidate});

pc.addIceCandidate(candidate);

}elseif(msg.type==='GETROOM'){

room=msg.value;

onRoomReceived(room);

}elseif(msg.type==='WRONGROOM'){

window.location.href="/";

}

};

2. WewillcheckwhetherthereceivedmessageisoftheCHATMSGtypeandifso,wewillcalltheonChatMsgReceivedmethodtoprocessit:

functiononChatMsgReceived(txt){

varchatArea=document.getElementById("chat_div");

chatArea.innerHTML=chatArea.innerHTML+txt;

chatArea.scrollTop=chatArea.scrollHeight;

};

Here,wewillgetthechat_divelementbyitsIDandalteritscontentbyaddingthechatmessagereceivedfromtheremotepeerviathesignalingserver.

3. Tosendachatmessage,weshouldimplementamethodlikethefollowing:

functionchatSendMessage(msg){

if(!channelReady)return;

sendMessage({"type":"CHATMSG","value":msg});

};

ThisfunctioncheckswhethertheWebSocketchannelisupandsendsachatmessagetothesignalingserverusingthechannel.Tousethisfunction,wecanusetheHTMLinputtagwiththesubmitbuttonandcallitonthesubmitevent.

Howitworks…Thebasicprincipleofthissolutionisprettysimple:

Onepeersendsatextmessagetothesignalingserver,markingitastheCHATMSGtypeThesignalingserverretransmitsthemessagetoanotherpeerAnotherpeergetsthemessagefromthesignalingserver,checkswhetheritisoftheCHATMSGtypeandifso,showsittotheuser

TipTodistinguishchatmessagesfromWebRTCmessages,youcanuseanywordtomarkthemessagetype.ItcanbeCHATMSGorwhateveryouprefer.

There’smore…Thiswayofimplementingwebchatisusuallynotsecurebecausethedatawillgoviathesignalingserverandnotdirectlythroughthepeers.Nevertheless,itissuitableforpublicchatroomswheretherecanbeseveralpeopleatatime.Forprivatepeer-to-peerchats,itisusuallybettertouseWebRTCdatachannels,andthatwayitismoresecure.

SeealsoToimplementthechatfeatureusingdatachannels,followtheImplementingachatusingdatachannelsrecipe

ConfiguringandusingSTUNYourWebRTCapplicationcanworkwithoutSTUNorTURNserversifallthepeersarelocatedinthesameplainnetwork.Ifyourapplicationissupposedtoworkforpeersthatmightbelocatedindifferentnetworks,itwilldefinitelyneedtouseatleasttheSTUNservertowork.

GettingreadyInthisrecipe,wewillinstallaSTUNserveronaLinuxbox.STUNservercanbeinstalledundertheotherplatformaswell,butforsimplicity,wewillconsideronlytheLinuxcase.So,pleaseprepareaLinuxmachine.

Inthisrecipe,wewilluseaverybasicandsimpleSTUNserverimplementation,soyouprobablywillnotneedtoinstalladditionallibrariesordosomedifficultconfiguration.

STUNneedstwoIPaddressestoworkcorrectly.Thus,whenexperimentingwithyourLinuxbox,takecarethattheLinuxboxshouldhaveatleasttwoIPaddressesthatareavailableforallpossiblepeers(WebRTCclients).

Howtodoit…ThefollowingsetofstepswillleadyouthroughtheprocessofconfiguringandbuildingaSTUNservice:

1. DownloadtheSTUNserverfromitshomepageathttp://sourceforge.net/projects/stun/.

2. UnpackthearchiveandgointotheSTUNserverfolder:

tar–xzfstund-0.97.tgz

cdstund

3. Builditwiththefollowingcommand:

make

Thelastcommandwillbuildtheserver.Afterthat,youcanstarttheSTUNserverbyusingthefollowingcommand:

./server-hprimary_ip-asecondary_ip

Notethatinsteadofprimary_ipandsecondary_ip,youshoulduseactualIPaddressesthatareavailableonthemachine.Thissoftwarecan’tdetectsuchnetworkparametersautomatically,soyouneedtosetitupexplicitly.

TipIfyouwanttostarttheserverinthebackground,addthe-boptiontotheprecedingcommand.

Now,whentheSTUNserverisconfiguredandrunning,wecanutilizeitintheWebRTCapplication.Whenyourapplicationwantstocreateapeerconnectionobject,itusessomethinglikethefollowingcode:

varpc;

pc=newRTCPeerConnection(configuration);

Here,configurationisanentitythatcontainsdifferentoptionsforcreatingpeerconnectionobject.ToutilizeyourfreshlyinstalledSTUNserver,youshouldusesomethinglikethefollowingcode:

varconfiguration={

'iceServers':[

{

'url':'stun:stun.myserver.com:19302'

}]}

HereweinformthewebbrowserthatitcanusetheSTUNserverifnecessary.NotethatyoushouldusetherealdomainnameorIPaddressoftheSTUNserver.Youcanalsoexplicitlysettheportnumberasshownintheprecedingcode,incaseitisdistinguishedfromthedefaultvalue.

Howitworks…STUNservercanhelppeersdeterminetheirnetworkparametersandthusestablishadirectcommunicationchannel.IfyourclientsarelocatedbehindNATorfirewall,yourapplicationshoulduseatleasttheSTUNservicetomakethedirectconnectionpossible.Nevertheless,inmanycasesthatmightnotbeenough,andusingTURNmightbenecessary.

ThefollowingdiagrammightbehelpfultoyoutoimaginehowtheSTUNserverislocatedinthewholeinfrastructure,andhowallthecomponentsinteroperatewitheachother:

There’smore…Asanalternativetothis,youcanuserfc5766-server—itisafreeandopensourceimplementationofbothSTUNandTURNservers.Italsosupportsmanyadditionalfeaturesthatmightbequiteuseful.Youcanfinditathttps://code.google.com/p/rfc5766-turn-server/.

SeealsoFordetailsonhowSTUNworks,youcanrefertoRFC#3489http://www.ietf.org/rfc/rfc3489.txt.IntheConfiguringandusingTURNrecipe,wewilluseaTURNserverbasedontherfc5766-serversoftware.ThatapplicationcanserveasaSTUNserveraswell.

ConfiguringandusingTURNInmostcases,itisenoughtouseaSTUNservertoestablishapeer-to-peerdirectconnection.Nevertheless,youwilloftenneedtoutilizeTURNservers—mostlyforclientslocatedinbigcompanies(becauseoffirewallpolicyandtrickyNAT)andsomespecificcountries(becauseoffirewallsandaccesslimits).

GettingreadyInthissection,wewilldownload,install,anddothebasicconfigurationofaTURNservice.Then,wewillutilizeitinourWebRTCapplication.ATURNservercanbeinstalledunderdifferentplatforms,althoughwewillcoveraLinuxboxusecaseonly.Thus,forthisrecipe,youwillneedaLinuxboxinstalled.

Forthisrecipe,wewilluserfc5766-turn-server—afreeandopensourceimplementationoftheTURNandSTUNservers.Downloaditssourcecodefromitshomepageathttps://code.google.com/p/rfc5766-turn-server/.

Howtodoit…First,wewillshortlycovertheinstallationandbasicconfigurationoftheTURNserver.Afterthat,wewilllearnhowtouseitintheapplication.

IfyouhaveTURNserveralreadyinstalled,youcanskipthissectionandgodirectlytothenextone.

InstallingtheTURNserverIassumethatyouhavedownloadedrfc5766-serveralreadyandunpackedit.So,let’sinstallandconfigureyourownTURNserver:

1. Gototherfc5766-serverfolderwiththefollowingcommand:

cd~/turnserver-4.1.2.1

2. Buildtheserver:

./configure

make

sudomakeinstall

TipNotethatrfc5766-serverneedssomelibrariesthatmightbenotinstalledonyoursystem—inparticular,libssl-dev,libevent-dev,andopenssl.Youshouldinstalltheabsentlibrariestocompilethesoftwaresuccessfully.

3. Afterthat,youcanstarttheserver—itwilldetectallthenetworkoptionsautomatically:

turnserver

Youwillseediagnosticmessagesintheconsole:

0:===========Discoveringrelayaddresses:=============

0:Relayaddresstouse:x.x.x.x

0:Relayaddresstouse:y.y.y.y

0:Relayaddresstouse:::1

0:=====================================================

0:Total:3relayaddressesdiscovered

0

0:=====================================================

NoteTostoptheserver,justpressCtrl+C;youwillgetbacktoconsole.

NowitistimetoperformsomeconfigurationstepsandtuneyourfreshTURNserverforyourrequirements.

Bydefault,theTURNserverdoesn’thaveanyconfigurationfile.Weneedtocreatethisconfigurationfilefromthedefaultconfigurationfilesuppliedwiththeserver:

sudocp/usr/local/etc/turnserver.conf.default

/usr/local/etc/turnserver.conf

Opentheturnserver.conffileandedititaccordingtoyourrequirements.WewillnotcoveralltheTURNoptionshere,butjustbasicconfigurationitemsthatmightbeimportant:

ListeningIP:ThisoptiondeterminestheIPaddressesthatwillbeusedbytheTURNserverwhileoperating.Bydefault,thisoptionwilldoitautomatically.Nevertheless,itisagoodideatosettheobviousIPaddressesyouwouldliketheservertouse:

listening-ip=

TipNotethattheTURNserverneedsatleasttwopublicIPaddressestooperatecorrectly.

RelayIP:Inthisoption,youcanexplicitlysetupIPaddressthatshouldbeusedforrelay.Inotherwords,ifyouhavetwoIPaddresses,oneofthemcanbelistening-ipandthesecondonerelay-ip.

relay-ip=

Verbosity:Inthisoption,youcansetalevelofverbosity.Bydefault,theTURNserverwillnotprintextradetailsonitswork,butfordebugginganddiagnosticpurposes,itmightbeveryusefultosettheverboseleveltonormal.Forthat,youshouldplacethewordverboseintheconfigurationfile.Ifyouwouldliketorefertomoredetails,youshouldwritethewordwithcapitalV—Verbose—sotheserverwillprintasmuchdebuggingdetailsaspossible.Anonymousaccess:Youcanenableanonymousaccessduringthedevelopmentprocess,ifyou’resurethatyourTURNserverisprotectedbynetworkfirewallandnobodycanuseit.Otherwise,youshouldnotenablethisoptionespeciallyonproductionsystems:

no-auth

NoteInthisrecipe,wehaven’tcoveredTURNauthentication—thistopiciscoveredinChapter2,SupportingSecurity.

Atthisstage,youhaveyourownTURNserverwithbasicconfiguration,whichcanbeusedinWebRTCapplications.

UsingTURNinWebRTCapplicationWhenyoucreateapeerconnectionobject,youusuallyusesomeconstructionlikethefollowingone:

varpc;

pc=newRTCPeerConnection(configuration);

Here,configurationisanentitythatcontainsdifferentoptionstocreateapeerconnectionobject.ToutilizeyourTURNserver,youshouldusesomethinglikethe

following:

varconfiguration={

'iceServers':[

{

'url':'stun:stun.l.google.com:19302'

},

{

'url':'turn:turn1.myserver.com:3478?transport=udp',

},

{

'url':'turn:turn2.myserver.com:3478?transport=tcp',

'credential':'superuser',

'username':'secretpassword'

}

]

}

Here,wewillasktheWebRTCAPI(actually,wewillaskthewebbrowser)touseoneofthreewayswhenestablishingapeerconnection:

PublicSTUNserverprovidedbyGoogle.TURNserverwithanonymousaccess.YouwillusethisnotationtoutilizetheTURNserverinstalledandconfiguredinthisrecipe.TURNserverwithauthentication.InChapter2,SupportingSecurity,wewillcoverthetopicofsecurityandauthenticationwithinthescopeofaTURNserver.Toutilizeaserverthatusesauthentication,youshouldusethisnotation.

TipNotethatyoucanaskthewebbrowsertouseaUDPorTCPprotocolwhileestablishingapeerconnectionthroughtheTURNserver.Todothat,setupthetransportparameterasshownintheprecedingbulletpoints.

Howitworks…Insomecases,whenclientsuseNATandfirewalls,itisimpossibletoestablishapeerconnectionusingSTUN.Thissituationoftenappearswhenaclientislocatedinacorporativenetworkwithastrictpolicy.Insuchacase,theonlywaytoestablishtheconnectionistousetheTURNserver.

TheTURNserverworksasaproxy—allthedatabetweenpeers(includingaudio,video,andservicedata)goesthroughtheTURNserver.

Thefollowingdiagramshowshowallthecomponentsoperatewitheachother:

There’smore…Inthisrecipe,wecoveredonlyoneTURNsolution,opensourceandpopular,butthereareothersolutionsintheworldthatcouldalsobesuitableforyou:

TurnServer:Thisisalsofreeandopensource.Formoreinformation,refertohttp://turnserver.sourceforge.net.Numb:Thisisnotsoftwarethatyoucandownloadandinstall,butaservicewhereyoucancreateanaccountandgetaccesstoaconfiguredTURNserver.Formoredetails,refertohttp://numb.viagenie.ca.

Ofcourse,thereareevenmoredifferentsolutionsandservicesavailable.

SeealsoFordetailsonTURNservers,refertoRFC5766athttp://tools.ietf.org/html/rfc5766FordetailsregardingSTUN(anotherusefultechnologywiththescopeofdevelopingWebRTC-basedservices),youcanalsotakealookattheConfiguringandusingSTUNrecipe

Chapter2.SupportingSecurityInthischapter,wewillcoverthefollowingtopics:

Generatingaself-signedcertificateConfiguringaTURNserverwithauthenticationConfiguringawebservertoworkoverHTTPSConfiguringaWebSocketsproxyonthewebserverConfiguringafirewall

IntroductionAtthetimeofwritingthisbook,theWebRTCstandardwasnotcompleteandthetechnologyanditsstandardwerebothunderactivedevelopment.Nevertheless,securityandsafetyareveryimportantandmandatoryfunctionalrequirementsthatlieatthebasisoftheWebRTCstandard.Basically,yourWebRTCapplicationshoulduseonlyencryptedchannels.

Inthischapter,wewillcoversecurity-relatedquestions.Wewilltalkaboutsecurity,third-partycomponents,andsoftwareyouwillprobablyusewhendevelopingyourWebRTCservice.Wewilltalkaboutconfiguringsecuredchannels(HTTPS)onwebbrowsers.WewillcovertheprocessofcreatingsecurecertificatesandusingtheminwebserversaswellastheTURNservice.WewillalsolearnhowtoimplementauthenticationonaTURNserverusingtheTURNRESTAPI.

WewilltalkabouthowWebRTCcanworkthroughfirewallsandNAT,andlearnhowtoconfigureafirewallonourserverthatisservingauxiliaryservicessuchasTURNorSTUN.

Generatingaself-signedcertificateUsingencryptionishighlyrecommended(I’dsayevenmandatory)forWebRTCapplications.Thetechnologyhasgoodsupportforsecurityandencryption,sothereisnoreasontoignorethem.Inthisrecipe,wewillcovertheprocessofcreatingself-signedcertificates.SuchacertificatecanbeusedwithaTURNserverorwithawebserverwhenoperatingwithHTTPSchannels.

Typically,apublickeyinfrastructure(PKI)isadigitalsignaturefromacertificateauthority(CA),whichatteststhataparticularPKIisvalidandcontainscorrectinformation.UsersortheirsoftwarethencheckthattheprivatekeyusedtosignacertificatematchesthepublickeyintheCA’scertificate.SinceCAcertificatesareoftensignedbyother,high-rankingCAs,theremustnecessarilybeahighest-rankingCA,whichprovidestheultimateattestationauthorityinthatparticularPKIscheme.

Thehighest-rankingCA’scertificatesaretermedasrootcertificates.Clearly,thelackofmistakesorcorruptionintheissuanceofsuchcertificatesiscriticaltotheoperationofitsassociatedPKI;theyshouldbe,andgenerallyare,issuedwithgreatcare.

Aself-signedsecuritycertificateisacertificatethatissignedbythesameentitywhoseidentityitcertifies.Suchacertificatecanbeusedfordevelopingpurposesandcanbegeneratedbyanybody.

YoucanfindmoredetailsonPKIathttp://en.wikipedia.org/wiki/Public_key_infrastructure.

TipSelf-signedcertificatescanbeusedfordevelopment,butyoushouldissuetrustedcertificatesforproductionsystems.

AllcommunicationchannelsinaWebRTCapplicationshouldbeusingencryption:client-to-client,client-to-server,oranyotherkindofchannelsyoumightbeusing.SomeWebRTCfeatures(suchasscreensharing)willnotworkwithoutencryption,eveninadevelopmentenvironment.

GettingreadyInthisrecipe,wewillusetheOpenSSLtoolset.

OpenSSLisanopensourcemultiplatformtoolkitthatimplementsSecureSocketsLayer(SSL)andTransportLayerSecurity(TLS)protocolsandprovidesageneralpurposefull-strengthcryptographylibrary.ManycomputersoftwareuseOpenSSLforsupportingencryptionandsecurity.

Youcanfindmoredetailsonthisproductatitshomepage,https://www.openssl.org.

Often,itisinstalledbydefaultonUnix-likesystems,butitisnotsuppliedwithWindowsinstallations.TocheckwhetheryoursystemhasOpenSSLinstalled,youcanusethefollowingconsolecommand:

opensslversion-a

OnmyMac,itproducesthefollowingmessage:

Ifyouseesomethingsimilar,thenyouhaveOpenSSLinstalledonyoursystem.Ifnot,youneedtoinstallthetool.

NoteFormoreinformationonhowtoinstallOpenSSL,pleaserefertoitsofficialhomepageathttp://www.openssl.org.

Howtodoit…Inthissection,wewillgeneratepublicandprivatesecuritycertificatekeyswiththefollowingsteps:

1. First,generateatemporaryserverpasswordkey:

opensslgenrsa-des3-passoutpass:x-outserver.pass.key2048

Youwillseesomethinglikethefollowingscreenshot:

2. Usingtheserverpasswordkey,generateaserverprivatekey:

opensslrsa-passinpass:x-inserver.pass.key-outserver.key

Youwillseethefollowingoutput:

writingRSAkey

3. Wedon’tneedtheserverpasswordkey,sowecanremoveit:

rm-rfserver.pass.key

4. Generateacertificatesigningrequest:

opensslreq-new-keyserver.key-outserver.csr

5. Thiswillaskyouadditionalquestionsaboutthecompanythecertificateisbeingcreatedfor—youcanusefictionaldata.Itwillalsopromptyouforapasswordasshowninthefollowingscreenshot—forsimplicity,youcanjustpressreturn:

6. Generatethecertificate:

opensslx509-req-days365-inserver.csr-signkeyserver.key-out

server.crt

Youwillseethefollowingoutput:

Nowyouhavetwofiles,server.crt(thecertificate)andserver.key(thecertificate’sprivatekey),whichcanbeusedwithyourwebserver(operatingoverHTTPS)orTURNserver.

Howitworks…ByusinganOpenSSLtool,wegeneratedanewself-signedsecuritycertificatethatcanbeusedwithawebserveroraTURNserverthatisservingourWebRTCapplication.

NoteKindlynotethatwegeneratedthecertificateinPEMformat.Forsomesoftware,itmightbenecessarytoconvertittootherformats.

Thoughthecertificateimplementsfullencryption,yourwebsitevisitorswillseeabrowserwarningindicatingthatThecertificateshouldnotbetrusted!.

Ifaself-signedcertificatehasbeenusedtocreateaWebSocketserver,thenyourwebbrowserwillfailwhentryingtoestablishaconnectiontotheserverandwillnotshowanywarning.Tosolvesuchacase,youcanconfigureawebservertobesecured,butleavetheWebSocketserverunsecured;then,youshouldconfigureaWebSocketproxyonthewebserver.Thus,theclientwillcommunicatewiththeWebSocketservernotdirectly,butthroughthewebserverusingasecuredchannel.PleaserefertotheConfiguringaWebSocketsproxyonthewebserverrecipe.

So,useself-signedcertificatesfordevelopingonly.

There’smore…Forproductionsystems,youshouldusetrustedcertificatesemittedbysuchtrustedcenterssuchasVerisign,Thawte,orothers.

Youcanalsostartwithafree-of-chargebuttrustedcertificatefromStartSSL.Formoredetails,refertohttp://www.startssl.com.

IfyouhaveaWindowsbox,youcanusetheSelfSSL.exetooltocreateaself-signedcertificate.ThistoolispartofInternetInformationServices(IIS)ResourceKitToolsthatcanbefoundathttp://www.microsoft.com/en-gb/download/details.aspx?id=17275.

Youcanalsouseonlinetoolstocreateaself-signedcertificate,forexample,thisoneathttp://www.selfsignedcertificate.com.

SeealsoYoucanfindmoredetailsonhowtousecertificatesintheConfiguringaTURNserverwithauthenticationandConfiguringawebservertoworkoverHTTPSrecipes.

ConfiguringaTURNserverwithauthenticationSTUNserversdon’tsupportauthentication,butontheotherhand,TURNserversdo.Moreover,ifyoumaintainaTURNserver,ithastosupportauthenticationandprohibitanonymousaccess.WhenusingaTURNservice,allthetrafficfromonepeertoanothergoesthroughtheTURNserver.Ifanyonehadanonymousaccesstosuchaserver,theycouldveryquicklyutilizetheserver’sresourcesandtrafficlimits.

Inthisrecipe,wearegoingtogothroughaTURNauthenticationtask.

GettingreadyFirstofall,weneedtodownloadandinstallaTURNserver.Thereareseveralimplementations,andinthisrecipe,wewillconsiderusingrfc5766-turn-server.

ThissoftwareismultiplatformandcanbeusedonUnix-likesystemsandonWindowssystemsaswell.Nevertheless,tokeepitsimple,inthisrecipe,wewillcoveraLinux-basedcaseonly.

DownloadthesourcecodefromtheTURNserverhomepageathttps://code.google.com/p/rfc5766-turn-server/.

Toinstallthesoftware,youmightneedotheradditionalpackagestobeinstalledfirst:

mysqlclient-dev

libevent

libmysqlclient-dev

libevent-dev

libssl-dev

Pleaseuseyourpackageinstallationtooltoinstallnecessarypackets.

NoteThepackagelistmightvaryfordifferentLinuxdistributions.

UnpackthedownloadedTURNserverpackageintoanewfolder,gotoit,andthencompileandinstallthesoftwareusingthefollowingcommands:

./configure

make

sudomakeinstall

Ifyoudidn’tchangetheinstallationprefix,theconfigurationfilewillbeplacedat/usr/local/etc/turnserver.conf.

Now,weneedtoeditthisfile,changingthenecessaryoptions.Wewillnotcoveralltheconfigurationoptions,butjusttheonesthatarenecessarytoachieveourgoal:

1. First,ensurethesupportforencryptedtransport:

tls-listening-port=5349

2. Switchtheverbosemodeon:

verbose

TipYoudon’twantverboseenabledonaproductionsystem,butitisveryusefulfordebugpurposes.I’drecommendyoukeepitenabledduringthedeveloping/debuggingprocess,andthendisableitwhenyoudeployyourapplicationtotheproductionsystem.

3. Enablealong-termcredentialmechanism—aRESTAPIcanbeusedwithlong-term

credentialsonly:

lt-cred-mech

4. Commentouttheshort-termcredentialmechanismoption:

#st-cred-mech

5. EnabletheRESTAPI:

use-auth-secret

6. Determinethestaticauthenticationsecret—theclientwillusethisvaluewhencalculatingthetemporarypasswordforaccessingtheTURNserver:

static-auth-secret=<SuperSecretKey>

7. Setuptherealm(usually,thecompany’swebsitedomainname):

realm=mycompany.org

8. Setupthegeneratedsecuritycertificate:

cert=/usr/local/etc/turn_server_cert.pem

9. Setupthecertificateprivatekey:

pkey=/usr/local/etc/turn_server_pkey.pem

10. Setupthesecuritycertificatekeypassword.Thisoptionisimportantifyouuseacertificateprotectedbyapassword.Ifthekeyispassword-less,thenleavethisoptioncommentedout:

#pkey-pwd=

11. Usingtheenableconsolefeature,youcanconnecttotheTURNserverconsoleandcontroltheserver,orjustgetsomestatistics.Itisveryusefulfordebugging:

cli-ip=127.0.0.1

cli-port=5766

12. Setuptheconsolepassword:

cli-password=<you-cli-password>

Howtodoit…NowwehaveaTURNserverinstalledandconfigured.Next,weneedtomakeappropriatechangesontheclient-sidecode(thatwillbeexecutedbythewebbrowser)andontheserver-sidecode.

Whatisimportantforthisfeatureisthatyourwebapplicationshouldhaveauserauthenticationmechanismimplemented.Theapplicationshouldhaveaprivateareawhereonlyauthorizeduserscangetaccess.

Thecertainimplementationdependsontheplatform/frameworkyouusefordevelopingtheapplication.

Implementingtheclient-sidecodeThegeneralflowtoimplementtheclient-sidecodeisasfollows:

1. Theapplicationhassomekindofauthorizationformwithaloginandpassword.ThewebpagewiththeWebRTCfeatureshouldbehiddenbehindtheloginpageandaccessshouldberestrictedtoauthorizedusersonly.

2. Aftertheuserenterscorrectcredentialsandhasbeenauthorized,he/shecanhaveaccesstoaprivatearea.

3. Whenauserisauthorized,he/sheshouldbeforwardedtotheprivateareawheretheWebRTCinteractivepageisplaced.

4. TheinteractivepagethatausergetsfromthewebservershouldcontaincorrectcredentialsforaccessingtheTURNserver.Thesecredentialsarecalculatedbythewebserverandarethensenttotheauthorizedclient.

Thefollowingfragmentisanexampleofwhatanauthorizedclientshouldgetfromthewebserver:

variceServers=[

{

'url':'turn:turn1.website.com',

'credential':'dejwjhkuyui4BUHiebdiejbi',

'username':'secretuser'

}

];

Here,thecredentialfieldisthetemporarypasswordcalculatedonthewebserverthatcanbeusedtoaccesstheTURNserver.Onlyauthorizeduserscangetit—usernameisalsousedwhilecalculatingthepassword(refertotheImplementingtheserver-sidecodesectionofthisrecipe).

TheclientshouldusethisdatawhenaccessingtheTURNserver(pseudocode):

pc_config={"iceServers":iceServers};

varpc=RTCPeerConnection(pc_config,pc_constraints);

Implementingtheserver-sidecode

Server-sidecodecanbeimplementedusinganylanguageandtechnologyyoulike.IfyouareaJavaprogrammer,theeasiestwaywouldbetouseJavaSpringorPlayFramework.

Thewebservershouldprovidethefollowingflowforimplementingserver-sidecode:

1. AuthenticatedusersshouldaccesstheWebRTCinteractivewebpageonly.2. Whenauserisauthenticatedusingtheloginpage,theyshouldbeforwardedtothe

privatearea(theWebRTCinteractivepage).3. Duringtheauthenticationprocess,thewebservershouldstoretheuserlogin.4. ThewebservershouldcalculatetheTURNtemporaryaccesspasswordusingthe

followingformula:

base64(hmac(secretkey,username))

Hereyoucanseethefollowing:

secretkey:Thisisthestatic-auth-keyoptionfromtheTURNserverconfiguration(refertotheGettingreadysectionofthisrecipe)username:Thisistheusernamethewebservergetsfromtheuserduringtheauthenticationhmac:Thisisthehashfunctionofsecretkeyandusernamebase64:Thisfunctionimplementsthebase64encodingalgorithm,andweapplyittotheresultofthehmacfunction

5. Afterthetemporarypasswordiscalculated,itshouldbesenttotheclient.

Howitworks…Inthisrecipe,wewillutilizetheTURNRESTAPI.ThemaingoalofthisAPIistoprovideamechanismthatwillenabledynamictemporarypasswords,whichcanbeusedwithTURNserverswhenauthenticating.

ThegeneralTURNauthenticationflowisasfollows:

Theclient(awebbrowser)sendsarequesttotheapplication(thatisworkingontheserverside)askingforTURNcredentials.Optionally,therequestcanalsoincludetheusername.TheapplicationrespondswithaTURNURL,username,andpassword.

TheclientthenusesthesecredentialsforfurtherauthenticationontheTURNserver.Theapplicationthenreplieswiththefollowingdata:

Username:ThisistheTURNusernamethattheclienthastousewhenauthenticating.Thisnameisacolon-delimitedcombinationoftheexpirationtimestampandusernameparameterfromtheclient’soriginalrequest.Iftheusernameisnotspecified,theservercanuseanyothervaluehere.Password:ThisistheTURNpasswordthattheclienthastousewhenauthenticating.Thisvalueiscalculatedbytheserverusingthefollowingalgorithm:base64(hmac(secretkey,username)).TheTURNserverandtheserverapplicationbothsharethesamesecretkey.So,theTURNserverwilldothesamecalculationsandwillcomparethemtothecredentialsreceivedfromtheclient.

NoteKindlynotethatcredentialsaretemporary(timelimited).

TTL:Thisvaluerepresentsthetime-to-liveparameter.Itisoptionalandwewon’tusethisfieldonourapplication.URIs:ThisfieldrepresentsanarrayofURLsoftheTURNserver(s)available.Inourcase,wewillsendjustoneURLtoourownTURNserver.

There’smore…Thisfeatureisnotapartofthefinalstandardyet,sointhefuture,someaspectsofthisrecipemightneedtobeimproved.

SeealsoRefertotheGeneratingaself-signedcertificaterecipeonhowtocreateself-signedcertificates.TakealookattheTURNserver’sRESTAPIstandarddraftathttp://tools.ietf.org/html/draft-uberti-rtcweb-turn-rest.ThePDFfromtherfc5766-trun-serverdocumentationcanbeuseful.Formoredetails,refertohttps://rfc5766-turn-server.googlecode.com/svn/docs/TURNServerRESTAPI.pdf.

ConfiguringawebservertoworkoverHTTPSInthisrecipe,wewillcoverhowtoconfigureasecuredlayer(HTTPS)onawebserver.AsfarasencryptionandsecurityaremandatoryforWebRTC,HTTPSisanimportantpartofthewholeapplication’ssecurityandsafety.

GettingreadyWewillcoverthethreemostpopularwebservers:Nginx,ApacheHTTPServer,andIISfromMicrosoft.Wewillnotcovertheinstallationprocedure,soyoushouldhavethewebserveryouwishtouseinstalledandproperlyconfigured.

Howtodoit…Whatweneedtodoistoeditthewebserver’sconfigurationtoswitchonusingHTTPS.Beforewemaketheconfigurationchanges,youneedtohavethegeneratedsecuritycertificate.Usually,itistwofiles:acertificateandcertificatekey.Butitispossibletojointhesetwofilesintojustone.Inthisrecipe,wewillconsiderthefirstoption,withtwofiles.

Thesecertificatefiles(server.crtandserver.key)canbetrustedSSLcertificatesortheycanbeself-signedcertificates.

ConfiguringNginxYoushouldeditthewebsite’sconfigurationfile—usually,itislocatedunder/etc/nginx/sites-enabled/website.com:

1. Thefollowingconfigurationfragmentshowsimportantchangesthatyoushouldmake:

server{

2. Wewillaskthewebservertolistenonport443(defaultportforHTTPS)anduseSSL:

listen443ssl;

3. Youshouldalsosetupthewebsite’sname—asyouwoulddoforanon-securedwebsite:

server_namewww.example.com;

4. Forasecuredwebsite,weneedtosetuptheSSLcertificateandSSLcertificatekey.Technically,they’rejusttwofilesgeneratedinaspecificway:

ssl_certificate/etc/nginx/ssl/certs/server.crt;

ssl_certificate_key/etc/nginx/ssl/private/server.key;

}

NoteAgoodpracticeistokeep.crtand.keyfilesindifferentfolders,asyoucanseeintheprecedingcode.Sodon’tforgettocopybothfilesofyoursecuritycertificatetoproperplaces.Createappropriatefoldersifnecessary.

5. Youwillneedtoreloadthewebserverafterthesechanges.ForUbuntu,thiscanbedoneusingthefollowingcommand:

sudoservicenginxreload

6. Alternatively,youcanrestartthewholewebserverusingthefollowingcommand:

sudoservicenginxrestart

ConfiguringApache

Youshouldeditthewebsite’sconfigurationfile—usually,itcanbefoundunder/etc/apache2/sites-available/website.conf.

Wewillnotcoveralltheconfigurationfilesbutwillconsiderrelevantchanges:

1. AddtheoptiontomaketheApachewebserverlistenontheHTTPSdefaultportNameVirtualHost*:443.

2. MakenecessarychangesintheappropriateVirtualHostsection:

<VirtualHost*:443>

ServerAdminwebmaster@website.com

DocumentRoot/var/www/website.com

ServerNamewww.website.com

DirectoryIndexindex.php

ErrorLog/var/log/apache2/vhost1-error.log

CustomLog/var/log/apache2/vhost1-access.logcombined

SSLEngineOn

SSLCertificateFile/etc/apache2/ssl/server.crt

SSLCertificateKeyFile/etc/apache2/ssl/server.key

<Location/>

SSLRequireSSLOn

SSLVerifyClientoptional

SSLVerifyDepth1

SSLOptions+StdEnvVars+StrictRequire

</Location>

</VirtualHost>

3. Afteryou’vemadethesechanges,youneedtorestarttheApacheHTTPServer.

ConfiguringIISInthissection,wewillcoverhowtoconfigureIIStousetheSSLcertificate:

1. Logontothewebservercomputerasanadministrator.2. ClickonStart,pointtosettings,andthenclickonControlPanel.3. Double-clickonAdministrativeTools,andthendouble-clickonInternetServices

Manager.4. Selectthewebsitefromthelistofdifferentservedsitesintheleftpane.5. Right-clickonthewebsiteonwhichyouwanttoconfigureSSL,andthenclickon

Properties.6. ClickontheDirectorySecuritytab.7. ClickonEditandthenonRequiresecure-channel(SSL).8. ClickonRequire128-bitencryptiontoconfigure128-bit(insteadof40-bit)

encryptionsupport.9. Toallowuserstoconnectwithoutsupplyingtheirowncertificate,clickonIgnore

clientcertificates:

There’smore…Theconfigurationprocessmightvarydependingonthecertainwebserverversionyouuse.Pleaserefertotheappropriatevendor’sdocumentationprovidedwiththewebserveryouuseforspecificdetails.

SeealsoRefertotheGeneratingaself-signedcertificaterecipefordetailsonhowtocreateself-signedcertificates.Thereyoucanalsofindadditionalinformationonwheretostartifyouwouldliketogetatrustedcertificatetouseinproduction.

ConfiguringaWebSocketsproxyonthewebserverWebSocketsisanewprotocolthatenablesactivemessagingfromservertoclient.Itissupportedbyallmodernwebbrowsers.ThisprotocolisimplementedontopofHTTPandcanbeeasilyservedbymostpopularwebservers.Itcanalsobeservedoversecuredchannels,suchasHTTPS.BecauseofWebSockets’advantages,peopleoftenchoosethisprotocolfortheirclient-serverprojects.InWebRTC-basedapplications,WebSocketsusuallyservesasatransportprotocolforsignalingserverimplementation.

ConfiguringaWebSocketsproxyonawebservercanbeveryusefulifyouhaveusedWebSocketsasatransportlayerforcommunicatingwiththesignalingserver.Forsomecases,itmightevenbemandatory.

GettingreadyConfiguringthisfeaturerequiresmakingchangesintheconfigurationfilesofthewebserver.Wewillnotcovertheentirewebserver’sinstallationandconfigurationprocess,soyouneedtohavethewebserverupandrunning.

Howtodoit…Wewillmakenecessaryconfigurationchangestothewebservertoachievethegoal.

ConfiguringNginxThewebsite’sconfigurationfilesareusuallylocatedunderthe/etc/nginx/sites-enabledfolder:

1. ThefollowingpieceofthewebsiteconfigurationfileshowstheWebSocketsproxysettings:

location/websocket{

2. HerewewillsetthelocalservicethatwillbeservingWebSocketrequestsforthewebserver:

proxy_passhttp://localhost:16384;

3. IndicatethatwewillworkwithHTTPprotocolversion1.1—WebSocketsisnotsupportedonlowerHTTPversions:

proxy_http_version1.1;

proxy_set_headerUpgrade$http_upgrade;

proxy_set_headerConnection"upgrade";

proxy_redirectoff;

4. HerewecansetadditionaloptionsaskingthewebservertosendusefuldetailsaboutconnectedclientsintheHTTPheaders:

proxy_set_headerHost$host;

proxy_set_headerX-Real-IP$remote_addr;

proxy_set_headerX-Forwarded-For$proxy_add_x_forwarded_for;

}

5. YouwillneedtorestartNginxorreloaditsconfigurationafteryou’vemadethesechanges.

TipYouneedaseparatelocationsectionforeveryWebSocketURLthatyouneedtoproxyviathewebserver.

ConfiguringApacheApachedoesn’tsupportthisfeaturefromscratch(atleast,forversions>=2.4).Nevertheless,therearesomethird-partymodulesthatcanhelpuswiththis.Inthisrecipe,wewillusetheapache-websocketmodule,availableathttps://github.com/disconnect/apache-websocket:

1. Thefollowingconfigurationfragmentshowshowtousethemodule:

<IfModulemod_websocket.c>

<Location/websocket>

SetHandlerwebsocket-handler

WebSocketHandler

/usr/lib/apache2/modules/mod_websocket_tcp_proxy.sotcp_proxy_init

WebSocketTcpProxyBase64on

WebSocketTcpProxyHostlocalhost

WebSocketTcpProxyPort16384

WebSocketTcpProxyProtocolbase64

</Location>

</IfModule>

2. OnadefaultApacheinstallation,youmightwanttochangeyourrequestreadtimeoutoption:

<IfModulereqtimeout_module>

RequestReadTimeoutbody=300,minrate=1

</IfModule>

3. YoucantracknativesupportofthisfeatureinApacheusinghttps://issues.apache.org/bugzilla/show_bug.cgi?id=47485.

ConfiguringIISTheWebSocketproxyfeatureisavailableinIISversion8andisnotsupportedinolderIISversions.

YoushouldinstallApplicationRequestRouting(ARR)3.0oranewerversion.Thisisaproxy-basedroutingmodulethatservestoforwardHTTPrequeststocontentservers.

AccordingtoMicrosoft’srecommendations,ARRshouldbeinstalledusingtheWebPlatformInstaller(WebPI)module.

ChooseApplicationRequestRouting3.0asdepictedintheprecedingscreenshot,andclickontheAddbuttonandthenclickonInstall.Duringtheinstallationprocess,youwillseethescreenshowninthefollowingscreenshot:

AfterARRisinstalled,youwillseeanappropriatemessageasshowninthefollowingscreenshot:

Now,whenARRisinstalledsuccessfully,youshouldinstalltheWebSocketsfeaturesonIISusingtheServerManagercomponentanditsManageandAddRolesandFeaturesmenus,asshowninthefollowingscreenshot:

Oncetheinstallationiscomplete,ARRwillhandleWebSocketsrequestsappropriately.

Howitworks…UsingsecurechannelsismandatoryforaWebRTCapplication.Inourrecipes,wehaveusedWebSocketsasatransportprotocoltocommunicatewiththesignalingserver.ThemaingoalofusingaWebSocketsproxyistohidetheWebSocketsservice(signalingserver)behindthewebserver,whichisservingoverHTTPS(securedlayer).Insuchacase,wedon’tneedtoconfigureHTTPSonthesignalingserveritself.

Thefollowingdiagramdepictsthewaythisworks.Whentheclient(webbrowser)makesarequesttothesignalingserverusingWebSockets,itdoesn’tmaketherequesttothesignalingserverdirectly,buttothewebserver(usingasecuredchannel,HTTPS).Then,thewebserverforwardsthisrequesttothesignalingserver(usingtheusual,non-securedlayer),andthenitforwardstheresponsebacktotheclient(thewebbrowser).

Thebenefitsofusingsuchasolutionareasfollows:

Youdon’tneedtoopenalisteningportofthesignalingservertotheexternalworldYouneedtoconfigureasecuredlayerforthewebserveronly,andnoneedtoconfigureitforthesignalingserverOntheclientside,youcanusethesamedomainandport

TipThesebenefitsarerelevantifyouhaveawebserverandsignalingserverbothinstalledonthesamemachine.

There’smore…Theconfigurationprocessmightvarydependingonthecertainwebserverversionyouuse.WebSocketsisayoungtechnologyandisnotsupportedbyoldwebservers.ThewebservershouldsupportHTTP1.1tobeabletosupportWebSocketsandtheWebSocketsproxy.So,youshouldusethenewestwebserverversion.

You’renotlimitedtousingWebSocketsforthesignalingservertransportprotocol.Thisisjustaparticularcase.Youcanuseanytransportyoulikeforthispurpose.So,ifyouprefertousesomethingdifferentratherthanWebSockets,thisproxyfeaturemightnotberelevantforyou,oryoumighthavetouseothersolutionstomakeyourprotocolofchoicesecureandsafe.

SeealsoInthisrecipe,webuiltthesignalingserverbehindthewebservertoutilizeitsHTTPS(securedlayer).FormoredetailsonhowtoconfigureHTTPSforwebservers,pleaserefertotheConfiguringawebservertoworkoverHTTPSrecipe.

ConfiguringafirewallIfyoudevelopaWebRTCapplicationandmaintainyourowninfrastructure(STUN/TURNservers,webservers),thenaproperlyconfiguredfirewallisveryimportantforyou.Usually,everyserverhasanetworkfirewallconfiguredandrunning.Misconfiguredfirewallscanblockservicesandcausesideeffects.WithWebRTC,amisconfiguredfirewallcanleadtheapplicationtoDoS(denialofservice)ormakesomepartsofitunworkable;forexample,youcanhearaudiobutcan’tseevideo.

Inthisrecipe,wewillcoverbasicinformationthatmighthelpyoutoconfigureanetworkfirewallproperly.

GettingreadyTherearemanyfirewallimplementations,anditisimpossibletocoverallofthem.Sohere,wewillmostlytalkaboutrecommendationsratherthanpracticalcommandsandcodes.

Findwhichfirewallisusedonyoursystem.OnWindows,itisabuilt-infirewall.OnLinuxsystems,youoftenhaveiptables.OnBSDsystems,itcanbepforipfw.MacsystemsusuallyusetoolsfromtheBSDfamily.Yoursystemmightevenbeusingsomekindofthird-partytool,soyoushouldrefertotherelevantdocumentationofthefirewalltoolthatisusedonyoursystem.

Howtodoit…Itisworthconsideringhowtoconfigureafirewallinthescopeofserversideandclientsideseparately.

ConfiguringafirewallonaserverIfyouhaveyourownserver(s)forallyourWebRTCapplicationcomponents(STUN,TURN,webserver,anyotherkindofnetworkservices),itisworthknowingwhichportsandprotocolscanbeusedbythesecomponentstocreateanappropriatenetworkingpolicy.Otherwise,yourapplicationmightfailtoaccesstheseservices.

DefaultportnumbersforknownservicesrelevantforWebRTCapplicationsareasfollows:

STUN/TURN:Ports3478and5349,UDPandTCP.ThesecondportisusedforTLS.Web:TCPport80forHTTPandTCPport443forHTTPS.Signalingserver:Thisdependsonthetechnologyandprotocolyouuse.Usingthisisagoodideaifyoucanhidethesignalingserverbehindthewebserversothatthesignalingservercanlistenonlocalhostonly,andnotlistentotheexternalworld.Ifyou’reusingTURN,yourservershouldhavetwoIPaddresses—keepthisfactinmindwhenconfiguringafirewall.Alltheprecedingportsshouldbeopenedandaccessibletotheexternalworld.

ConfiguringafirewallonaclientOfcourse,youcan’tcontrolafirewallontheuser’sside.Nevertheless,thefollowingdetailscouldhelpyouwhiledebuggingorproblemsolving.

WebRTChasgreatbuilt-inmechanismsandfeaturestohandlefirewallsandNetworkAddressTranslation(NAT).ItcanutilizeInteractiveConnectivityEstablishment(ICE),whichitsupportsviaTURNandusingSTUNservices.

Thefollowingscreenshotshowstwocases:

ThecommunicationprocessbetweenclientsandthesignalingserverDirectcommunicationbetweenpeersaftersignalization

Signalizationisnecessarywhenpeersarelocatedondifferentnetworks.Thesignalingservershouldbeknownandaccessibletoallpeers,andthentheycanexchangedatawitheachothervianetworkdatausingthesignalingserver,andthenestablishdirectconnection.

However,ifapeerislocatedbehindaNAT/firewall,thenthiswillnotwork—peershavenowaytoknowtheirownexternalnetworkaddresses,soestablishingthedirectconnectionisproblematic.

Thefollowingscreenshotshowssuchacase:

Inthiscase,beforepeerscanestablishadirectconnection,aSTUNserviceshouldbeusedbypeerstodetecttheirnetworkparameters.STUNallowspeerstoknowabouttheirexternalIPaddresses.Nevertheless,inmanycasesitwillnotwork—manyusersarelocatedbehindaNATandfirewall.

IfSTUNdidn’thelp,theonlysolutionthatmightsolvetheissueisaTURNserver.Inthiscase,allthedatabetweenpeerswillgothroughtheTURNserver—itwillproxyallmediaandotherdatathatpeerswilltransfertoeachother.Inotherwords,therewillnotbeadirectpeer-to-peerconnectionestablished,andallcommunicationwillbedoneviatheTURNserverinthemiddle.

ThisiswhyyouwillprobablywanttohaveyourownTURNserver—manybusinessclientshaveverystrongnetworkpoliciesandverycomplexfirewall/NATconfigurations,sosimplesolutionswilljustnotworkintheircases.

TipIfyoudevelopyourwebapplicationorserviceusingWebRTC,considerinstallingyourownSTUNandTURNserversattheverybeginning.

TheschemainthefollowingdiagramdepictsthedataflowwhileusingaTURNserver:

SeealsoTakealookattheConfiguringaWebSocketsproxyonthewebserverrecipefordetailsonhowtohidethesignalingserver(thecaseusingWebSocketsasthetransportlayer)behindthewebserver

Chapter3.IntegratingWebRTCInthischapter,wewillcoverthefollowingtopics:

IntegratingWebRTCwithAsteriskIntegratingWebRTCwithFreeSWITCHMakingcallsfromawebpageIntegrationofWebRTCwithwebcameras

IntroductionThischapterisfullydedicatedtothetopicofintegratingWebRTCwiththerestoftheworld—othercomponents,technologies,andservices.

YouwillfindrecipesonintegrationofWebRTCwithVoIPplatforms(AsteriskandFreeSWITCH),andwilllearnhowtoimplementasimplesolutionintheMakingcallsfromawebpagerecipeusingWebRTCandSIP.WewillalsocovertheintegrationofWebRTCwithwebcameras.

Inthischapter,wewillnotwritecode,butwillinstallandconfigurethird-partyapplicationsandlibraries,connectingthemwitheachotherinordertoachievethegoal.Mostofsoftwarethatwehavecoverediscross-platform,buttosimplifythetask,wewillcoverLinux-basedinstallationsonly.So,formostofrecipes,youwillneedtohaveapreparedLinuxmachine.Sincewewillconsidersimplecases,itwillnotneedmanyresources,soifyoudon’thaveaready-to-useLinuxbox,youcanusesomespecialsoftwareforcreatingvirtualLinuxmachinetoworkontherecipes.ItcanbeVMware,VirtualBox,oranyothersolutionyoulike.YoucanuseanyLinuxdistributionforthesepurposes;IpersonallyusedUbuntuwhileworkingonthisbook.

NoteSomecommandsorsystempathsmightbedifferentfordifferentLinuxdistributions.

Therecipesofthischapterdon’tcoverallthecompletedsolutionsfromscratch,andcoverspecificquestionsonly.So,itisassumedthatyouhavebasicknowledgeofusingtheLinuxcommandlineandhavebasicexperienceofinstallingandconfiguringLinuxsoftware.

IntegratingWebRTCwithAsteriskInthisrecipe,wewillcovertheintegrationofWebRTCwithAsterisk—anopensourceplatformusedtobuildcommunicationsapplications.Asteriskturnsanordinarycomputerintoacommunicationsserver.AsteriskpowersIPPBXsystems,VoIPgateways,conferenceservers,andothercustomsolutions.Itisusedworldwidebysmallandlargebusinesses,callcenters,carriers,andgovernmentagencies.

Asterisk-basedtelephonysolutionsofferarichandflexiblefeatureset.AsteriskoffersbothclassicPBXfunctionalityandadvancedfeatures,andinteroperateswithtraditionalstandards-basedtelephonysystemsandVoiceoverIPsystems.Asteriskofferstheadvancedfeaturesthatareoftenassociatedwithlarge,high-end(andhighcost)proprietaryPBXs.

GettingreadyInthisrecipe,wewillworkunderLinux.So,prepareaLinuxbox.WealsowillusetoolssuchasGitandSVN—installthemifthey’renotinstalledyetonyourmachine.

YoumightwishtoinstallFreePBXtomakeyourlifeeasierwhenconfiguringAsterisk.Thissoftwarecanbefoundonitshomepageathttp://www.freepbx.org.

IassumethatyouhavesomeexperiencewithinstallingandconfiguringLinuxsoftware.Ifnot,youcanrefertoahelppageonLinuxbasics,forexample,http://manuals.bioinformatics.ucr.edu/home/linux-basics.

Howtodoit…Duringthisrecipe,wewillinstallandconfigureasetofapplicationsandbuildaservicebyintegratingtheseapplicationswitheachother.Wewillnotcoveralltheinstallationandconfigurationstepsfromscratch,butwillcoverspecificstepsonlythatmightberelevantintothisrecipe.

InstallinglibSRTPBeforewecompileandinstallAsterisk,weneedtoinstalllibSRTP—asoftwarelibrarythatprovidesanSRTP(SecureReal-timeTransportProtocol)implementation.AsteriskshouldsupportSRTPforintegratingwithaWebRTCapplication.ThesupportofthisprotocolisnecessarybecauseWebRTCusessecuredchannelstobuildcommunicationbetweenpeers.WeinstalllibSRTPwiththefollowingsteps:

1. Createadirectory~/src/libsrtpandgotoit.2. Downloadlibsrtptothefolderfromthelibrary’shomepage,

http://sourceforge.net/projects/srtp/files/.3. Unpackthedownloadedarchiveandgointothesrtpfolder.4. Compilethelibrary:

./configureCFLAGS=-fPIC

make

sudomakeinstall

Atthispoint,wehavecompiledandinstalledthelibSRTPlibrarythatwillbeusedwhenbuildingandinstallingAsterisk.

InstallingAsteriskInthisrecipe,wewillinstallAsterisk11.5;performthefollowingstepstodoso:

1. DownloadAsteriskfromthehomepage,http://www.asterisk.org.2. UnpackthearchiveandgointotheAsterisksourcecodefolder.3. ConfigureAsteriskasfollows:

./configure--with-crypto--with-ssl--with-srtp=/usr/local/lib

contrib/scripts/get_mp3_source.sh

makemenuselect.makeopts

menuselect/menuselect--enableformat_mp3--enableres_config_mysql--

enableapp_mysql--enableapp_saycountpl--enablecdr_mysql--enable

EXTRA-SOUNDS-EN-GSM

TipParticularconfigurationoptionsgivenintheprecedingcodecanvarydependingonyourspecificcase.Forexample,youmightbenotusingMySQLbutsomeotherdatabase.InnewestversionsofAsterisk,app_saycountplisreplacedwithapp_saycounted.

4. BuildAsteriskasfollows:

make

makeinstall

NowwehavecompiledandinstalledAsterisk,wecanconfigurethesoftwarewiththefollowingsteps:

1. Edit/etc/asterisk/sip.confandchangetheGeneralsection:

udpbindaddr=0.0.0.0:5060

realm=<your_server_IP>

transport=udp,ws

2. Edit/etc/asterisk/rtp.conftoenableSTUNandICE:

icesupport=yes

stunaddr=<IP_of_your_STUN_server>

TipIfyoudidn’tinstallyourownSTUNserveryet,youcanusethepublicSTUNservicefromGoogleatstun.l.google.com:19302.

3. Edit/etc/asterisk/http.confandenableanHTTPservice:

[general]

enabled=yes

bindaddr=0.0.0.0

bindport=8088

4. Edit/etc/asterisk/sip.confandcreateaSIPaccount:

[8000]

secret=SuperS3cret

context=from-internal

host=dynamic

trustrpid=yes

sendrpid=no

type=friend

qualify=yes

qualifyfreq=600

transport=udp,ws

encryption=yes

dial=SIP/8000

callerid=JohnDow<8001>

callcounter=yes

avpf=yes

icesupport=yes

directmedia=no

YoucanfindadditionaldetailsonAsteriskconfigurationoptionsathttp://www.voip-info.org/wiki/.

5. Nowthattheconfigurationisfinished,restartAsterisk.

Howitworks…Thewholeschemaofinteroperationbetweenallthecomponentscanbefoundinthefollowingdiagram(takenfromthesipML5library’shomepage):

Asyoucansee,HTML5clientcaninteractwithaVoIPplatformusingWebRTCandaSIPmodule(JavaScriptSIPinthediagram).

There’smore…ThereisanopinionthatAsteriskisnotthebestchoice.Itisperhapstheoldestandmostmaturesolutioninthefield.Nevertheless,manypeoplefounditbuggyandunstableinsomecases.Inparticular,WebRTCwasnotsupportedbymanyuntilthepreviousversions.

So,ifyouarelookingforalternatives,itmightbeagoodideatotryothersolutionssuchasFreeSWITCH.Itshomepagecanbefoundathttp://www.freeswitch.org.

SeealsoForanalternativesolution,usingotherVoIPsoftware,refertotheIntegratingWebRTCwithFreeSWITCHrecipeIntheMakingcallsfromawebpagerecipe,wewillcoverhowtomakecallsfromwebpagesusingWebRTCandaVoIPplatformintegration

IntegratingWebRTCwithFreeSWITCHInthisrecipe,wewillcovertheintegrationofWebRTCwithFreeSWITCH—anopensourceplatformusedtomakeVoIPcommunicationservices.

FreeSWITCHisascalableopensourcecross-platformtelephonyplatformdesignedtorouteandinterconnectpopularcommunicationprotocolsusingaudio,video,text,oranyotherformofmedia.Itwascreatedin2006tofillthevoidleftbyproprietarycommercialsolutions.FreeSWITCHalsoprovidesastabletelephonyplatformonwhichmanytelephonyapplicationscanbedevelopedusingawiderangeoffreetools.

GettingreadyInthisrecipe,wewillworkunderLinuxaswell.So,youneedaLinuxboxtobeprepared.

ItispossibletoinstallFreeSWITCHunderWindows,butwedon’tcoverthisusecaseintherecipe.IfyouneedaWindowsinstallation,pleaserefertotheofficialdocumentationathttp://wiki.freeswitch.org/wiki/Installation_for_Windows.

Duringthework,wewillalsousetoolssuchasGitandSVN—installthemifthey’renotinstalledyetonyourmachine.IassumethatyouhavesomeexperiencewithinstallingandconfiguringLinuxsoftware.

Howtodoit…Duringthisrecipe,wewillinstallandconfigureasetofapplicationsandbuildaservicebyintegratingtheseapplicationswitheachother.Wewillnotcoveralltheinstallationandconfigurationstepsfromscratch,butwillonlycoverthespecificstepsthatmightberelevanttothisrecipe.

InstallingFreeSWITCHFreeSWITCHcanbeinstalledfromprecompiledbinarypackagesorfromsourcecode.Thefirstwayiseaser,butthevendorrecommendsthesecondone.WeinstallFreeSWITCHwiththefollowingsteps:

1. Installthenecessarypackagesforyoursystem:

apt-getinstallautoconfautomakedevscriptsgawkg++git-corelibjpeg-

devlibncurses5-devlibtoolmakepython-devgawkpkg-configlibtiff5-

devlibperl-devlibgdbm-devlibdb-devgettextlibssl-devlibcurl4-

openssl-devlibpcre3-devlibspeex-devlibspeexdsp-devlibsqlite3-dev

libedit-devlibldns-devlibpq-dev

2. Gotothe/usr/srcfolderandcompilesourcecode:

cd/usr/src

gitclonehttps://stash.freeswitch.org/scm/fs/freeswitch.git

cd/usr/src/freeswitch

./bootstrap.sh–j

./configure--enable-core-pgsql-support

make&&makeinstall

NoteInthiscase,wewillusethemasterversion.Notethatmasterversionsareusuallyunstable,andforproductionsystems,youshouldusestableversionsonly.Forthisinformation,refertothehomepageandclonetherelevantstableversionathttps://www.freeswitch.org.

3. Installsounds:

makecd-sounds-installcd-moh-install

4. Setpermissionsandthefileowner:

cd/usr/local

adduser--disabled-password--quiet--system--home

/usr/local/freeswitch--gecos"FreeSWITCHVoicePlatform"--ingroup

daemonfreeswitch

chown-Rfreeswitch:daemon/usr/local/freeswitch/

chmod-Rug=rwX,o=/usr/local/freeswitch/

chmod-Ru=rwx,g=rx/usr/local/freeswitch/bin/*

NoteFormoredetails,refertohttps://www.freeswitch.org.

EnablingWebRTCFreeSWITCHsupportsWebRTCfromversion1.4.WebRTCcanbeenabledordisabledbychangingappropriateoptionsintheconfigurationofFreeSWITCH.Bydefault,configurationoptionsthatenableWebRTCarecommentedout,soWebRTCisdisabled.ToenableWebRTCinFreeSWITCH,youshouldopensip_profiles/internal.xmlconfigurationfileandeditappropriateconfigurationoptionsasshown:

<!--uncommentforsipoverwebsocketsupport-->

<paramname="ws-binding"value=":5066"/>

<!--uncommentforsipoversecurewebsocketsupport-->

<!--Youneedwss.pemin/usr/local/freeswitch/certsforwss-->

<!--<paramname="wss-binding"value=":7443"/>-->

YouwillneedtorestartFreeSWITCHafterthischange.

NoteYouneedtouseSSL/TLScertificatesifyouwanttoutilizetheWebSocketssecuredlayer(WSS).

StartingFreeSWITCHYouneedtoaddanewuserintoFreeSWITCH.Pleaserefertotheappropriatepageonthistopicathttps://wiki.freeswitch.org/wiki/XML_User_Directory_Guide.

Afteryou’vemadealltheconfigurationsteps,starttheFreeSWITCHbyusingthefollowingcommand:

cd/usr/local/freeswitch/bin

./freeswitch

NowwehaveFreeSWITCHinstalledwithenabledwiththesupportofWebRTC.

Howitworks…It’sbettertouseadiagramtodescribetheworkflow,sohavealookatthefollowingdiagram:

There’smore…FreeSWITCHisnottheonlyVoIPplatformsolutionexistingintheworld.Oneofthebest-knownalternativesisAsterisk.

Decidingwhichparticularsolutionmightfityourrequirementsisalluptoyou.TheybothhavesupportforWebRTCsincethelastversions(middleof2014).Sotheybothmightcontainsomebugsorfeaturesrelatedtothetechnology.

AsteriskseemstobeolderandmorematurethanFreeSWITCH.Therearemorehacksandthere’smoredocumentationrelatedtoAsteriskthanFreeSWITCH.

SoifyouarelookingforalternativestoFreeSWITCH,itmightbeworthtryingAsterisk.Itshomepageishttp://www.asterisk.org.

SeealsoForanalternativesolution,usingotherVoIPsoftware,refertotheIntegratingWebRTCwithAsteriskrecipeIntheMakingcallsfromawebpagerecipe,wewillcoverhowtomakecallsfromwebpagesusingWebRTCandaVoIPplatformintegration

MakingcallsfromawebpageInthisrecipe,wewillcovertheprocessofmakingcallsfromwebpages.Forthistask,youwillneedtorunaVoIPservice.ItcanbeyourownAsteriskorFreeSWITCHinstallation,oritcanbesomeexternal,cloud,orSaaSVoIPsolution.

Toachieveourgoal,wewilluseanHTML5SIPlibrarytomakecallsfromawebpagetoaphonenumberandviceversa.

GettingreadyInthisrecipe,wewillworkunderLinux,soprepareaLinuxbox.WewillalsousetoolssuchasGitandSVN—installthemifthey’renotinstalledyetonyourmachine.

Youwillneedawebserverinstalled.ItmightbeNginx,ApacheHTTPServer,oranyotherwebserveryoulikethemost.IassumethatyouhavesomeexperienceofinstallingandconfiguringLinuxsoftware.

Howtodoit…Duringthisrecipewewillinstallandconfigureasetofapplicationsandbuildaservicebyintegratingtheseapplicationswitheachother.Wewillnotcoveralltheinstallationandconfigurationstepsfromscratch,butwillonlycoverspecificstepsthatmightberelevanttothisrecipe.

InstallingsipML5ThefirstHTML5SIPclientissipML5.Wewillusethislibraryinthisrecipetoachieveourgoal.

1. Gointoyourdefaultwwwfolderofthewebserver.Itmightvaryondifferentsystems.ForUbuntuitcanbe/usr/local/www.

2. DownloadthesipML5sourcecode:

svncheckouthttp://sipml5.googlecode.com/svn/trunk/

3. GiveAsteriskaccessrightstodownloadedtheproject:

chown-Rasterisk:asterisk/usr/local/www/trunk/

4. OpentheChromewebbrowserandnavigatetohttp://<your_IP>/trunk/call.htm.

Here,your_IPistheIPaddressofyourmachinewheresipML5hasbeeninstalled.

5. GotoExpertModeandsettheoptionsasdepictedinthefollowingscreenshot:

Putyouractualmachine’sIPaddressinsteadofyour_IP.

TipIfyouhaveyourownSTUNserverinstalled,youcanspecifyitsIPornameattheICEServersoption.

6. Savethechanges.7. Nowgetbacktothefirsttabandfillinthefieldsasdepictedinthefollowing

screenshot:

Notethatyoushouldoutyourmachine’sactualIPaddress(whereAsteriskandsipML5areinstalled)insteadoftheyour_IPword.

TipUsethesamepasswordyouconfiguredforAsterisk(SuperS3cretinthisrecipe).

NowclickonLogin—youshouldseeaConnectedstatuslineatthetopoftheRegistrationbox.

NowyoucantrytomakeanoutgoingcallusingtheCallcontrol—callonanynumberthatisservedbytheVoIPplatform(AsteriskorFreeSWITCH)andisregisteredinthesystem.Incomingcallsshouldworkaswell;youcancheckthemusinganySIPsoftphoneclient.Hereareafewofthem:

Bria:Formoreinformation,gotohttp://www.counterpath.com/bria

Telephone:ToknowmoreaboutTelephone,refertohttps://github.com/eofster/Telephone

Zoiper:Formoredetails,refertohttp://www.zoiper.com/en

ExpressTalk:Refertohttp://www.nch.com.au/talk/formoreinformation

3CXPhone:Formoreinformation,gotohttp://www.3cx.com/voip/softphone/

X-Lite:ToknowmoreaboutX-Lite,refertohttp://www.counterpath.com/x-lite

Howitworks…Theworkingflowofthisconstructedsoftwaresystemmightbelookingrelativelycomplexforsomeonewhoisnotbuildingsuchsystemseveryday.Although,theworkingflowoftheintegratedsystemisnotthatcomplex:

HTML5SIPclient(sipML5inourcase)isjustaVoIPsoftphoneimplementedtoruninthebrowser.Thein-browsersoftphoneusesWebRTCtechnologytogetaccesstothecomputer’smultimedia(cameraandmicrophone).ThenusingWebRTC,SIPprotocol,andWebSockets,thein-browsersoftphoneestablishescommunicationwiththeVoIPplatform(AsteriskorFreeSWITCHforexample).Then,thesoftphoneregistersinthesystem.Afterthat,thesoftphonebecomesavailabletotheusertomakecalls.Thus,thein-browsersoftphonebecomesabletomakephonecallstootherendpointsoftheVoIPplatform.IftheVoIPplatformhasagatetoanexternalphonenetwork,youcanevenmakeexternalphonecallsusingjustthein-browsersoftphone.

There’smore…ThesipML5libraryisnottheonlysolutionthatcanbeusedforthistask.Thereareseveralalternativesoftwarepiecesthatcanbeusedinthisscopeaswell.Herearetwoexamplesofthem:

SIP.js:Formoreinformation,refertohttp://sipjs.com/

JsSIP:Refertohttp://jssip.net/formoreinformation

Eachlibraryhasitsownprosandconsandcanbesuitableforyourparticularexpectationsandrequirements.Thecommonintegrationschemaremainsthesame,soyoucantrydifferentsoftwareanddecidewhichoneisbestforyou.

SeealsoYouwillneedaVoIPplatform(SIPserver)installedtomakecallsfromawebpage.Youcanuseanexistingexternalserveroryoucaninstallyourown.ToinstallyourownVoIPplatform,pleaserefertothefollowingrecipes:

RefertotheIntegratingWebRTCwithAsteriskrecipetolearnhowtointegrateWebRTCwithAsteriskRefertotheIntegratingWebRTCwithFreeSWITCHrecipetolearnhowtointegrateWebRTCwithdifferentVoIPsolutionssuchasFreeSWITCH

TipItwouldprobablybegoodideatouseanexternalorcloudVoIPplatformforsuchpurposesinproduction.Maintainingagood,working,andscalableVoIPplatformcannotbeeasy.

IntegrationofWebRTCwithwebcamerasInthisrecipe,wewilldiscusshowtointegrateWebRTCwithwebcameras.WhymightsomeonewanttointegrateawebcamerawithWebRTCtechnology?Herearesomereasonswhytheymightdothis:

AwebcameraneedsaJavaorActiveXenabledontheclientforittobeableseetheimagefromthecamera.ManycomputershaveJavainstalled;neverthelessinsomecases,itmightbeimpossibletoinstall/useJavaorActiveX.RegardingActiveX,thistechnologyissupportedevenonfewerdevicesthanJava.WebRTCcanbecomeauniversalandlightweightwaytoshowmultimediafromawebcamandthatdoesn’tneedyoutoinstallanyadditionalsoftware.Asofnow,WebRTCisfullysupportedonAndroiddevices(mostlytheonesthatuseChromemobile),butinthenearfuture,itissupposedtobesupportedonothermobileplatformsaswell(suchasiOSandWindowsMobile).Atthistime,youusuallyhavetoinstallJVMorFlashPlayerinyourmobileifyouwanttoseeavideofromawebcam.Often,itisbarelypossibleatall.Webcamsusuallyareveryresourcelimiteddevices.Whenseveralclientsaccessthecameraatonetime,itcanshowtimedelaysandcanevengetstuck.SuchanissuecanbesolvedveryeffectivelybyusingofaWebRTCapplicationthatisintegratedintotheconnectionbetweentheuserandthecamera.

Herewecoverpossiblesolutionforsuchatask:capturingavideofromawebcam,transcodingitintoWebRTCflow,anddisplayingitinthewebbrowser.

GettingreadyTherearemanywaysinwhichwebcamsgiveoutvideos.Usually,itcanbeasetofJPEGimagesorRTSPflow.Inourexperiments,wewillcoverthesecondcaseandwilluseaD-LinkDCS-5220webcamera.

Soforthisrecipe,youneedawebcamthatcandoRTSP.Inmycase,itisD-Linkbutyoucanuseanyotherwebcam—therecipewillstillberelevant,butsomeminorchangesmightbenecessary.Installandconfigurethewebcamandconnectittothenetwork.

Inthisrecipe,wewillalsoinstallandconfiguretheWebRTCmediaserver—thissoftwareiswritteninJava,soyouneedJVMinstalledinyourbox.Onemorethingthatyouwillneedtodoisinstallawebserver.YoucanuseNginx,ApacheHTTPServer,oranyotherwebserverofyourchoice.

Howtodoit…Wewillconfigurethewebcam.ThenwewillinstallandconfiguretheWebRTCmediaserver,andthenwewillconnectallthecomponentsinthewholesystem.

ConfiguringthewebcamFirstofall,wewilldosomeminorconfigurationswiththewebcamera.Todoso,performthefollowingsteps:

1. Navigatetothewebcam’sadminpageandopentheNETWORKSETUPmenu.WeneedtogototheRTSPsection:

Inthissection,weneedtolookfortheRTSPportparameter—itshouldbe554bydefault.ItisalsoworthtosettheRTSPAuthenticationfieldtotheDisablestate—forthetimebeingwe’reworkingonthetask.

Checkwhetherthewebcamworksasexpected.Forthis,youcanuseVLCmediaplayer—justopenrtsp://cam_IP/live1.sdpintheplayer.

TipNotethatyouneedtoinserttherelevantIPaddressofthewebcamerainsteadofcam_IP.Ifthecameraisconfiguredthecorrectway,youwillseeavideocapturedfromit.

InstallingWebRTCmediaserverAsweknowalready,ourwebcamerastreamsmediaoverRTSP,butwewanttowatchthatstreaminawebbrowserusingWebRTC.SoyouhavetoconvertthemediafromRTSPtotheWebRTCform.Forthispurpose,wewillusetheWebRTCmediaserverfromFlashphoner.

ThissoftwarecancapturemediafromRTSPstreamer,re-encodeit,andstreamitinWebRTC:

1. Downloadthemediaserverfromitshomepageathttp://flashphoner.com/download_webrtcserver/.

2. Unpackthearchive:

tar-xvzfFlashphonerMediaServerWebRTC.tar.gz

3. Installtheserver:

cdFlashphonerMediaServerWebRTC

./install.sh

TipDuringtheinstallation,youwillbeaskedonthepublicandprivateservers’IPs.Ifyou’reexperimentingonyourlocalmachine,boththeIPsmightbeidentical.

4. Startthemediaserver:

servicewebcallserverstart

5. Checkwhetherthatserverisrunning:

ps-ax|grepFlashphoner

TipYoualsocanlookintoyourmediaserver’slogfilestocheckwhethereverythingisallright:/usr/local/FlashphonerWebCallServer/logs/server_logs/flashphoner.log.

6. Gotoyourwebserver’swwwfolder—inmycaseitis/usr/local/www:

cd/usr/local/www

7. DownloadthewebUIfilesintothefolder:

wget

https://github.com/flashphoner/flashphoner_client/archive/wcs_media_cli

ent.zip

ClientswillaccessthisUIviathewebserverinordertoseethecapturedmediastreamsfromthewebcamera.Inotherwords,thisistheUIforthemediaserver.

8. Unpackthearchive:

unzipwcs_media_client.zip

9. Thereareseveralnestedemptyfoldersinthearchive,soitisworthwhilemovingthenecessaryfilestotheupperlevelandmakinglifeabiteasierwiththefollowingcommands:

mvflashphoner_client-wcs_media_client/client/wcs_media_client./

rm-rfflashphoner_client-wcs_media_client/

10. Editthiswcs_media_client/flashphoner.xmlconfigurationfileandsettheproperIPaddressoftheWebRTCmediaserver:

<flashphoner>

<wcs_server>188.226.144.63</wcs_server>

<ws_port>8080</ws_port>

<video_width>1280</video_width>

<video_height>720</video_height>

</flashphoner>

Themediaserverisnowinstalledandproperlyconfigured!

TimeformagicNowwheneverythingisconfiguredandrunning,itistimetodothemagic.Fromyourwebbrowser,gotohttp://<server_IP>/wcs_media_client/?id=rtsp://<cam_IP>/live1.sdp.

ThefollowingparametersarementionedintheprecedingURL:

<server_IP>:ThisistheIPaddressofthemachinewheretheWebRTCmediaserverwithitsUIisinstalled<cam_IP>:ThisistheIPaddressofthewebcamera

WhilenavigatingtotheURL,youwillfirstseeanimagefromthemediaserver,asshowninthefollowingscreenshot:

Atthisstage,theWebRTCmediaserverwilltrytoconnecttothecameraandnegotiatewithitregardingthestreamcapturing.Itcantakeseveralseconds.Whenthe

communicationprocessisdone,theserverbeginscapturingthemediastreamfromthecameraandencodingitintotheWebRTCformat.Afterthat,youwillseetheimagefromthecamera.

Howitworks…Thefollowingdiagramdepictsthegeneralschemaofwhatwebuiltinthissolution:

Asyoucansee,theWebRTCmediaservercapturesthestreamfromthewebcameraandthentheclientscanseethecapturedstreamintheirwebbrowsersusingWebRTC.Whatisimportanthere,isthatclientsarenotconnectedtothewebcamandtheydon’tgetmediastreamedfromthewebcamdirectly;instead,clientsareconnectedtotheWebRTCmediaserver,andtheygetallmediastreamsfromthemediaserver.

Inthefollowingdiagram,youcanseetheworkflowofhowitworks,stepbystep:

There’smore…Youmightwanttotakealookatanothersolution—janus-gateway.Formoreinformationrefertohttps://github.com/meetecho/janus-gateway.

Thissolutionisopensource(whiletheserverfromFlashphonerisnot).Atthetimeofwritingthis,itworksunderLinuxonly,butitsauthorsclaimcross-platformsupportinthefuture.

Anotherpopularmediaserver,Wowza,canalsocapturetheRTSPstreamfromcameras,butitsmainpurposetore-encodemediadataintoFlash,soforWebRTC,thissolutionishardlysuitable.Nevertheless,Wowzacanbeaninterestingsolutionaswell,forexample,ifyouneedyourapplicationtosupportFlashtechnologyalongwithWebRTC.Thissoftwarecanbefoundathttp://www.wowza.com.

ManycamerasstreamtoMotionJPEG,andthisrecipeisirrelevantforsuchdevices.Nevertheless,itispossibletobuildasimilarsolutionforthemaswell,usingsimilarschema.

Chapter4.DebuggingaWebRTCApplicationInthischapter,wewillcoverthefollowingtopics:

WorkingwithaWebRTCstatisticsAPIDebuggingwithChromeDebuggingTURNDebuggingusingWireshark

IntroductionDebuggingisaveryimportantaspectindevelopingacomputersoftware.Evenifyouareanexperienceddeveloperandwriteverycleanandprofessionalcode,youmightfacesomesituationswhentheonlygoodwaytounderstandwhat’sgoingwrongisdebuggingandprofiling.

Inthischapter,wewillcoverdebuggingwithinthescopeofdevelopingWebRTCapplications.WewilltalkaboutspecificusefultoolsbuiltinChromewebbrowser,whichcanbehelpful.Also,wewillcoverbasicquestionsofdebuggingJavaScriptapplicationsinthescopeofthemaintopic.Ofcourse,wewillcovertheserversideaswell.

WebRTChasaveryusefulAPIknownasstatisticsAPI;itcanbeusedformonitoringanddebuggingWebRTCapplications.Wewillcoverthistopicintheappropriaterecipe,consideringreal-worldusecasesandpracticalpossiblesolutions.

AWebRTCapplicationusuallyworksveryintensivelywithnetwork.Therefore,wewilllearnhowtouseWireshark(anetworksniffer)fordebuggingpurposesinthescopeofdevelopingWebRTCapplicationsandservices.

WorkingwithaWebRTCstatisticsAPIWebRTC’sstandarddescribesstatisticsAPI—amechanismthatanapplicationcanuseforgettingmanykindsofstatisticaldata.Usingthismechanismcanbehelpfulwhendebuggingapplications,becauseyoucangetaccesstosomehiddendatathatisnotvisibletotheapplicationortoacustomerinanyotherway.

UsingthispartofAPIyoucanbetterunderstandwhatisgoingonunderthehoodofthewebbrowserandyourapplication.Itisveryusefulifyouareabeginnerandwouldliketoknowmoreonhowallthisworks.Itisalsohelpfulifyou’reanexperienceddeveloperandarecreatingsomeadvancedfeatureintheapplication.

GettingreadyForthisrecipe,wewillnotdomuchconfigurationwork.WewillnotinstallanylibrariesorcompileLinuxsoftwarelikewedoinsomeotherrecipes.Thisrecipeisdedicatedtodebuggingandmostofthetopicisdedicatedtoclientside.Therefore,mostofthematerialisaboutJavaScript,thewebbrowserandbrowser’sconsole.

IwouldrecommendyouuseChromeforthisrecipe,becausethisbrowserstillseemstobemorestableinthescopeofsupportingWebRTC.Moreover,usuallyChromehasbetterandmoreadvancedsupportforthistechnology.

Howtodoit…Foraccessingthestatisticsdata,youshouldusethegetStatsAPIfunction(amethodofPeerConnectioninstances).Whilecallingthisfunction,youhavetopasstheselector.Inreply,thebrowserwillreturnrelevantstatisticaldata.

SinceWebRTCisstillunderdevelopment,theAPIfunctionsmightstillhavedifferentnamesinthesupportedwebbrowsers.Tosolvethisissue,itisworthwhiletowriteadditionalcodethatcouldserveasawrapperanduniversalAPItothefunction.Thefollowingcodecanbeusedasasimpleexampleofsuchbehavior:

functionmyGetStats(peer,callback){

if(!!navigator.mozGetUserMedia){

peer.getStats(

function(res){

varitems=[];

res.forEach(function(result){

items.push(result);

});

callback(items);

},

callback

);

}else{

peer.getStats(function(res){

varitems=[];

res.result().forEach(function(result){

varitem={};

result.names().forEach(function(name){

item[name]=result.stat(name);

});

item.id=result.id;

item.type=result.type;

item.timestamp=result.timestamp;

items.push(item);

items.push(item);

});

callback(items);

});

}

};

Nowlet’swriteafunctionthatwewillcallfromtheapplicationtogetthestatistics.Thisfunctionwillprintstatisticaldatatothebrowser’sconsoleevery5seconds:

functionprintStats(peer){

myGetStats(peer,function(results){

for(vari=0;i<results.length;++i){

console.log(results[i]);

}

setTimeout(function(){

printStats(peer);

},5000);

});

}

Next,weshouldputthefunctioncallintheproperplaceintheapplication.Somewhereinyourapplication,youshouldcreateapeerconnectionobjectusingaconstructionsimilartothefollowing:

pc=newRTCPeerConnection(pc_config,pc_constraints);

Afterthat,youshouldsetuptheonaddstreamcallbackofthecreatedobject:

pc.onaddstream=onRemoteStreamAdded;

Here,onRemoteStreamAddedisacallbackfunctionthatiscalledoncewhenpeerconnectionisestablished.Inthefollowingcallbackfunction,youshouldaddsomecodethatcallstheprintStatsfunction,whichwehavejustwrittenintheprecedingcode:

varonRemoteStreamAdded=function(event){

clog("Remotestreamadded.");

attachMediaStream(remoteVideo,event.stream);

remoteStream=event.stream;

printStats(pc);

};

Ihaveprovidedthefulllistofthefunctionsheretoshowthebigpictureandmakeitclear.YoucanseeinthefollowingscreenshotthatafterthemediastreamisattachedtothepropervideoHTMLtag,wecallprintStatssothatitprintsthestatisticaldatatotheconsoleevery5seconds:

HereyoucanseeascreenshotofanexamplewebpagethatusesthedescribedprintStatsfunction.Thewebbrowserconsoleisopened,andyoucanseethestatisticaldataprintedthere.Thestatisticaldatalooksincomprehensible,butthefollowingscreenshotswillgiveyoumoredetails,makingitclearer.

Thefollowingscreenshotdepictsapartofthebrowser’sconsolewithoneoftheexpandedstatisticdataobjects.Inthescreenshot,youcanseetheObjectstructure,andaccordingtoitsoptionsitisanaudiotrack:itsinputlevelis131,itsusedcodecisOpus,andtherewerearound300kilobytessentthroughthischannel.Youcanalsoseeotherusefulinformationregardingthisobject,suchasechocancellationfeaturedetails.

Anotherscreenshotpresentsonemoreexpandedstatisticobject.Inthefollowingscreenshot,youcanseethatwedealwithvideodata,wehaveadelayof33milliseconds,andtheframesizeis640x480.Moreserviceinformationispresentinthefollowingscreenshot:

Let’sseeonemoreexamplescreenshot.Inthefollowingscreenshot,wecanseethatthe

usedvideocodecisVP8,thevideoframesizeis640x480,andaround13megabytesofvideodatahavebeensentthroughthismediachannel:

ThegetStatsWebRTCAPIfunctioncanbeveryusefulnotonlyfordebuggingpurposes.Thisfunctioncanbehelpfulformanyusecases,forexample:

Monitoring:Inthisusecase,ifyouhaveyourwebservicerunning,youprobablywanttomonitoritsstatedynamically,toknowhowwelltheresourcesareutilizedandsoonTests:Forthisusecase,ifyou’reworkingonsomefeatureorjustimplementingsomenewfunctionalityinyourapplication,statisticsAPIcanbehelpfulwithA/BtestingTroubleshooting:Inthisusecase,ifyourapplicationdoesn’tworkbysomereasonforacustomer,youcanusethismechanismtotracktheissueandfindtherootcause

CheckingestimatedbandwidthWejustconsideredacommoncaseofusingWebRTCstatisticsAPI.Nowwewillconsiderapracticalexampleofusingthismechanism.Inparticular,wewilltrytoknowourestimatedbandwidthforthevideochannelusedinourapplication.

Thefollowingfunctioncollectsstatisticaldatarelatedtothebandwidthutilizationandprintsasimplereportontheconsole:

functionprintStats(peer){

ThemyGetStatsfunctionisdescribedasfollowsandcanbefoundintheHowtodoit…sectionofthisrecipe:

myGetStats(peer,function(results){

for(vari=0;i<results.length;++i){

varres=results[i];

Checkifwehaveavideoobject:

if(res.googCodecName=='VP8'){

if(!window.prevBytesSent)window.prevBytesSent=

res.bytesSent;

GetthebytesSentvalueasfollows:

varbytes=res.bytesSent-window.prevBytesSent;

window.prevBytesSent=res.bytesSent;

Nowconvertthevalueintokilobytes:

varkilobytes=bytes/1024;

console.log(kilobytes.toFixed(1)+'kilobytesper

second');

}

}

setTimeout(function(){

printStats(peer);

},1000);

});

}

Wehavesetthetimeoutvalueto1,000milliseconds.ThuseverysecondthisfunctiongetsstatisticsusingWebRTCAPI,extractsthesentbytesvaluefromtheappropriateobject,andcalculatesthebitrate.Thefollowingscreenshotdepictswhatyoushouldseeinthebrowser’sconsole:

ThefollowingsectionrepresentsonemoreusecasethatyoumightfacewhiledevelopinganapplicationoraserviceusingWebRTCfeatures.

CheckingpacketlossInthissection,wewillconsideranotherusecase:checkingpacketloss.ThisisanexampletakenfromtheWebRTCstandarddraft,abitadaptedtoourcodebase.Inthescenario,theuserisexperiencingbadsound,andtheapplicationwantstodeterminewhetherpacketlosscausesthisissuewiththefollowingsteps:

1. Firstofall,let’sdeclarethevariableswherewewillstorebaselinevaluesandcurrentvalue:

varbaselineReport,currentReport;

2. Next,writeinitializationfunction—itwillmakefirstcalltostatisticsAPIandstorethefirstvalueasbaseline:

functioninitStats(peer){

myGetStats(peer,function(report){

baselineReport=report;

});

3. Now,usingtimer,wewillgetstatisticseveryonesecondandprocessit:

setTimeout(function(){

myGetStats(peer,function(report){

currentReport=report;

processStats();

});

},1000);}

4. Thefollowingfunctiondoesalltheprocessingwork:

functionprocessStats(){

//comparetheelementsfromthecurrentreportwiththebaseline

foreach(varnowincurrentReport){

if(now.type!="outbund-rtp")continue;

//getthecorrespondingstatsfromthebaselinereport

base=baselineReport[now.id];

if(base){

remoteNow=currentReport[now.remoteId];

remoteBase=baselineReport[base.remoteId];

varpacketsSent=now.packetsSent-base.packetsSent;

varpacketsReceived=remoteNow.packetsReceived-

remoteBase.packetsReceived;

//iffractionLostis>0.3,wehaveprobablyfoundthe

culprit

varfractionLost=(packetsSent-packetsReceived)/

packetsSent;

if(fractionLost>0.3){console.log("fractionLostistoo

big:"+fractionLost);}

}

}

}

5. Now,thefollowingcoderepresentshowallthatwejusthavewrittencanbeusedintheapplication:

varonRemoteStreamAdded=function(event){

clog("Remotestreamadded.");

attachMediaStream(remoteVideo,event.stream);

remoteStream=event.stream;

initStats(pc);

};

Here,wewillcalltheiniStatsfunction.ThisfunctionwillgetthefirstdatafromthestatisticsAPI;storeitinthememory,andsetupatimeforonesecond.Then,everysecondanotherfunctionwillbecalled—itwillgetthenextstatisticssampleanddocalculationstryingtodetermineifsomethingiswrongwiththepacketlossvalue.

Howitworks…ThewebbrowsercollectsandmaintainsasetofstatisticdatathatcanbeaccessedviaWebRTCAPI.Whenaccessingthisdata,youshoulduseaselector—somethingthatdeterminesthekindofdatayouwanttoretrieve.

Theselectormight,forexample,beaMediaStreamTrackobject.Inthiscase,thevalidselectormustbeamemberofaMediaStreamobjectthatissentorreceivedbythePeerConnectionobject,forwhichstatisticsisrequested.

NoteUsingtheselectorandcallingthegetStatsfunction,youwillgetstatisticsdatapackedinaJavaScriptobject.Thenyouneedtoparseitandgetthenecessaryvalue.MostWebRTCAPIfunctionsallowyoutosetupanerrorfunctioncallback.Thisfunctionwillbecalledifsomethinggoeswrong;usuallysuchcallbackfunctionsservetoprinterrormessagesinaconsole.Usingtheseerrorcallbacksismandatory.Evenifyoudon’tpasstheerrorcallbackandeverythingworkswell,thesituationmightchangewiththenextbrowserupdate,andyourapplicationwillthrowanexception.Thereforedon’tmisstheerrorcallbacks!

There’smore…Formoredetails,refertoWebRTCstandarddraftathttp://dev.w3.org/2011/webrtc/editor/webrtc.html,whereyoucanfindmoreinformationregardingthispartofAPI.Thestandardisinthedraftstageyet,sosome(ormany)conceptsmightbechanged.

SeealsoTakealookattheDebuggingwithChromerecipe.Chromehasasetofbuilt-inWebRTC-relatedtoolsthatmightbehelpfulwhendevelopinganddebuggingWebRTCapplications.

DebuggingwithChromeChromeisawebbrowserdevelopedbyGoogle—thecompanythatinvestsinWebRTCdevelopmentveryintensively.ChromeusuallyhasthemostadvancedsupportofWebRTCfeaturesthanotherbrowsers,andnewandexperimentalfeaturesusuallyappearfirstinChrome.

Thus,itisnotsurprisingthatChromehasgoodtoolsfordebuggingtheWebRTCstack.Someoftherelevantdetailswillbecoveredinthisrecipe.

GettingreadyForthisrecipe,youwillneedChromeinstalled.Itisamultiplatform,soyoucandownloadtherelevantinstallationpackfromitshomepageathttps://www.google.com/chrome/browser/.

Howtodoit…TherearetwoknownChromemechanismsthatcanbeusefulfordebuggingWebRTCapplications:

WebRTC-internalsLogging

Inmostcases,youprobablywillusethefirstone.

Usingwebrtc-internalsWebRTC-internalsisabuilt-inmechanisminChromewiththeuseofwhichyoucangetaccesstoavarietyofWebRTCstack-relatedinformationandstatisticsdata.

OpenaChromewebbrowserandgototheURLchrome://webrtc-internals/.

Ifyouhaven’topenedanyWebRTCapplicationyet,youwillnotseeanythinginteresting.Nowinthenewtab,openawebpageofawebapplicationwhereaWebRTCAPIisutilized,andrefreshthepagethathasopenedweb-internals.Youwillseesomethingsimilartowhatisdepictedinthefollowingscreenshot:

Hereyoucanseethescreenshotofarealapplication;itsURLispresentatthetopofthewindow.Inthebrackets,youcanseethelistofSTUN/TURNserversthatthewebbrowser

usesforestablishingpeer-to-peerconnection.There,alsoshownaretheoptionalparametersthatarespecifiedwhilecreatingthatpeerconnection,forexample,theDtlsSrtpKeyAgreementoption.

Belowthelistthereareseverallineswithhorizontalarrowsthatcanbeexpanded,andthereyouwillfindadditionaldetailsregardingtheapplicationandWebRTCstack.Thereisnotmuchinformationthatcanbedisplayedbecauseatthisstagethedirectpeer-to-peerconnectionisnotestablishedyet.

Thefollowingscreenshotdepictsthenextstagerightafterestablishingthepeer-to-peerconnection:

Hereyoucanseemorelines;eachofthemrepresentsdatarelatedtosomeobjectorevent.Thefollowingscreenshotshowsanexampleofwhatkindofdatayoucanfindwhileexpandingtheselines:

YoucanseethatI’veexpandedthesetRemoteDescriptionlistitem,andtherearedetailsthathaveappearedforthisobject:thisisanSDPmessageofthetypeoffer.Youcanalsoseerelevantinformationaboutthecandidates,codecs,andIPaddressesofthisitem.

Inthenextscreenshot,youcanfindevenmoreexamplesofdifferentkindsofitemsthatcanbeaccessibleviathispage:

Nowherearetheaudioandvideoconnectionobjectsavailableandmanyotherserviceitemsthatarenotobvious.Let’sseewhatisundertheaudioconnectioniteminthefollowingscreenshot:

HereweexpandedtheConn-audioobjectthatrepresentstheaudioconnection.Youcanseethebytesthatweresentandreceived,IPaddressesofpeers(Iwasrunningthisexampleonmynotebooklocally,sobothIPaddressesareidentical),transportprotocoltype,andotheroptions.

Youwillseethesamekindofinformationwhileexpandingthevideoconnectionitem,soIwillskipthescreenshotforthisone.Insteadofthat,let’sseewhatisonbweforvideo:

Thisitemrepresentsthebandwidth-relateddetails.Hereyoucanfindthebitrateandbandwidthutilizedbythewebbrowserduringthecommunication.

Inthefollowingscreenshot,youcanfindanotherexamplerelatedtovideodata:

Whatisgoodwiththistoolisthatitgivesnotonlynumbersandrawdata,butitalsopresentsgreat-lookinggraphics,whereyoucanvisuallyseewhatishappening.Inthefollowingscreenshot,youcanseethegraphsrelatedtoaudioandvideochannelsutilization:

Nowlet’stakealookatanothergraphicrepresentation—bweforvideo.Itrepresentsvariousnetworkconnectionparametersrelatedtothevideochannel.Ontheleft-handside,youcanfindoptionsthroughwhichyoucanenableordisabletheparametersthatyouwantordon’twanttoseeinthegraphicrepresentation.

Therearemoregraphicrepresentationsavailable—everygraphicrepresentsadynamicalchangeinsomeparameter.

UsingChromeloggingmechanismThisisnotsomethingspecifictoWebRTC,butcanbehelpfulwhiledevelopinganddebuggingWebRTCapplications.Chromecanbestartedwithenablingtheloggingforcertainmodules.Inthiscase,Chromeduringitsworkwillprintavarietyofusefuldetailsintologfiles.

ThefollowingcommandstartsChromewithenabledlogging:

chrome--enable-logging--v=4--vmodule=*libjingle/source/talk/*=4--

vmodule=*media/audio/*=4

Now,Chromewillputadditionaldetailsintothechrome_debug.logfilethatcanbefoundinChrome’suserdatafolder.Thelogfileisaplaintextfile,soyoucanreaditwithoutusingspecialtools.

TipOnsomesystems,thislogfilemightbedirectlywrittenintotheterminal.

AlthoughweareworkingonthelogfileunderWindows,youcanuseconvenienttoolssuchasSawbuck.Youcanfinditshomepageathttps://code.google.com/p/sawbuck/.

SawbuckisalogfilesviewerthatcanbeusednotonlyforChromelogs,butalsoforworkingwithlogsofotherapplications(usingplugins).Youcanseewhatthistoollookslikeinthefollowingscreenshot(takenfromthetool’shomepage):

Howitworks…Welearnedthebuilt-inmechanismavailableinChromethatcanhelpdebuggingandprofilingwhiledevelopingWebRTCapplications.Chromecollectsusefuldata,andusingloggingandthewebrtc-internalstool,youcanaccessthesedata.Moreover,byaccessinggraphs,youcananalyzetheprocessinadynamicmanner.

Tousethistool,youdon’tneedtoinstallanyadditionalsoftware.Thismakesitirreplaceableintheapplicationdevelopmentprocess.

There’smore…YoucanfindmoredetailsspecifictoChromebyloggingontheappropriatewebpageoftheChromiumprojectathttp://www.chromium.org/for-testers/enable-logging.

SeealsoForserver-sidedebuggingadvices,pleaserefertotheDebuggingTURNrecipe

DebuggingTURNAsyouprobablyknow,yourapplicationwilldefinitelyuseSTUNifyouwantittoworkintherealworld.UsingSTUNwillbeenoughformostcases,althoughyouwillhavetouseTURNinmanysituations—especiallywhenworkingwithenterprisecustomers,becausetheyusuallyhaveverystrictnetworkfirewallpoliciesandcomplexnetworkconfigurations.UsingTURNcanbetheonlyavailablesolutionforcustomerslocatedinsomeplaces,forexample,somecountriesmighthavespecificnetworkaccesslimitationsthatcauseissuesfornetworkapplicationsthatareWebRTC-based.

Sointhisrecipe,wewillcoverhowtodebugTURN.

GettingreadyForthisrecipe,youneedtohaveyourownTURNserverinstalledandrunning.WhenyouuseaTURNserverasathird-partyservice,youcandebugonlyclientside.However,ifyouuseyourownTURNserver,youhaveaccesstoitandcandomoreinthescopeofdebugging.Sointhisrecipe,wewillconsiderdebuggingaTURNserverthatyouhavedirectaccessto.

Howtodoit…InChapter3,IntegratingWebRTC,weconsideredtheinstallationandconfigurationofourownTURNserver.TodebugTURN,settheverbosityleveltomaximumandruntheTURNserverinconsole.ThenstartyourWebRTCapplicationusingtheTURNserver—whentheapplicationwillcontacttheserver,youwillseedebugmessagesontheconsoledisplaywheretheserverisrunning.Thefollowingrepresentsthekindsofmessagesyoumightseeintheconsole:

129:session128000000000000001:new,username=<user1:alpha>,lifetime=3600

129:session128000000000000001:user<user1:alpha>:incomingpacket

ALLOCATEprocessed,success

129:handle_udp_packet:NewUDPendpoint:localaddr176.58.121.75:3478,

remoteaddr89.209.127.164:50186

130:session128000000000000007:user<>:incomingpacketBINDING

processed,success

130:session128000000000000009:user<>:incomingpacketmessage

processed,error401

131:session128000000000000009:new,username=<user2:beta>,lifetime=600

131:session128000000000000009:user<user2:beta>:incomingpacket

ALLOCATEprocessed,success

131:handle_udp_packet:NewUDPendpoint:localaddr176.58.121.75:3478,

remoteaddr89.209.127.164:52914

131:session128000000000000010:user<>:incomingpacketmessage

processed,error401

Inthisdump,youwillseeafragmentofTURNauthenticationstagewheretwoclientsaretryingtogetauthenticated.Session129representstheclientuser1withthealphapassword,andsession131representsthecustomeruser2withthebetapassword.Youcanalsoseesession130,whichrepresentsaSTUNclient—itdoesn’tuseTURNfunctionality,soyoudon’tseeanyusernamesorpasswordsfromthisclient.

Nowifyou’veconfiguredtheTURNserverwithdefaultconsoleoptions,youcanconnecttotheTURNconsoleandgetmorespecificdetailsonthecertainsession.ConnecttotheTURNconsole:

telnetlocalhost5766

Afteryou’veconnected,itwillshowyousomethinglikethefollowing:

Connectedtolocalhost.

Escapecharacteris'^]'.

TURNServer

rfc5766-turn-server

Citrix-3.2.2.910'MarshalWest'

Type'?'forhelp

Intheconsoleyouhaveasetofcommands—using?orhelpyoucanaskthesystemtoshowthewholelistofavailablecommandsandoptions.Thecommandwe’reinterestedinisps—itshowsdetailedinformationabouttheavailableTURN/STUNsessions.

>ps

7)id=128000000000000004,user<user1:alpha>:

started78secsago

expiringin3522secs

clientprotocolUDP,relayprotocolUDP

clientaddrx.x.x.x:58454,serveraddry.y.y.y:3478

relayaddrx.x.x.x:63599

fingerprintsenforced:ON

mobile:OFF

SHA256:OFF

SHAtype:SHA1

usage:rp=2,rb=172,sp=1,sb=120

rate:r=0,s=0,total=0(bytespersec)

8)id=128000000000000010,user<user2:beta>:

started76secsago

expiringin524secs

clientprotocolUDP,relayprotocolUDP

clientaddrx.x.x.x:52914,serveraddry.y.y.y:3478

relayaddrx.x.x.x:50796

fingerprintsenforced:OFF

mobile:OFF

SHA256:OFF

SHAtype:SHA1

usage:rp=2,rb=140,sp=1,sb=120

rate:r=0,s=0,total=0(bytespersec)

Totalsessions:8

Fromthislistingwecanseethatintotalthereareeightsessionsontheserver.Inthisprecedingfragment,weseedetailsoncertaintwosessions.Weknowtheusernames(user1anduser2),passwords,IPaddresses,timeofexpiration,timeofliving,andsomemoredetailsofeachsession.

UsingtheTURNconsole,youcancheckwhethersomeproblematicclienthasconnectedtotheserversuccessfullyorhasanyissues.Youcancheckwhichusernamesorpasswordshavebeenusedforeachsession.Youcanalsoknowabouttheusedprotocolsandencryptiondetails.AnalyzingsuchkindsofinformationcanhelpintroubleshootingtheTURN/STUNcommunicationprocess.

Howitworks…HavingdirectaccesstotheTURNserver,youcanuseitsconsoletogetmorecertaindataandanalyzewhat’sgoingon.Usingsuchamethod,youcandebugyourapplicationthatisusingTURN.

There’smore…Inthisrecipe,weconsideredacertainwaytoimplementaTURNserver,usingrfc5766-turn-serversoftware.Ifyouusesomeothersoftware,itmightbesuppliedwithsomeotherspecifictoolsfordebugginganddiagnostic.

SeealsoWhenyouhavenodirectaccesstotheTURNserver,youcanuseanetworksniffertocapturenetworkpacketsandanalyzethesituationfromthatside.Tolearnthistechnique,pleaserefertotheDebuggingusingWiresharkrecipe.ToconfigureandinstallaTURNserver,refertoChapter3,IntegratingWebRTC.

DebuggingusingWiresharkWebRTCapplicationsusenetworksveryintensively.Thussometimesyoumightneedtodebugnotjusttheapplication,butalsoitscommunicationwithothercomponentsofthewholesystem.

Inthissection,wewillcovertheprocessofdebuggingWebRTCapplicationsusingnetworksniffer.

Networksnifferisatoolforcapturingnetworkpackets.Usually,suchtoolscanhelpyoutoanalyzecaptureddata.Usingsniffer,youcanseeandunderstandhowyourapplicationcommunicateswithotherpoints.

GettingreadyForourrecipe,wewilluseWireshark—whichisafreeandmultiplatformnetworksniffersoftware.Downloaditfromthehomepageathttp://www.wireshark.org.

Thistoolisveryuser-friendlyandworksonmostpopularplatforms,soyoudon’tneedanyspecificpreparations.

YouwillalsoneedsomeWebRTCapplication;youcanuseanysimplehelloworldapplicationforthispurpose.

Howtodoit…StartWireshark.YouwillseeaUIthatmightlookconfusingatthefirsttime.Thistoolisverypowerfulandhasmanyfeatures,butforthistask,wewillusebasicfunctionality.PerformthefollowingstepstouseWireshark:

1. ClickontheCapturebutton—Wiresharkwillbegincapturingdatanetworkframes.2. StartyourWebRTCapplicationandnavigateChromebrowsertotheapplication’s

mainwebpage.3. Navigatetotheapplication’swebpageusinganotherbrowserandmakeacalltothe

firstpeer.4. WaituntiltheWebRTCsessionbeginsandclickontheStopbuttoninthe

Wireshark’sUI.

Nowlet’sseewhatwecangetfromthecollecteddata.Inthefollowingscreenshots,youcanseetheexamplesfrommymachine.

Inthefirstscreenshot,youcanseeasetofnetworkpacketsthataresentbetweenpeers(mynotebookandanotherworkmachine).TheselectedlinepointstoaSTUNbindingsuccessresponsewithfollowingdecodedfields:

Afterthat,peerstrytoestablishsecuredirectconnection,andyoucanseethisstageinthefollowingscreenshot:

Anotherexampleofcommunicationthroughsecuredchannelisdepictedinthefollowingscreenshot.Hereyoucanseetheapplication’sdataexchangingstage.

ThefollowingscreenshotdepictstheTURNauthenticationstage.Youcanseethattheserverrepliedwith401unauthorizedrequest;thisisnormalstepatthisstageanditjustmeansthattheserverwillnotserveforanonymousclient.Aftergettingthisserver’s

response,theclientwillcontinuethecommunicationprocessandwillsendcredentialstotheserver.

Usinganetworksniffer,suchasWireshark,canbeveryusefulandhelpfulinthedebuggingprocess.Youneedtocapturenetworkpacketsduringacertainstageoftheapplication’scommunication,andafterthat,youcananalyzethecommunicationprocesstounderstandwhat’swrong.

Howitworks…Anetworksnifferallowsyoutocapturenecessarynetworkpacketsthatarebeingsentbetweenpeersandservers.Byanalyzingthesepackets,wecanunderstandwhat’sgoingoninthecommunicationchannelsandfixtheissues.

There’smore…Thereareothernetwork-relatedtoolsthatmightbehelpfulforsuchkindoftask:

tcpdump:ThisisaconsolenetworksnifferstandardforUNIX-likesystemsmtr:Thisisanetworktoolthatcanbeusefulwhenyouneedtoanalyzeanetworkpathofthedatathatissentbetweenpeers

SeealsoWhendebuggingnetwork-relatedissues,usingthewebrtc-internalsmechanismmightalsobeuseful.RefertotheDebuggingwithChromerecipeforthedetails.RegardingtheprocessofdebuggingTURNservers,youcanrefertotheDebuggingTURNrecipe.

Chapter5.WorkingwithFiltersInthischapter,wewillcoverthefollowingtopics:

WorkingwithcolorsandgrayscaleWorkingwithbrightnessWorkingwithcontrastWorkingwithsaturationWorkingwithhueUsingthesepiafilterUsingtheopacityfilterInvertingcolorsImplementingtheblureffectImplementingthedroppedshadoweffectCombiningfiltersCustomvideoprocessing

IntroductionWiththeintroductionoftheHTML5standard,wehavegotnewpowerfulfeatures.OneoftheinterestingonesisaCSSfilter.Usingthisfeature,youcancontrolavarietyofanimage’sproperties.Youcanprocessastaticimageorvideoimageonthefly.

InthescopeofWebRTC,usageoffiltersenablesyoutoimplementnewfeaturesinyourapplication;itcancontrolvideoimages,makeitbrighterorlesscontrast,andapplysomespecifickindsoffilters.

Inthissection,wewillcoverusingofimageprocessing,implementingseveralpracticalsolutionsandutilizingvideofilters.Youwillseebeforeandaftercasespresentedinthescreenshots.

TipThisfeatureisnotsupportedbyallwebbrowsers—useChromebrowserwhiletestingtheprovidedexamples.

TheworkonHTML5andWebRTCstandardsisnotfinishedyet,sothereisachancethatcertainplacesinthecodemightneedtobechangedinfuture.Notethatthesefilterscanonlybeappliedlocally.Thismeansthatduringavideoconference,ifyouapplyafiltertothevideofromyourwebcamera,youwillseethechangeslocallyinyourbrowser—butyourpeerwon’tseethesechanges.Itwillseetheoriginalvideotranslatedfromyourwebcamera.Ontheotherside,youcanapplythesefilterstotheremotevideoofyourpeerthatisshowninyourwebbrowser.

Youcanfindthesourcecodesofthedemoapplicationsuppliedwiththisbook.

WorkingwithcolorsandgrayscaleThisrecipeshowshowtoworkwithafilterthatdealswiththecolorsoftheprocessedvideo.Wewillmakeavideolesscolorizedandthenmakeitblackandwhite.Thisrecipecanbeusedasakindofsimplespecialeffectforavideo.

Howtodoit…Performthefollowingsteps:

1. Addthecontrolbuttontothemainwebpageofyourapplication:

<buttononclick="doGrayScale()">dograyscale</button>

2. AddanappropriateJavaScriptfunction:

functiondoGrayScale(){

varv=document.getElementById("localVideo");

v.style.webkitFilter="grayscale(50%)";

};

Here,localVideoistheIDpropertyoftheHTMLvideotagforthelocalvideoplayback.

3. Navigateyourbrowsertothewebpage.Youwillfirstseeanunprocessedvideofromthewebcamera.Thefollowingscreenshotdepictssuchasituation:

4. Nowclickonthedograyscalebutton—youwillseethattheimagehasbecomelesscolorized,asshowninthefollowingscreenshot:

Thishappenedbecauseweappliedthegrayscalefilterwithavalueof50%.Inotherwords,weremoved50percentofcolorsfromthevideo.

5. Noweditthecodeandput100%intothefilter’svalue,reloadthewebpage,andclickonthedograyscalebuttonagain—youwillseethatvideobecomesblackandwhite.

Howitworks…Whenyouclickonthedograyscalebutton,theJavaScriptfunctionfromthesecondstepoftheHowtodoit…sectioniscalled.Thisfunctionappliesthegrayscalefilterwiththeappropriatevaluetothevideoobject—usingitsstyleHTMLproperty.Fromnowon,thewebbrowserwillshowthisvideoapplyingthefilteronthefly.

WorkingwithbrightnessThisrecipeshowshowtochangethebrightnessofavideousingtheHTML5filter.Ifyoudevelopavideoapplication,it’susuallyagoodideatogivesomecontrolonthevideotocustomers,allowingthemtochangethecontrast,brightness,andotherparametersofthevideo.

Howtodoit…Followthegivensteps:

1. Addthefollowingcontrolelementtothemainwebpageofyourapplication—usingthisobjectwewillchangethebrightness:

Brightness

<inputtype="range"oninput="changeBrightness(this.valueAsNumber);"

value="0"step="0.1"min="0"max="10">

2. AddtheappropriateJavaScriptfunction:

functionchangeBrightness(val){

varv=document.getElementById("localVideo");

v.style.webkitFilter="brightness("+val+")";

};

3. Here,localVideoistheIDpropertyoftheHTMLvideotagforthelocalvideoplayback.Navigateyourwebbrowsertothewebpage.Youwillfirstseeanunprocessedvideofromthewebcamera.Thefollowingscreenshotdepictssuchasituation:

4. Ontheleft-handsideofthepage,youcanseeacontroldescribedasBrightness.Trytomoveitalittletotheright—youwillseethatthevideoisbecomingbrighter.InthefollowingscreenshotImovedthecontroltoomuchtotherightandtheimagebecametoobright:

5. Ifyoumoveittoomuchtotheleft,youwilljustseeablackbox.

Howitworks…Whenyoumovethecontrol,theJavaScriptfunctionfromthesecondstepiscalled.Thisfunctionappliesthebrightnessfilterwiththecontrol’svaluetothevideoobject—usingitsstyleHTMLproperty.Fromnowon,thewebbrowserwillshowthisvideoapplyingthefilteronthefly.

WorkingwithcontrastThisrecipeshowshowtocontrolthecontrastfeatureofavideousingtheHTML5filterfeature.Thisisthesecondmostimportantcontrolthatcustomersusuallywanttohavewhenusingvideoapplications.

Howtodoit…Followthegivensteps:

1. Addacontrolelementtothemainwebpageofyourapplication—usingthisobjectwewillchangethecontrast:

Contrast

<inputtype="range"oninput="changeContrast(this.valueAsNumber);"

value="0"step="0.1"min="0"max="10">

2. AddanappropriateJavaScriptfunction:

functionchangeContrast(val){

varv=document.getElementById("localVideo");

v.style.webkitFilter="contrast("+val+")";

};

Here,localVideoistheIDpropertyoftheHTMLvideotagforthelocalvideoplayback.

3. Navigateyourwebbrowsertothewebpage.Youwillfirstseeanunprocessedvideofromthewebcamera.Thefollowingscreenshotdepictssuchasituation:

4. Ontheleft-handsideofthepage,youcanseeacontroldescribedasContrast.Trytomoveittotherightorleft—youwillseethatthevideohasmoreandlesscontrastrespectively.InthefollowingscreenshotImovedthecontroltotherightandincreasedthecontrast:

Ifyoumoveittoomuchtotheleft,youwillseejustalight-graybox.Ifyoumovethecontroltotheright,youwillmaketheimagealmostblack(dependsontheamountoflightatyourplace).

Howitworks…Whenyoumovethecontrol,theJavaScriptfunctionfromthesecondstepiscalled.Thisfunctionappliesthecontrastfilterwiththecontrol’svaluetothevideoobject—usingitsstyleHTMLproperty.Fromnowon,thewebbrowserwillshowthisvideoapplyingthefilteronthefly.

WorkingwithsaturationInthisrecipe,wewillcovertheprocessofcontrollingthesaturationofavideobeingcapturedfromthewebcamerausingWebRTC.Saturationisrarelyusedasacontrolavailabletousers.Althoughforsomekindsofapplicationsitmightbeveryuseful.

Howtodoit…Performthefollowingsteps:

1. Addacontrolelementtoyouapplication’smainwebpage—usingthisobjectwewillchangethesaturation’slevel:

Saturation

<inputtype="range"oninput="changeSaturation(this.valueAsNumber);"

value="0"step="0.1"min="0"max="10">

2. AddanappropriateJavaScriptfunction:

functionchangeSaturation(val){

varv=document.getElementById("localVideo");

v.style.webkitFilter="saturate("+val+")";

};

HerelocalVideoistheIDpropertyoftheHTMLvideotagforthelocalvideoplayback.

3. Navigateyourwebbrowsertothewebpage.Youwillfirstseeanunprocessedvideofromthewebcamerawithnormalsaturation.Thefollowingscreenshotdepictssuchasituation:

4. Ontheleft-handsideofthepage,youcanseeacontroldescribedasSaturation.Trytomoveittotheextremeleft—youwillseethatthevideobecameblackandwhite.Bysmoothlymovingthecontroltotheright,youwilladdsaturation,andthevideowilllookmorenormal.Inthefollowingscreenshot,Imovedthecontroltoomuchto

theright,makingthevideotoosaturated:

Movingthecontroltotherightboundwillmakethevideooversaturated,anditwillbebarelypossibleforustoseewhat’shappeninginthescene.

Howitworks…Whenyoumovethecontrol,theJavaScriptfunctionfromthesecondstepiscalled.Thisfunctionappliesthesaturatefilterusingthecontrol’svalueasthefilter’sparameter.Thefunctionusestheobject’sstyleHTMLproperty.Fromnowon,thewebbrowserwillshowthevideoapplyingthechosenfiltertoitonthefly.

WorkingwithhueInthisrecipe,wewilllearnhowtocontrolthevideo’shue.Usually,youwillnotusethisfilterinyourapplications,although,sometimesitmightbehelpful;forexamplewhenyou’reusingsomekindofspecificvideoequipmentthatmightneedthiswayofprocessingvideo.

Howtodoit…Followthegivensteps:

1. Addacontrolelementtotheapplication’smainwebpage—usingthisobjectwewillchangethevideo’shue:

Hue

<inputtype="range"oninput="changeHue(this.valueAsNumber);"value="0"

step="20"min="0"max="360">

Here,youcanseethatwehavesetthemaxvalueas360—thisisbecausethehue’svalueistiedtodegrees.Inthisuniverse,wehave360degrees,sothemaximumvalueforthisfilterissetto360.

2. AddanappropriateJavaScriptfunction:

functionchangeHue(val){

varv=document.getElementById("localVideo");

v.style.webkitFilter="hue-rotate("+val+"deg)";

};

Wehavealsoaddedthedegpostfixtothefilter’svalue—itmeansdegree.Here,localVideoistheIDpropertyoftheHTMLvideotagforthelocalvideoplayback.

3. Navigateyourwebbrowsertothewebpage.Youwillfirstseeanunprocessedvideofromthewebcamera,withnofilterapplied.Thefollowingscreenshotdepictsthisstage:

4. Ontheleft-handsideofthepage,youcanseeacontroldescribedasHue.Trytomoveittotheleftandright—youwillseethatthevideo’scolorschange.Thisisbecausebymovingthecontrol,youchangetheimage’shue.InthefollowingscreenshotImovedthecontroltotheright,makingtheperson’sfacedarkpink,andtheyellow-blueflagbecamewhite-green:

Youprobablywillusethisfilterrarely.Itcanbeusefulifincaseforsomereasonyouhaveabrokenvideo(fromyourwebcameraorfromthepeer)withabnormalhues.Otherwise,itcanbeappliedjustforfun.

Howitworks…Whenyoumovethecontrol,theJavaScriptfunctionfromthesecondstepiscalled.Thisfunctionappliesthehue-rotatefilterusingthecontrol’svalueasthefilter’sdegree.Thefunctionusestheobject’sstyleHTMLproperty.Fromnowon,thewebbrowserwillshowthevideoapplyingthechosenfiltertoitonthefly.

UsingthesepiafilterThisrecipecoverstheusageofthesepiafiltertoprocessavideocapturedfromaremotepeerorlocalwebcamerausingWebRTC.Thisisapopularfilteroftenusedasaspecialeffectformakingvideoapplicationsmorefriendlyandwarm.

Howtodoit…Thefollowingstepswillshowyouhowtousethesepiafilter:

1. Addacontrolelementtothemainwebpageoftheapplicationyou’redeveloping—usingthisobjectwewillcontrolthevalueoftheappliedSepiafilter:

Sepia

<inputtype="range"oninput="changeSepia(this.valueAsNumber);"

value="0"step="0.1"min="0"max="1">

2. AddanappropriateJavaScriptfunction:

functionchangeSepia(val){

varv=document.getElementById("localVideo");

v.style.webkitFilter="sepia("+val+")";

};

Here,localVideoistheIDpropertyoftheHTMLvideotagforthelocalvideoplayback.

3. Navigateyourwebbrowsertothewebpage.Youwillfirstseearawvideointhewebcamera,withnofilterapplied.Inthefollowingscreenshot,youcanseeanimagewithoutanyappliedfilter:

4. Ontheleft-handsideofthepage,youcanseeacontroldescribedasSepia.Trytomoveittotheleftandright—youwillseethatthevideo’scolorschange.Theleftmostpositionmakestheimagelooknormal(nofilterisapplied).Therightmostpositionappliesthefiltertothemostavailablevalue.Inthefollowingscreenshot,I

movedthecontroltotherightmostendandmadethevideolookasifitwastakenfromanoldmovie:

Howitworks…Whenyoumovethecontrol,theJavaScriptfunctionfromthesecondstepiscalled.Thisfunctionappliesthesepiafiltertothevideoimage.Thefunctionusestheobject’sstyleHTMLproperty.Fromnowon,thewebbrowserwillshowthevideoapplyingthechosenfiltertoitonthefly.

UsingtheopacityfilterInthisrecipe,wewillcoverhowtousetheopacityfilter.Youwillprobablyrarelyuseit,butitcanbeusedforimplementinginterestingfeatures,suchaspictureinpicture.

Howtodoit…Followthesesteps:

1. Addacontrolelementtothemainwebpageofyourapplication—usingthisobjectwewillcontrolthevideo’sopacity:

Opacity

<inputtype="range"oninput="changeOpacity(this.valueAsNumber);"

value="1"step="0.1"min="0"max="1">

2. AddanappropriateJavaScriptfunction:

functionchangeOpacity(val){

varv=document.getElementById("localVideo");

v.style.webkitFilter="opacity("+val+")";

};

HerelocalVideoistheIDpropertyoftheHTMLvideotagforthelocalvideoplayback.

3. Navigateyourwebbrowsertothewebpage.Youwillfirstseeanunprocessedvideofromthewebcamera,withnofilterapplied.Thefollowingscreenshotdepictsthisstage:

4. Ontheleft-handsideofthepage,youcanseeacontroldescribedasOpacity.Trytomoveittotheleftandright—youwillseethatthevideobecomeslessandmoretransparent,respectively.Thetop-rightpositionisthenormalstate,andthetop-leftpositionisthetransparentstate.InthefollowingscreenshotImovedthecontrola

littletotheleft,andyoucanseethatthepersonintheimageisbarelyvisiblebecauseoftheimage’stransparency:

Thisfiltercanalsobeusefulwhenyouoverlapseveralvideos.Anotherutilityofthisfilteristhat,incaseyou’redevelopingamultiuserconference,byusingthisfilterandchangingausers’videotransparency,youcanmarktheparticipantsascurrentlyspeakingoronholdaccordingly.

Howitworks…Whenyoumovethecontrol,theJavaScriptfunctionfromthesecondstepiscalled.Thisfunctionappliestheopacityfiltertothevideousingthecontrol’svalue.Thefunctionusestheobject’sstyleHTMLproperty.Fromnowon,thewebbrowserwillshowthevideoapplyingthechosenfiltertoitonthefly.

InvertingcolorsThisrecipecoverstheprocessofusingaprettysimplefilter:inversionofcolors.Itwillhardlybeusefulforyouinmostnormalcases,butitmightbehelpfulifforsomereasonyourpeersendsyouabrokenvideowithinvertedcolors,oryougetonefromyourwebcamera.Somecamerasmightworkthatwayduetohardwareincompatibilityorduetotheincorrectinstallationofsoftwaredrivers.

Howtodoit…Performthefollowingsteps:

1. Addacontrolbuttontoyourapplication’smainwebpage:

Inversion

<inputtype="range"oninput="invertColors(this.valueAsNumber);"

value="0"step="0.1"min="0"max="1">

2. AddanappropriateJavaScriptfunction:

functioninvertColors(val){

varv=document.getElementById("localVideo");

v.style.webkitFilter="invert("+val+")";

};

HerelocalVideoistheIDpropertyoftheHTMLvideotagforthelocalvideoplayback.

3. Navigateyourbrowsertothewebpage.Youwillfirstseeanunprocessedvideofromthewebcamera.Thefollowingscreenshotdepictsthisstage:

4. OnthetopleftofthewebpageyoucanseetheInversioncontrol.Trytomoveittotheleftandright—youwillseethatthevideoimage’scolorschangeasandwhenyoumovethecontroltotheleftandright.InthefollowingscreenshotImovedthecontrolalmosttotherightmostposition,andtheimagetransformedtocolornegativeoftheoriginalimage:

Howitworks…WhenyouclickontheInversionbutton,theJavaScriptfunctionfromthesecondstepiscalled.Thisfunctionappliestheinvertfilterwiththeappropriatevaluetothevideoobject—usingitsstyleHTMLproperty.Fromnowon,thewebbrowserwillshowthisvideoapplyingthefilteronline.

ImplementingtheblureffectThisrecipedivesintotheimplementationoftheblureffect.Ifyouhaveworkedongraphiceditingcomputersoftware,thenyouarelikelyfamiliarwiththiseffect.

Howtodoit…Thefollowingstepswillhelpyouunderstandhowtoimplementtheblureffect:

1. Addacontrolelementtotheindexwebpageofyourapplication—usingthisobjectwewillcontroltheblureffect:

Blur

<inputtype="range"oninput="doBlur(this.valueAsNumber);"value="0"

step="1"min="0"max="15">

2. AddanappropriateJavaScriptfunction:

functiondoBlur(val){

varv=document.getElementById("localVideo");

v.style.webkitFilter="blur("+val+"px)";

};

Wehaveaddedapxpostfixforthefilter’svalue—thisisbecauseoftheblur’sintensitythatissettinginpixels.Here,localVideoistheIDpropertyoftheHTMLvideotagforthelocalvideoplayback.

3. Navigateyourwebbrowsertothewebpage.Youwillfirstseetheraw,unprocessedvideofromthewebcamera,withnofilterapplied.Thefollowingscreenshotdepictsthisstage:

4. Intheprecedingscreenshot,ontheleft-handsideofthepage,youcanseeaBlurcontrol.Bymovingthiscontroltotheleftandright,youcansettheintensityoftheblurrinessinanimage.Theleftmostpositionmeansthatthereisnoblurandyou

shouldseeanormalimage.InthefollowingscreenshotImovedthecontrolalittletotherightfromthemiddle,andyoucanseethattheimagebecameveryblurry—itisbarelypossibletorecognizethepersoninthevideo:

Thisfiltercanbeusedforindicatingthatyouhavemutedsomeoneonthevideoconference,orforindicatingthattheconferencehasnotstarted.

Howitworks…Whenyoumovethecontrol,theJavaScriptfunctionfromthesecondstepiscalled.Thisfunctionappliestheblurfiltertothevideousingthecontrol’svalue.Thefunctionusestheobject’sstyleHTMLproperty.Fromnowon,thewebbrowserwillshowthevideoapplyingthechosenfilteronthefly.

ImplementingthedroppedshadoweffectInthisrecipe,wewillcovertheprocessofimplementingthedroppedshadoweffect.Thisfiltercanbeusedfordecorationpurposes.AlthoughitutilizesCPUresourcesveryactively,don’tputitoneverypage.

Howtodoit…Followthesesteps:

1. Addacontrolelementtotheappropriatewebpageoftheapplication—usingthisobjectwewillcontrolintensityoftheeffect:

Shadow

<inputtype="range"oninput="doShadow(this.valueAsNumber);"value="0"

step="5"min="0"max="50">

2. AddtheonLoadhandlertoHTML’sbodytagofthewebpage.Byusingthismethod,wewillinitializethedroppedshadoweffect.

<bodyonload="doShadow(0);">

3. AddanappropriateJavaScriptfunction:

functiondoShadow(val){

varv=document.getElementById("localVideo");

v.style.webkitFilter="drop-shadow("+val+"px"+val+"px10px

green)";

};

Wehaveaddedthepxpostfixforthefilter’svalue—thisisbecauseoftheeffect’sintensityissettinginpixels.Also,youcanseethatwehavesettheshadow’swidthto10pixels,andwewanttheshadowtobegreen.

Here,localVideoistheIDpropertyoftheHTMLvideotagforthelocalvideoplayback.

4. Navigateyourwebbrowsertothewebpage.Youshouldseeanormalimagefromyourwebcamera,butthereshouldbeagreenshadowaroundtheimage.Thefollowingscreenshotdepictsthisstage:

5. Ontheleft-handsideofthepageyoucanseetheShadowcontrol.Bymovingthiscontroltotheleftandright,youcancontroltheshadow’sposition.Theleftmostpositionofthecontrolistheinitialpositionoftheshadow—justaroundtheimagewithawidthof10pixels,aswehavesetit.InthefollowingscreenshotImovedthecontrolalittletotherightfromthemiddle,andyoucanseethatthegreenshadowhasalsomovedtothebottomandright:

ThisfiltercanbeusedforadditionalUIdecorationwhiledevelopingWebRTCapplications.Youcaneasilycontroltheshadow’ssize,position,andcolor.

Howitworks…Whenyoumovethecontrol,theJavaScriptfunctionfromthesecondstepiscalled.Thisfunctionappliesthedrop-shadowfiltertothevideousingthecontrol’svalue.Thefunctionusestheobject’sstyleHTMLproperty.Fromnowon,thewebbrowserwillshowthevideoapplyingthechosenfilteronthefly.

CombiningfiltersAllthefiltersdescribedinthischaptercanbecombinedandworktogether.Inthisrecipe,wewillcoverthistopicusingasimplepracticalexample—combiningtwofilters:brightnessandcontrast.

Howtodoit…Followthegivensteps:

1. Addtwocontrolobjectstothepageforeachofthefiltersweplantouse:

Brightness<br>

<inputtype="range"oninput="doFilter('brightness',

this.valueAsNumber);"value="0"step="0.1"min="0"max="10">

<br>

Contrast<br>

<inputtype="range"oninput="doFilter('contrast',this.valueAsNumber);"

value="0"step="0.1"min="0"max="10">

<br>

2. Addaglobalvariablewherewewillstorethevaluesforeachfilter:

varfilters={};

3. AddanappropriateJavaScriptfunctionthatwillbecalledwhenvalueofthecontrols(introducedinthestep1)ischanging:

functiondoFilter(filtername,val){

filters[filtername]=val;

varv=document.getElementById("localVideo");

varf="";

for(varfnameinfilters){

f=""+fname+"("+filters[fname]+")"+f;}

v.style.webkitFilter=f;

};

4. Navigateyourwebbrowsertothewebpage.Youshouldseetheusualimagefromyourwebcameraandtwocontrols:forbrightnessandcontrast.Bymovingthesecontrols,youcanchangethevalueoftheimage’scontrastandbrightness.Changingthevalueofonefilterdoesn’tresetthevalueofanother.Inthefollowingscreenshot,youcanseesuchawebpagewiththedescribedfeature:

Howitworks…InthedoFilterfunction,wegetthenameofacertainfilterasthefilternameparameter.Certainfilternameswegettherefromtheappropriatefilter’scontrol(refertothefirststep).Asthesecondparameterofthefunction,wealsogetcertainfiltervalueswehavetouseapplyingthefilter.

Aftergettingthefilternameandfiltervalueinthefunction,wewillstoretheseparameters(refertothesecondstep)inthefiltersarrayvariable(wewilluseitasanassociativearray).Thenwewillgothroughallthearraykeysandvalues(filternamesandtheirvalues)andwillconstructthestringf,combiningnecessaryfilternamesanditsvalues.Wewilldelimitfiltersbythespacesymbol.

Afterthat,wewillgetthefstringassomethinglikethefollowing:brightness(3)contrast(5)

Wewillusetheconstructedstringtochangethestyleoftheappropriatevideotag.Asaresult,wewillapplytwofiltersinparallel.

Youcancombineasmanyfiltersasyoulike,butyoushouldknowthatsomeofthemcouldberesourcehungry.Ifyourapplicationsetstoomanyfiltersatonetime,itmightcauseissues(thewebbrowsermightstack,forexample).

CustomvideoprocessingUntilnow,weconsideredstandardfiltersonly.Inthisrecipe,wewillcoverthebasiccaseofcustomvideoprocessing.Usingthatapproach,youcanimplementyourownfiltersandprocessingalgorithms.

Howtodoit…Asanexample,wewillimplementthepixelizationeffect.

1. Putacanvasobjectsomewhereontheapplication’swebpage.Thiscanvaswillbeusedforgettingframesfromthevideo.Thevisibilityoptionissettohidden—wedon’twanttoshowthiscanvastotheuser,wewilluseitforourinternal,technicalpurposesonly.

<canvasid="canva"width="384px"height="288px"

style="visibility:hidden;"></canvas>

2. Putanothercanvasobjectonthewebpage.Thiscanvaswillbeusedtoshowtheresultofthevideoprocessing:

<canvasid="fcanva"width="384px"height="288px"></canvas>

3. Addabutton,whichwillenabletheprocessing:

<buttononclick="pixelize(10)">Pixelize</button><br>

4. Implementthepixelizefunction.Thisfunctionactuallyperformsallthevideoprocessing:

varpixelsize=10;

varw=384;

varh=288;

functionpixelize(pixelsize){

cnv.drawImage(lv,0,0,w,h);

for(varx=1;x<w;x+=pixelsize)

{

for(vary=1;y<h;y+=pixelsize)

{

varpxl=cnv.getImageData(x,y,1,1);

fcnv.fillStyle=

"rgb("+pxl.data[0]+","+pxl.data[1]+","+pxl.data[2]+")";

fcnv.fillRect(x,y,x+pixelsize-1,y+pixelsize-1);

}

}

setTimeout(function(){

pixelize(pixelsize);

},0);

}

5. Inthefollowingscreenshot,youcanseehowthefilterworks.Ontheleft-handside,theoriginalvideoisshown,ontheright-handside,youcanseethesamevideoafterapplyingthecustomfilter:

Howitworks…Weusedtwocanvases:one(whichishidden)wasusedtocopyframesfromthevideostreamandgetpixels;thesecondcanvaswasusedtoshowprocessedvideoframes.

Whenthepixelizefunctioniscalledthefirsttime,itcompletesprocessingofthefirstvideoframeandthensetsupatimertobecalledthenexttime.Thus,thebrowsercallsthisfunctionagainandagain.Witheverycall,itgetsanewvideoframe,processesit,andgetsdisplayedusingthesecondcanvasobject.

Thatway,youcanimplementanyvideoframeprocessingalgorithmanduseitasyourcustomvideofilter.

Chapter6.NativeApplicationsInthischapter,wewillcoverthefollowingtopics:

BuildingacustomizedWebRTCdemoforiOSCompilingandrunninganoriginaldemoforiOSCompilingandrunningademoforAndroidBuildinganOpenWebRTClibrary

IntroductionThischapterisfullydedicatedtousingWebRTCtechnologywhiledevelopingnativeapplicationsformobileplatforms.Here,thetermnativeapplicationreferstothekindofsoftwarethatisbeingdevelopedusingnativetoolsandSDKofacertainmobileplatform.

Firstofall,youwilllearnhowtogetandcompileWebRTClibrariesthatcanbeusedfordevelopingnativeapplications.Thereisnoseparatecodeforeverycertainplatform.Basically,thecodebaseisthesameforallavailablemobileplatforms.

Inotherrecipes,wewillbuildandrunWebRTCdemoapplicationsforAndroidandiOS,todemonstratetheuseofWebRTConmobiledevices.

TheBuildingacustomizedWebRTCdemoforiOSrecipecoverscustomizeddemoapplications.TheproblemisthattheWebRTCcodebaseisunderactivedevelopment,andoriginalexampleapplicationsmightnotdemonstrateallavailablefeaturesofthetechnology.Forexample,theoriginaliOSexampledidn’tsupportvideocallsforalongtimeandsupportedaudiocallsonly.Nevertheless,itispossibletobuildanativeiOSapplicationthatsupportsWebRTCvideocalls,andthecustomdemoapplicationdemonstratesthat.

Softwaredevelopmentformobileplatformsisaveryspecificfield.Itisbarelypossibletocoverdevelopmentofanapplicationinjustonechapter.SoIassumethatyouhaveenoughexperienceofdevelopingsoftwareforcertainmobileplatforms,becausethisissomethingthatisoutofthisbook’stopic.Here,wewillonlycoverWebRTCspecificdetailsandskiptherest.

TheflowofbuildinganativeapplicationusingWebRTCmightseemtrickyandnon-trivial.Thefollowingdiagramrepresentsthegeneralcasewiththebasicstepsoftheflow:

Inthischapter,wewillcoverthisflowwithallitssteps.Wewillalsolearnhowwecanmakethisprocesseasierandsimpler.

BuildingacustomizedWebRTCdemoforiOSInthisrecipe,wewilldownloadasimple,preparedWebRTCnativedemoapplicationforiOS,compileit,andrunitonarealdevice.ThisapplicationcanbeusedforvideoconferencecallsviaGoogle’sdemowebsite,https://apprtc.webrtc.org.

Thisdemosoftwareiscustomized,meaningthatWebRTClibrariesareprecompiledandshouldbejustlinkedduringcompilationofthedemoapplication.ItalsocontainssomechangescomparedtotheoriginaldemofromGoogle.

GettingreadyThedemoapplicationissupposedtorunonadevice,notinasimulator.SoyoushouldbepreparedwithaphysicalAppledevice(iPhone,iPad)toworkonthisrecipe.

YoushouldberegisteredontheiOSDeveloperProgrambyAppletobeabletoinstalltheapplicationonyourdevice.Ifyou’renotparticipatinginthisprogram,itisworthconsideringjoining.Fordetails,pleaserefertotheprogram’sofficialwebpageathttp://developer.apple.com.

Inmycase,Iusedthefollowingtools:

iPhone5swithiOS8.0.2.AnotebookwithWindows7installedastheseconddevicetobuildtheWebRTCcommunicationchannel.Inthenotebook,IusedaChromebrowsertorunaWebRTCapplication.Xcode6tocompiletheiOSdemo.ForXcode,youalsoneedtohaveanOSXmachinethatruns.

Howtodoit…PerformthefollowingstepstobuildacustomizedWebRTCdemo:

1. Createanewprojectdirectoryandgotoitasfollows:

mkdir~/dev

cd~/dev

2. Getthesourcecodeusingthefollowingcommand:

gitclonehttps://github.com/fycth/webrtc-ios

3. OpenthedemoprojectinXcode:~/dev/webrtc-ios/ios-example/AppRTCDemo.xcodeproj.

4. ChoosethebuildtargetusingtheXcodemenubynavigatingtoProduct|Destination|iPhone.

5. BuildthedemoapplicationbynavigatingtoProduct|Build.6. ConnectyouriPhonetothemachineandrunthedemobynavigatingtoProduct|

Run.

Afterthelastcommandisexecuted,thedemoapplicationwillbeinstalledonthedeviceandwillstartautomatically;itcantakeacoupleofseconds,sodon’trushtoruntheapplicationmanually.

Inthefollowingscreenshot,youcanseeaniconoftheinstalledAppRTCDemoapplication:

Aftertheapplicationstarts,youwillseeashortmessageandaprompttoenteraroomnumber.Navigateyourbrowseronanothermachinetohttp://apprtc.webrtc.org;youwillseeanimagefromyourcamera.CopytheroomnumberfromtheURLstringandenteritinthedemoapplication.Thefollowingscreenshotrepresentsthisstage:

AfteryouenterthecodeandclickontheApplybutton,theapplicationwilltrytoconnecttothevirtualroom.Itcantakeacoupleofseconds(evenuptooneminuteinmycase),sobepatient.

Whentheconnectionisestablished,youshouldseetheimagefromtheiPhoneinthewebbrowser,andviceversa.ThefollowingscreenshotdepictsascreenshotfrommyiPhoneafterIestablishedaWebRTCconnectionwithanotebook:

Inthescreenshot,youcanseeamanwithaniPhone,fromwhichthisscreenshotwastaken.ThevideoontheiPhoneistranslatedfromthenotebook’scamera.Andthefollowingscreenshotrepresentswhatwasvisibleonthenotebook’sdisplay:

Here,inthesmallimageboxyoucanseethevideotakenfromthenotebook’swebcamera.Inthebigimage,youcanseethevideotranslatedfromtheiPhone.

There’smore…ForthisrecipeIforkedthecodefromanotherprojectonGitHub.Tolearnmore,refertohttps://github.com/gandg/webrtc-ios.

Iintroducedsomechangesintheforkedproject,fixingsomeminorissues.Youcanforkanyoftheseprojectsandtakeitscodeasthebaseofyourownproject.

Youcanalsocheckthisprojectathttps://github.com/pristineio/webrtc-build-scripts.ItisasetofscriptsdevelopedspeciallytofacilitatethecompilationofWebRTClibraries’codeforiOS.IfyoudevelopWebRTC-basedsoftwareforApplemobileOS,thistoolmightbeveryusefulforyou.

BuildingademoprojectforaiOSsimulatorThisdemoprojectusesprecompiledWebRTClibrariesthatarebuilttouseonphysicaldevices.YoushouldrebuildtheselibrariesincaseyouwanttoruntheapplicationunderaniOSsimulator.

1. DownloadandinstallGoogleDeveloperTools:

mkdir~/dev

cd~/dev

gitclone

https://chromium.googlesource.com/chromium/tools/depot_tools.git

exportPATH=`pwd`/depot_tools:"$PATH"

2. Configurethedevelopertools:

gclientconfighttp://webrtc.googlecode.com/svn/trunk

3. InformthetoolsthatwewanttobuildlibrariesforiOS:

echo"target_os=['ios']">>.gclient

4. DownloadtheWebRTCsourcecode.Itcantakeacoupleofminutes;itwilldownloadseveralgigabytesofcode.

gclientsync

5. Configurethebuildtoolasfollows:

exportGYP_DEFINES="build_with_libjingle=1build_with_chromium=0

libjingle_objc=1"

exportGYP_GENERATORS="ninja"

exportGYP_DEFINES="$GYP_DEFINESOS=iostarget_arch=ia32"

exportGYP_GENERATOR_FLAGS="$GYP_GENERATOR_FLAGSoutput_dir=out_sim"

exportGYP_CROSSCOMPILE=1

gclientrunhooks

6. Buildthelibrariesasshowninthefollowingcommandlines:

cd~/dev/trunk

ninja-Cout_sim/DebugiossimAppRTCDemo

Thebuildingprocesscantakesometime.AfterthatyouwillfindcompiledWebRTC

librariesbynavigatingto~/dev/trunk/out-sim/Debug/.

7. Nowyoushouldcopytheselibrariesintotheproject’sios-example/libsfolder,andthenyouwillbeabletobuildtheprojectforiOSsimulator.

SeealsoAnotherrecipe,BuildinganOpenWebRTClibrary,alsomightbeusefulforyouinthescopeofdevelopingWebRTCnativeapplicationsforiOSRefertotheCompilingandrunninganoriginaldemoforiOSrecipefordetailsonhowtoworkwiththeoriginaldemofromGoogle

CompilingandrunninganoriginaldemoforiOSThisrecipecovershowtobuildanoriginalGoogleWebRTCnativedemoapplicationforiOS.TheoriginaldemofromGoogledoesn’thaveanyXcodeprojectfilesusingwhichyoucouldopentheIDEanddothejobwithcomfort.Unfortunately,youwouldhavetouseasetofconsoletoolsandscriptstocompilethisapplication.

GettingreadyInthisrecipe,wewillcovertheprocessofbuildinganapplicationforbothaniOSsimulatorandforaphysicaldevice.SoyoushouldhaveaMacOSXmachinetorunthedemoinasimulator,andyoushouldhaveanApplegadgetifyouwouldliketorunitonaphysicaldevice.

YoushouldalsoberegisteredontheAppleiOSDeveloperProgramtobeabletoinstallyourapplicationonyourdevice.Ifyou’renotparticipatinginthisprogram,itisworthconsideringjoining.Fordetails,refertotheprogram’sofficialwebpageathttp://developer.apple.com.

Inmycase,IusedaMacBookProwithMacOSX10.9.5installedonit.

Howtodoit…Firstofall,weneedtodownloadandbuildtheWebRTCsourcecode.Thedemoapplicationisapartofthiscode,sowewillbuilditwiththerestbyperformingthefollowingsteps:

1. DownloadandinstallGoogleDeveloperTools:

mkdir–p~/dev&&cd~/dev

gitclone

https://chromium.googlesource.com/chromium/tools/depot_tools.git

exportPATH=`pwd`/depot_tools:"$PATH"

2. Configurethedevelopertools:

gclientconfighttp://webrtc.googlecode.com/svn/trunk

3. InformthetoolsthatwewanttobuildlibrariesforiOS:

echo"target_os=['ios','mac']">>.gclient

4. DownloadtheWebRTCsourcecode.Itcantakeacoupleofminutes;itwilldownloadseveralgigabytesofcode:

gclientsync

BuildingademoprojectforaniOSdeviceThefollowingstepsshouldbetakenifyou’rebuildingademotorunonaphysicalAppledevice.IfyouwanttorunthedemoonaniOSsimulator,skipthissectionandcontinuetothenextone:

1. Configurethebuildtoolasfollows:

exportGYP_DEFINES="build_with_libjingle=1build_with_chromium=0

libjingle_objc=1"

exportGYP_GENERATORS="ninja"

exportGYP_DEFINES="$GYP_DEFINESOS=iostarget_arch=armv7"

exportGYP_GENERATOR_FLAGS="$GYP_GENERATOR_FLAGSoutput_dir=out_ios"

exportGYP_CROSSCOMPILE=1

2. Preparethebuildscripts:

gclientrunhooks

3. Buildthedemoapplication:

cd~/dev/trunk

ninja-Cout_ios/Debug-iphoneosAppRTCDemo

BuildingademoprojectforaniOSsimulatorThissectiondescribesthestepsthatshouldbetakenifyouwanttocompiletheapplicationforaniOSsimulator.Ifyouwanttoruntheapplicationonaphysicaldevice,findthe

relevantstepsprovidedintheprevioussection:

1. Configurethebuildtoolasfollows:

exportGYP_DEFINES="build_with_libjingle=1build_with_chromium=0

libjingle_objc=1"

exportGYP_GENERATORS="ninja"

exportGYP_DEFINES="$GYP_DEFINESOS=iostarget_arch=ia32"

exportGYP_GENERATOR_FLAGS="$GYP_GENERATOR_FLAGSoutput_dir=out_sim"

exportGYP_CROSSCOMPILE=1

2. Preparebuildscripts:

gclientrunhooks

3. Buildademoapplication:

cd~/dev/trunk

ninja-Cout_sim/DebugiossimAppRTCDemo

4. StarttheapplicationinaniOSsimulator:

~/dev/trunk/out_sim/Debug/AppRTCDemo.app

There’smore…TheoriginalcodefromGoogledoesn’thaveanyIDEprojectfilessoyouhavetodealwithconsolescriptsthroughallthedevelopmentprocess.Thiscanbeeasierifyouusesomethird-partytoolsthatsimplifythebuildingprocess.Suchkindsoftoolscanbefoundathttp://tech.pristine.io/build-ios-apprtc/.

SeealsoItisalsoworthtakingalookattheBuildingacustomizedWebRTCdemoforiOSrecipe.Inthisrecipewecovertheprocessofusingaready-to-useXcodesimpleprojectwithprecompiledWebRTCbinaries.

CompilingandrunningademoforAndroidHere,youwilllearnhowtobuildanativedemoWebRTCapplicationforAndroid.Unfortunately,thesupplieddemoapplicationfromGoogledoesn’tcontainanyIDE-specificprojectfiles,soyouwillhavetodealwithconsolescriptsandcommandsduringallthebuildingprocess.

GettingreadyWewillneedtocheckwhetherwehaveallthenecessarylibrariesandpackagesinstalledontheworkmachine.Forthisrecipe,IusedaLinuxbox—Ubuntu14.04.1x64.SoallthecommandsthatmightbespecificforOSwillberelevanttoUbuntu.Nevertheless,usingLinuxisnotmandatoryandyoucantakeWindowsorMacOSX.

TipIfyou’reusingLinux,itshouldbe64-bitbased.Otherwise,youmostlikelywon’tbeabletocompileAndroidcode.

PreparingthesystemFirstofall,youneedtoinstallthenecessarysystempackages:

sudoapt-getinstallgitgit-svnsubversiong++pkg-configgtk+-2.0

libnss3-devlibudev-devantgcc-multiliblib32z1lib32stdc++6

InstallingOracleJDKBydefault,UbuntuissuppliedwithOpenJDK,butitishighlyrecommendedthatyouinstallanOracleJDK.Otherwise,youcanfaceissueswhilebuildingWebRTCapplicationsforAndroid.OneanotherthingthatyoushouldkeepinmindisthatyoushouldprobablyuseOracleJDKversion1.6—otherversions(inparticular,1.7and1.8)mightnotbecompatiblewiththeWebRTCcodebase.Thiswillprobablybefixedinthefuture,butinmycase,onlyOracleJDK1.6wasabletobuildthedemosuccessfully.

1. DownloadtheOracleJDKfromitshomepageathttp://www.oracle.com/technetwork/java/javase/downloads/index.html.

IncasethereisnodownloadlinkonsuchanoldJDK,youcantryanotherURL:http://www.oracle.com/technetwork/java/javasebusiness/downloads/java-archive-downloads-javase6-419409.html.

TipOraclewillprobablyaskyoutosigninorregisterfirst.Youwillbeabletodownloadanythingfromtheirarchive.

2. InstallthedownloadedJDK:

sudomkdir–p/usr/lib/jvm

cd/usr/lib/jvm&&sudo/bin/sh~/jdk-6u45-linux-x64.bin--noregister

Here,IassumethatyoudownloadedtheJDKpackageintothehomedirectory.

3. RegistertheJDKinthesystem:

sudoupdate-alternatives--install/usr/bin/javacjavac

/usr/lib/jvm/jdk1.6.0_45/bin/javac50000

sudoupdate-alternatives--install/usr/bin/javajava

/usr/lib/jvm/jdk1.6.0_45/bin/java50000

sudoupdate-alternatives--configjavac

sudoupdate-alternatives--configjava

cd/usr/lib

sudoln-s/usr/lib/jvm/jdk1.6.0_45java-6-sun

exportJAVA_HOME=/usr/lib/jvm/jdk1.6.0_45/

4. TesttheJavaversion:

java-version

YoushouldseesomethinglikeJavaHotSpotonthescreen—itmeansthatthecorrectJVMisinstalled.

GettingtheWebRTCsourcecodePerformthefollowingstepstogettheWebRTCsourcecode:

1. DownloadandprepareGoogleDeveloperTools:

mkdir–p~/dev&&cd~/dev

gitclone

https://chromium.googlesource.com/chromium/tools/depot_tools.git

exportPATH=`pwd`/depot_tools:"$PATH"

2. DownloadtheWebRTCsourcecode:

gclientconfighttp://webrtc.googlecode.com/svn/trunk

echo"target_os=['android','unix']">>.gclient

gclientsync

Thelastcommandcantakeacoupleofminutes(actually,itdependsonyourInternetconnectionspeed),asyouwillbedownloadingseveralgigabytesofsourcecode.

InstallingAndroidDeveloperToolsTodevelopAndroidapplications,youshouldhaveAndroidDeveloperTools(ADT)installed.ThisSDKcontainsAndroid-specificlibrariesandtoolsthatarenecessarytobuildanddevelopnativesoftwareforAndroid.PerformthefollowingstepstoinstallADT:

1. DownloadADTfromitshomepagehttp://developer.android.com/sdk/index.html#download.

2. UnpackADTtoafolder:

cd~/dev

unzip~/adt-bundle-linux-x86_64-20140702.zip

3. SetuptheANDROID_HOMEenvironmentvariable:

exportANDROID_HOME=`pwd`/adt-bundle-linux-x86_64-20140702/sdk

Howtodoit…Afteryou’vepreparedtheenvironmentandinstalledthenecessarysystemcomponentsandpackages,youcancontinuetobuildthedemoapplication:

1. PrepareAndroid-specificbuilddependencies:

cd~/dev/trunk

source./build/android/envsetup.sh

2. Configurethebuildscripts:

exportGYP_DEFINES="$GYP_DEFINESbuild_with_libjingle=1

build_with_chromium=0libjingle_java=1OS=android"

gclientrunhooks

3. BuildtheWebRTCcodewiththedemoapplication:

ninja-Cout/Debug-j5AppRTCDemo

Afterthelastcommand,youcanfindthecompiledAndroidpacketwiththedemoapplicationat~/dev/trunk/out/Debug/AppRTCDemo-debug.apk.

RunningontheAndroidsimulatorFollowthesestepstorunanapplicationontheAndroidsimulator:

1. RunAndroidSDKmanagerandinstallthenecessaryAndroidcomponents:

$ANDROID_HOME/tools/androidsdk

ChooseatleastAndroid4.x—lowerversionsdon’thaveWebRTCsupport.Inthefollowingscreenshot,I’vechosenAndroidSDK4.4and4.2:

2. CreateanAndroidvirtualdevice:

cd$ANDROID_HOME/tools

./androidavd&

ThelastcommandexecutestheAndroidSDKtooltocreateandmaintainvirtualdevices.Createanewvirtualdeviceusingthistool.Youcanseeanexampleinthefollowingscreenshot:

3. Starttheemulatorusingjustthecreatedvirtualdevice:

./emulator–avdemu1&

Thiscantakeacoupleofseconds(orevenminutes),afterthatyoushouldseeatypicalAndroiddevicehomescreen,likeinthefollowingscreenshot:

4. Checkwhetherthevirtualdeviceissimulatedandrunning:

cd$ANDROID_HOME/platform-tools

./adbdevices

Youshouldseesomethinglikethefollowing:

Listofdevicesattached

emulator-5554device

ThismeansthatyourjustcreatedvirtualdeviceisOKandrunning;sowecanuseittotestourdemoapplication.

5. Installthedemoapplicationonthevirtualdevice:

./adbinstall~/dev/trunk/out/Debug/AppRTCDemo-debug.apk

Youshouldseesomethinglikethefollowing:

636KB/s(2507985bytesin3.848s)

pkg:/data/local/tmp/AppRTCDemo-debug.apk

Success

Thismeansthattheapplicationistransferredtothevirtualdeviceandisreadytobestarted.

6. Switchtothesimulatorwindow;youshouldseethedemoapplication’sicon.ExecuteitlikeitisarealAndroiddevice.Inthefollowingscreenshot,youcanseetheinstalleddemoapplicationAppRTC:

TipWhiletryingtolaunchtheapplication,youmightseeanerrormessagewithaJavaruntimeexceptionreferringtoGLSurfaceView.Inthiscase,youprobablyneedtoswitchtotheUseHostGPUoptionwhilecreatingthevirtualdevicewithAndroidVirtualDevice(AVD)tool.

FixingabugwithGLSurfaceViewSometimesifyou’reusinganAndroidsimulatorwithavirtualdeviceontheARMarchitecture,youcanbefacedwithanissuewhentheapplicationsaysNoconfigchosen,throwsanexception,andexits.

ThisisaknowndefectintheAndroidWebRTCcodeanditsstatuscanbetrackedathttps://code.google.com/p/android/issues/detail?id=43209.

Thefollowingstepscanhelpyoufixthisbugintheoriginaldemoapplication:

1. Gotothe~/dev/trunk/talk/examples/android/src/org/appspot/apprtcfolderandedittheAppRTCDemoActivity.javafile.Lookforthefollowinglineofcode:

vsv=newAppRTCGLView(this,displaySize);

2. Rightafterthisline,addthefollowinglineofcode:

vsv.setEGLConfigChooser(8,8,8,8,16,16);

Youwillneedtorecompiletheapplication:

cd~/dev/trunk

ninja-Cout/DebugAppRTCDemo

3. Nowyoucandeployyourapplicationandtheissuewillnotappearanymore.

RunningonaphysicalAndroiddeviceFordeployingapplicationsonanAndroiddevice,youdon’tneedtohaveanydevelopercertificates(likeinthecaseofiOSdevices).SoifyouhaveanAndroidphysicaldevice,itprobablywouldbeeasiertodebugandrunthedemoapplicationonthedeviceratherthanonthesimulator.

1. ConnecttheAndroiddevicetothemachineusingaUSBcable.2. OntheAndroiddevice,switchtheUSBdebugmodeon.3. Checkwhetheryourmachineseesyourdevice:

cd$ANDROID_HOME/platform-tools

./adbdevices

Ifdeviceisconnectedandthemachineseesit,youshouldseethedevice’snameintheresultprintoftheprecedingcommand:

Listofdevicesattached

QO4721C35410device

4. Deploytheapplicationontothedevice:

cd$ANDROID_HOME/platform-tools

./adb-dinstall~/dev/trunk/out/Debug/AppRTCDemo-debug.apk

Youwillgetthefollowingoutput:

3016KB/s(2508031bytesin0.812s)

pkg:/data/local/tmp/AppRTCDemo-debug.apk

Success

AfterthatyoushouldseetheAppRTCdemoapplication’sicononthedevice.

Afteryouhavestartedtheapplication,youshouldseeaprompttoenteraroomnumber.Atthisstage,gotohttp://apprtc.webrtc.orginyourwebbrowseronanothermachine;you

willseeanimagefromyourcamera.CopytheroomnumberfromtheURLstringandenteritinthedemoapplicationontheAndroiddevice.YourAndroiddeviceandanothermachinewilltrytoestablishapeer-to-peerconnection,andmighttakesometime.Inthefollowingscreenshot,youcanseetheimageonthedesktopaftertheconnectionwithAndroidsmartphonehasbeenestablished:

Here,thebigimagerepresentswhatistranslatedfromthefrontalcameraoftheAndroidsmartphone;thesmallimagedepictstheimagefromthenotebook’swebcamera.Soboththedeviceshaveestablisheddirectconnectionandtranslateaudioandvideotoeachother.

ThefollowingscreenshotrepresentswhatwasseenontheAndroiddevice:

There’smore…Theoriginaldemodoesn’tcontainanyready-to-useIDEprojectfiles;soyouhavetodealwithconsolecommandsandscriptsduringallthedevelopmentprocess.Youcanmakeyourlifeabiteasierifyouusesomethird-partytoolsthatsimplifythebuildingprocess.Suchtoolscanbefoundathttp://tech.pristine.io/build-android-apprtc.

SeealsoIfyouconsiderdevelopingWebRTCapplicationsforiOS,theBuildingacustomizedWebRTCdemoforiOSrecipemightalsobeusefulforyou

BuildinganOpenWebRTClibraryAtthebeginningof2014,EricssonpresenteditsownopensourceimplementationofWebRTCstack—OpenWebRTC.EricssonstatesthatthisproductsupportsiOS,Android,Windows,Linux,andMacOSXplatformsfromthebox.Inthisrecipe,wewillbuildthisnewWebRTCstack.Thisimplementationcameoutjustacoupleofdaysagoandthereisn’taready-to-useexamplesuppliedwithit,sowewillbuildjustthelibrary.

GettingreadyAtthistime,OpenWebRTCbuildscriptssupportLinuxandMacOSXplatformsonly,andthereisnoreadysolutiontobuildOpenWebRTCunderWindows.SoyouneedLinuxorOSXinstalledtoworkonthisrecipe.

Inmycase,IusedaMacBookProwithMacOSX10.9installed.

Howtodoit…PerformthefollowingstepstobuildOpenWebRTC:

1. Getthesourcecodes:

mkdir~/dev&&cd~/dev

gitclonegit@github.com:EricssonResearch/openwebrtc.git--recursive

cdopenwebrtc

2. Configuretheenvironment(thisstepwilltakesometime).Ifyou’reworkingunderLinux,putlinuxinsteadofosxinthecommand:

cdscripts/bootstrap

./bootstrap.sh-rosx

cd-

3. Buildthedependencies.Youcanalsouselinuxandandroidwordsifyou’rebuildingfortheappropriateplatforms.NotethatyouneedAndroidNDKinstalledandconfiguredtobuilddependenciesforthisplatform:

cdscripts/dependencies

./build-all.sh-rosxios

./deploy_deps.sh

cd–

4. BuildOpenWebRTCusingthefollowingcommand:

./build.sh-rosxios

Afterallthesecommandsareexecuted,youwillhaveOpenWebRTClibrariesbuiltandreadytouse.Tofurtherlearnthislibrary,itmightbeworthtakingalookatBowser—anopensourcedwebbrowsercompletelybuiltontheOpenWebRTCstack.

There’smore…Thisnewlibraryisunderactivedevelopmentandevenitsdocumentationactivelychanges.So,formoredetails,pleaserefertothehomepageoftheprojectathttp://www.openwebrtc.io.

AlsotakealookatBowser—anopensourceWebRTC-orientedwebbrowserfromEricsson.ThisbrowsercanrununderbothAndroidandiOS.Itshomepageisathttp://www.openwebrtc.io/bowser/.

Chapter7.Third-partyLibrariesInthischapter,wewillcoverthefollowingtopics:

BuildingavideoconferenceusingSimpleWebRTCCreatinganapplicationusingRTCMultiConnectionDevelopingasimpleWebRTCchatusingPeerJSMakingasimplevideochatwithrtc.ioUsingOpenToktocreateaWebRTCapplicationCreatingamultiuserconferenceusingWebRTCO

IntroductionWhenanewtechnologyoraninstrumentappearsonthemarket,itmightnotbereasonabletocreateyourownframeworkoralibrarybyutilizingthisnewtooltodevelopaproduct.SometimesitisworthlookingaroundandusingaSoftwareDevelopmentKit(SDK)oraready-to-useframeworkthatimplementsallthetechnology’snecessaryfeatures.

WebRTCisaveryyoungtechnologythatisunderactivedevelopment.Wedon’thaveacompletedstandardyet,onlyadraft.Therearemanythird-partyframeworksandlibrariesavailablethatutilizeWebRTCfeaturesandprovideaniceAPIforadeveloper.Tousesuchtools,itisnotnecessarytogetdeepintoWebRTCandstandards,butyoucanconcentratejustonyourproduct.

TipMostoftheframeworksprovideyouwithacompletesetoftools.Therefore,youmightneedtouseGoogle’sadapter.jsinadditiontokeepcompatibilitybetweenmultiplewebbrowsersortheir(browsers’)versions.

Usually,suchanSDKcanmakeadeveloper’slifeeasier—theyoftenprovideadditionalservicessuchassignalingandSTUN/TURNservers.Whenusingagoodthird-partyframework,youoftendon’tneedtotakecareoftheserverinfrastructureandinstallationandmaintenanceofyourownsignalingserver;youcanworkonlyontheclientcode—therestwillbeservedbythechosensolution.

Inthischapter,wewillconsiderafewsuchtools.Youwillfindrecipesthatutilizeatool’sAPItoimplementbasicexamplesofWebRTCapplications.Allexamplesarebasedontheofficialtool’sdocumentationanddemoapplicationsfromtheirhomepages.

TipWebRTCstackisdevelopedwithgreatattentiontosecurity,andthewebbrowsermightnotevenruntheapplicationincaseitisaccessedfromthelocalsystem.Sowhiletestingtheprovidedexamples,placethemonawebserver.Asanalternative,youcanusecloudservicessuchasDropboxforaccessingtheapplicationoverpublicfolder—inthiscase,youshouldchangeallHTTPlinksintheapplicationtoHTTPS.

BuildingavideoconferenceusingSimpleWebRTCSimpleWebRTCisaveryeasy-to-useframeworkwritteninJavaScript.Usingthisproduct,youcanstartyourfirstvideoconferenceinjustoneminute.Inthisrecipe,wewillcovertheprocessofcreatingofabasicWebRTCapplicationusingtheSimpleWebRTCsoftware.

GettingreadyInthisrecipe,wewillcreateasimpleHTMLpagebyutilizingaSimpleWebRTCframework.So,youwillneedatexteditorandaWebRTCcompliantwebbrowser.Ifyou’reusingFirefox,thedemomightbeexecutedfromthelocalfilesystem;ifyou’reusingChrome,youshoulduseawebserver—otherwise,thebrowserwillprohibittherunningoftheapplication.

Howtodoit…Tobuildabasicvideoconferenceusingthistool,youneedtocreatejustoneHTMLwebpage.Youdon’tevenneedtoregisteranaccountinthevendor’ssystem.

1. CreateanemptyHTMLfileandaddthefollowingcode:

<!DOCTYPEhtml>

<html>

<headlang="en">

<metacharset="UTF-8">

2. IncludeaSimpleWebRTCJavaScriptframework:

<scriptsrc="http://simplewebrtc.com/latest.js"></script>

</head>

<body>

3. Createavideoobjectforalocalvideo:

<videoheight="300"id="localVideo"></video>

4. Createavideoobjectforthevideotranslatedfromaremotepeer:

<divid="remotesVideos"></div>

<br>

5. Createabuttonandtieahandlerfunctiontoit.Whenyouclickthebutton,videoconferencewillbecreated:

<buttonid="btn1"onclick="startconf()">Startconference</button>

<scriptlanguage="JavaScript">

6. SetupavariabletohandletheSimpleWebRTCobject:

varwebrtc=null;

Thefollowingfunctioniscalledwhenacustomerclicksthebutton:

functionstartconf(){

7. CreateaSimpleWebRTCobjectwithinitialparameters.WewillsendtheIDsofboththevideoobjects(forlocalandremotevideo);also,wewillasktheframeworktogetmediaaccessimmediately:

webrtc=newSimpleWebRTC({

localVideoEl:'localVideo',

remoteVideosEl:'remotesVideos',

autoRequestMedia:true

});

Thefollowingcodeactuallystartsthevideoconference.Here,wewillalsosetupavirtualroomname,Room86#—youarefreetouseanynameyouwouldliketouse:

webrtc.on('readyToCall',function(){

webrtc.joinRoom('Room86#');

});

};

</script>

</body>

</html>

8. Now,savethisfileinafolderandopenitinyourwebbrowser(inmycase,I’veusedFirefoxforMacOSX).

Howitworks…WhenyouopentheHTMLfileinyourwebbrowser,youwillseeablankpagewithabutton.ClickontheStartconferencebutton—thewebbrowserwillcaptureavideofromyourwebcameraandshowitonthepage(itmayaskyouforaccesspermission).

Inthefollowingscreenshot,youcanseethisstage:

Now,itistimetoconnectanotherpeer.OpenthesameHTMLfileinanotherbrowser.Youcanevencopyittoanothermachineandopenitthere.ThenclickontheStartconferencebutton—afteracoupleofseconds,thepeerconnectionshouldbeestablishedandyoushouldseeboththelocalandremoteimagesoneverybrowserwindow,asshowninthefollowingscreenshot:

Noteyoudon’tneedtoinstallasignalingserver—SimpleWebRTCtakescareofit.WhenyoucallSimpleWebRTC’sJavaScriptAPImethods,itcommunicatestothesignalerserverinstalledontheSimpleWebRTC’sservers.

There’smore…AlthoughweconsideredaverysimpleexampleofusingaSimpleWebRTCframework,thistoolcanbeusedtobuildmorecomplexapplications.Formoredetails,pleaserefertotheofficialdocumentationfortheframeworkathttp://simplewebrtc.com.

CreatinganapplicationusingRTCMultiConnectionThisrecipecoverstheprocessofcreatingasimpleWebRTCapplicationusinganopensourceRTCMultiConnectionframework.ThisisaJavaScript-basedframeworkthatallowsyoutobuildapplicationsandservicesusingmanyWebRTCfeatures,includingexperimentalfeatures.

GettingreadyToworkwiththisframework,wewillbuildabasicWebRTCservicethatsupportsprivatevirtualroomsforvideoconferencing.YouwillneedtowritesomeHTMLandJavaScriptcode,whichdoesnotneedtodevelopanyserver-sideparts.So,havingjustatexteditorandaWebRTCcompliantwebbrowsershouldbeenoughtoworkonthisrecipe.

Howtodoit…TheRTCMultiConnectiontooltakesalloftheworkregardingthesignalingonitsown.Thus,youcanconcentrateontheclientsideandUI.

1. CreateanemptyHTMLfileandaddthefollowingcodeinsideit:

<!DOCTYPEhtml>

<html>

<headlang="en">

<metacharset="UTF-8">

2. IncludetheHTMLstylesuppliedwiththetool.Thisisnotnecessary,andyoucanuseyourownCSS:

<linkrel="stylesheet"href="http://cdn.webrtc-

experiment.com/style.css">

3. Includetheframework’sJavaScriptlibraries:

<scriptsrc="http://cdn.webrtc-experiment.com/firebase.js">

</script>

<scriptsrc="http://cdn.webrtc-

experiment.com/RTCMultiConnection.js">

</script></head>

<body>

<section>

<span>

4. Thefollowinganchorisusedforcreatingvirtualrooms:

<ahref=""target="_blank"title=""><code>

<strongid="unique-token"></strong></code></a></span>

5. Addaninputobjecttohandlethevirtualroomname:

<inputtype="text"id="conference-name">

6. Createanewbuttonelementonthepage.Whenitisclicked,anewconferencewillstart:

<buttonid="setup-new-conference"class="setup">SetupNew

Conference</button>

</section>

<tablestyle="width:100%;"id="rooms-list"></table>

7. Createaseparatedivlayerforthevideoobjects:

<divid="videos-container"></div>

</section>

<script>

8. Createanewconnectionobject.Usingthisobject,wecancontroltheconnectionitself:

varconnection=newRTCMultiConnection();

connection.session={

audio:true,

video:true

};

9. Declareacallbackhandlerthatwillbecalledwhenanewmediastreamisready.Thishandlerwillcreateanewvideoobjectforeverymediastreamandplaceitinthevideocontainerlayer:

connection.onstream=function(e){

e.mediaElement.width=300;

videosContainer.insertBefore(e.mediaElement,

videosContainer.firstChild);

};

10. Createahandlerforthestreamendedevent.Itwillbecalledwhenastreamisstopped(peerconnectionisinterrupted,forexample).Thisfunctionwillremovetheirrelevantvideoobject:

connection.onstreamended=function(e){

e.mediaElement.style.opacity=0;

setTimeout(function(){

if(e.mediaElement.parentNode){

e.mediaElement.parentNode.removeChild(e.mediaElement);

}

},1000);

};

varsessions={};

11. Makeafunctionthatwillbecalledwhenanewvirtualroomiscreated,andsomeoneiswaitingfortheremotepeertojoin:

connection.onNewSession=function(session){

if(sessions[session.sessionid])return;

sessions[session.sessionid]=session;

vartr=document.createElement('tr');

12. Weneedtonotifythecustomerwhenthevirtualroomiscreated.ThefollowingcodeshowssuchanotificationandcreatesaJoinbutton:

tr.innerHTML='<td><strong>'+session.extra['session-name']+

'</strong>isrunningaconference!</td>'+'<td><button

class="join">Join</button></td>';

roomsList.insertBefore(tr,roomsList.firstChild);

varjoinRoomButton=tr.querySelector('.join');

joinRoomButton.setAttribute('data-sessionid',

session.sessionid);

13. CreateanappropriatecodefortheJoinbutton:

joinRoomButton.onclick=function(){

this.disabled=true;

varsessionid=this.getAttribute('data-sessionid');

session=sessions[sessionid];

if(!session)throw'Nosuchsessionexists.';

connection.join(session);

};

};

varvideosContainer=document.getElementById('videos-container')||

document.body;

varroomsList=document.getElementById('rooms-list');

document.getElementById('setup-new-conference').onclick=

function(){

this.disabled=true;

connection.extra={

'session-name':document.getElementById('conference-

name').value||'Anonymous'

};

connection.open();

};

connection.connect();

14. TheuniqueURLtosharethevirtualroomwithothersiscreatedontheclientsideaswell.Thefollowingcoderepresentshowthistaskissolvedintheexample:

(function(){

varuniqueToken=document.getElementById('unique-token');

if(uniqueToken)

if(location.hash.length>2)

uniqueToken.parentNode.parentNode.parentNode.innerHTML='<h2

style="text-align:center;"><ahref="'+location.href+'"

target="_blank">Sharethislink</a></h2>';

elseuniqueToken.innerHTML=

uniqueToken.parentNode.parentNode.href='#'+(Math.random()*new

Date().getTime()).toString(36).toUpperCase().replace(/\./g,'-');

})();

</script>

</body>

</html>

Thatisall.Savethisfileonadisk,andnavigateyourwebbrowsertoit.

Howitworks…WhenyouopentheHTMLfile,youwillseeawebpagesimilartothefollowing:

Now,createanewprivatevirtualroombyclickingontheURLtotheleft(itwillopenanewtabinthebrowserasshowninthefollowingscreenshot).

Inthispage,youshouldenteryournameoraroom’snameintheinputtextbox,andthenclickontheSetupNewConferencebutton.Afterthat,youshouldseetheimagefromyourwebcamera:

Now,copytheSharethislinkURLandopenitonanothermachine,oryoucanopenitinanotherbrowser’stab,likeIdid.YouwillseeabigJoinbuttonliketheoneshowninthefollowingscreenshot:

So,toconnecttotheconference,justclickontheJoinbutton.Rightafterthat,theconferencewilltrytoestablishpeer-to-peerconnection.Ifeverythinggoeswell,everypeershouldseebothlocalandremoteimages.

TipInmycase,Iusedthesamemachine(justseparatebrowserwindows),sotheimagesareidentical.

ThislibraryusesFirebase(https://www.firebase.com)forsignaling,soyoudon’tneedtoinstallandmaintainyourownsignalingserver—RTCMultiConnectionwilltakecareofthat.

There’smore…RTCMultiConnectionallowsyoutocreatemorecomplexapplications,andutilizeadvancedWebRTCfeatures.Here,wetouchedjustthebasicconcepts.

Fordetailsonhowtousethisframework,refertoitsofficialhomepagehttps://www.webrtc-experiment.com/RTCMultiConnection/.

DevelopingasimpleWebRTCchatusingPeerJSInthisrecipe,wewillusethePeerJSWebRTCframeworktocreateasimplewebchatconceptbyutilizingdatachannels.

GettingreadyPeerJSrequiresdeveloperstoregisterbeforetheycanuseitsAPI.Duringtheregistrationprocess(itisfree),adevelopergetsauniqueIDthatcanbeusedtoworkwiththeAPI.Ifyouwouldliketousethisframeworkanddon’tmindregistering,thenvisititshomepageathttp://peerjs.com.

Howtodoit…UsingPeerJSisreallysimple,andabasicexamplecanbeperformedusingjustoneHTMLfile.Inthefollowingsteps,youwillfindsuchanindexfilewithcommentsinalltheimportantplaces:

1. PlacethestandardHTMLheaders:

<!DOCTYPEhtml>

<html>

<headlang="en">

<metacharset="UTF-8">

2. IncludethePeerJSlibrary:

<scriptsrc="http://cdn.peerjs.com/0.3/peer.js"></script>

</head>

<body>

3. Addaninputtextbox.Here,acustomercanenterhis/hernamewhileconnectingtothesystem.Forsimplicity,thesameboxwillbeusedtoenterfurtherchatmessages:

<br><inputtype="text"id="inputbox"/>

4. Createthreebuttonstoconnecttothesystem,tocalltheremotepeer,andtosendmessagestotheremotepeer:

<buttonid="btn_connect"onclick="Connect()">Connect!</button>

<buttonid="btn_call"onclick="CallTo()"disabled="true">Call

To</button>

<buttonid="btn_send"onclick="SendMessage()">Sendmessage</button>

<scriptlanguage="JavaScript">

5. Inthefollowingvariable,youshouldaddyourdeveloperAPIIDyougotfromthePeerJSsystemduringtheregistrationprocess:

varMY_API_ID=YOUR_API_ID;

varpeer=null;

varconn=null;

6. Thefollowingfunctiontakesthecustomer’snameandregistersitinthePeerJSsystem.Afterthat,anotherpeercanconnecttothiscustomerusingitsnameforconnection:

functionConnect(){

varmyname=document.getElementById("inputbox").value;

peer=newPeer(myname,{key:MY_API_ID});

7. Setupacallbackfunctionontheconnectionevent.Thisfunctionwillbecalledwhenaremotepeerestablishesaconnectionwithus.Here,wewillalsosetahelperfunctionthatwillprintthereceivedmessagesfromtheremotepeertothebrowser’sconsole:

peer.on('connection',function(connection){

connection.on('data',function(data){

console.log("Remotepeersaid:"+data);

});

conn=connection;

});

document.getElementById("btn_connect").setAttribute("disabled",

"true");

document.getElementById("btn_call").removeAttribute("disabled");

};

8. Wealsoneedafunctionthatwillcalltheremotepeer.Thefollowingcoderepresentssuchafunction.Ittakesaremotepeer’snamefromtheinputtextboxandcallsPeerJStoestablishtheconnection:

functionCallTo(){

varremotename=document.getElementById("inputbox").value;

conn=peer.connect(remotename);

document.getElementById("btn_call").setAttribute("disabled","true");

};

9. Tosendmessages,weneedanappropriatefunctionresponsibleforthat.Suchafunction,youcanfindinthefollowing:

functionSendMessage(){

varmsg=document.getElementById("inputbox").value;

conn.send(msg);

};

</script>

</body>

</html>

Thatisall.Savethisfileonadisk,andnavigateyourwebbrowsertothedemo.

Howitworks…OpenapreparedHTMLfile,inthat,youwillseeaninputboxandthreebuttons.Enterapeer’snameinthetextboxandclickontheConnect!button.ItwillconnecttoaPeerJSsystem.Now,openthefileinanotherbrowser(wecanalsoopenthefileonanothermachine).Enteranotherpeer’sname,andclickonConnect!.Inthefollowingscreenshot,Iusedpeer1andpeer2asnamesforthepeers:

Now,forthesecondpeer,enterthefirstpeer’sname(peer1inmycase)inthetextbox,andclickontheCallTobutton.Thiswillstarttoestablishthepeerconnection—peer2

willtrytomakeacalltopeer1.

Aftertheconnectionisestablished,wecantestmessageexchanging.Forpeer2,enteranyinputinthetextboxandclickonSendmessage.Theenteredtextwillbesenttopeer1,andwillbeprintedinitsbrowserconsole.Inthefollowingscreenshot,IhavesentaHello,peer1!!!message:

PeerJSusesitsowninfrastructuresuchassignalingmechanisms.Thus,ifyouusePeerJS,youdon’tneedtobeworriedofdevelopingsignalingprotocols,andyoucanconcentrateondevelopingyourapplication.

There’smore…YoucanfindoutmoreaboutPeerJSfromitshomepagehttp://peerjs.com.

Thisisafreeandopensourcetool,soitcanbeusedasanSDKorcanbetakenasacodebasefordevelopinganotherWebRTCframeworkforcustomapplication.

Makingasimplevideochatwithrtc.iortc.ioisafreeandopensourceprojectfordevelopingWebRTCapplications.ItprovidessimpleandcleanAPIs.Inthisrecipe,wewillusertc.iotocreateabasicvideochatservice.

GettingreadyLikemostoftheotherconsideredframeworks,rtc.ioservesitsownsignalingserver,soyoucancreateabasicapplicationusingjustafewlinesofJavaScriptcodeandHTML.Forthisrecipe,youwillneedatexteditorandwebbrowser.

Howtodoit…Createanemptyfileinthetexteditorandaddthefollowingcode.ThisisaplainHTMLwithaJavaScriptsection.Relevantplacesarecommentedinline.

1. Firstofall,let’saddthestandardHTMLheadsandbitofstyles:

<!DOCTYPEhtml>

<html>

<headlang="en">

<metacharset="UTF-8">

<style>

#messages{

border:1pxsolidblack;

min-height:20px;

}

</style>

2. Includethertc.ioframeworkinthisproject:

<scriptsrc="https://rawgit.com/rtc-io/rtc/master/dist/rtc.js">

</script></head>

<body>

3. Createseparatedivlayersforchatmessagesandbothlocalandremotevideo:

<divid="messages"contenteditable></div>

<divid="l-video"></div>

<divid="r-video"></div>

<scriptlanguage="JavaScript">

4. Settheframework’soptions—forabasiccase,wejustneedaroom’snameandsignalerserverURL.Here,weusedanativesignalerseverhostedonthertc.ioinfrastructure.It’sanopensourcecode,soyoucandownloadandinstallitonyourownserver:

varrtcOpts={

room:'my-cool-test-room',

signaller:'//switchboard.rtc.io'

};

5. InitializetheframeworkandcreateanRTCobject:

varrtc=RTC(rtcOpts);

varlocalVideo=document.getElementById('l-video');

varremoteVideo=document.getElementById('r-video');

varmessageWindow=document.getElementById('messages');

6. Bindhandlerfunctionstoappropriateeventsthatmightbegeneratedonthedatachannel:

functionbindDataChannelEvents(id,channel,attributes,connection){

channel.onmessage=function(evt){

messageWindow.innerHTML=evt.data;

};

messageWindow.onkeyup=function(){

channel.send(this.innerHTML);

};

}

7. Initializethesession:

functioninit(session){

session.createDataChannel('chat');

session.on('channel:opened:chat',bindDataChannelEvents);

}

8. Displaythelocalandremotevideo:

localVideo.appendChild(rtc.local);

remoteVideo.appendChild(rtc.remote);

9. Handlethesessionestablishingevent:

rtc.on('ready',init);

</script>

</body>

</html>

Theexamplecanbesavedonthediskanduploadedtothewebserver.

Howitworks…WecreatedanewRTCobjectusingtheframework’sAPI.Additionally,wesetacoupleoffunctionstohandleevents.Then,weinitializedtheframeworkbycallingtheappropriateAPImethod.Afterallthis,itwillhandlesignalingandpeerconnections.

There’smore…Foradditionaldetailsandadvancedexamplesofhowtousethisframework,refertoitshomepageathttp://rtc.io.

UsingOpenToktocreateaWebRTCapplicationOpenTokisaproprietaryframeworkthatallowsyoutobuildWebRTC-basedapplicationsusingtheprovidedSDK.Inthisrecipe,wewillbuildasimpledemoapplicationbyutilizingthebasicfeaturesofthetool.

GettingreadyTousethisframework,youshouldregisterwiththeOpenToksystem,andgetauniquedeveloperAPIID.Tousethissystem,youshouldhavethreekeys:theAPIkey,sessionID,andtoken.Thefollowinginstructionscovertheprocessofcreatingthesekeys:

1. Navigatetohttps://tokbox.com/opentok/andclickonSignUp.2. FilltheformandclickontheSignUpbutton:

3. Checkforane-mailfromOpenTok(TokBox),theywillsendaconfirmatione-mailwiththeAPIkey.WritedowntheAPIkey—thisisthefirstkey.Confirmyourregistrationwiththeirsystembyclickingontheappropriatelinkinthee-mail:

4. Navigatetohttps://dashboard.tokbox.com—findtheProjectssectionandclickontheViewDetailsbutton:

5. Inthenextpage,youwillseeProjectTools,whereyoucancreateanewsession.DoitbyusingtheCreatebutton:

6. Rightafterthat,youwillseethegeneratedsessionIDbelowthebutton.Writedownthisvalue—thisisthesecondkey.

7. Afteryou’vecreatedthenewsession,youshouldcreateanewtokenbasedonthissession.AttheGenerateTokensection,clickontheGeneratebutton:

8. Afteryou’veclickedontheGeneratebutton,youwillseeageneratedtokenbelowthebutton,asshowninthefollowingscreenshot:

9. Writedownthisvalue(generatedtoken)—thisisthethirdkey.

Now,youhaveallthethreekeystoworkwiththeOpenToksystem.

NoteThisframeworkrequiresyoutouseawebserver,soforthisrecipe,youshouldhaveawebserverinstalledandconfigured.

Howtodoit…Now,whenyouhaveyourAPIID,asessionID,andtwotokens,youcancontinuewiththeprocessofbuildinganapplicationusingOpenTok:

1. CreateanemptyHTMLfile(let’snameitindex.html)andaddthefollowingcode:

<!DOCTYPEhtml>

<html>

<headlang="en">

<metacharset="UTF-8">

<title></title>

2. IncludetheOpenTokcodeinyourproject:

<scriptsrc=

'http://static.opentok.com/webrtc/v2.2/js/opentok.min.js'>

</script>

<scripttype="text/javascript">

3. Inthefollowinglines,youshouldinserttheactualAPIID(APIkey)andsessionID,whichyouhavegeneratedwhilepreparingforthisrecipe:

varapiKey=<YOUR_API_ADI>;

varsessionId=<GENERATED_SESSION_ID>;

4. Asyouremember,wegeneratedtwotokens—oneperclient.Addthefirsttokeninthefollowingvariable:

vartoken=<TOKEN_1>;

5. InitializethesessionbycallingtheOpenTokmethod:

varsession=OT.initSession(apiKey,sessionId);

6. Subscribetoevents:

session.on("streamCreated",function(event){

session.subscribe(event.stream);

});

7. Openanewconnection:

session.connect(token,function(error){

varpublisher=OT.initPublisher();

session.publish(publisher);

});

</script>

</head>

<body>

8. WealsoneedanHTMLobjecttopublishavideothere:

<h1>Awesomevideofeed!</h1>

<divid="myPublisherDiv"></div>

</body>

</html>

9. Now,savethefileandcreateanotherone(let’snameitindex2.html).Makethesecondfileidenticaltothefirstone.Then,editthesecondfileandchangethetokenvalueinthefollowingline:

vartoken=<TOKEN_2>;

10. Inthesecondfile,youshouldaddthesecondtoken,whichyouhavegeneratedwhilepreparingforthisrecipe.Savethesecondfile.

Now,wehavetwofiles:index.htmlandindex2.html.Theyarebothidentical,exceptfortheirtokenvalue—everyfilecontainsitsowntokenID.Putboththefilesinthewebserver.

Howitworks…It’stimetotestwhatwe’vedeveloped.

Openawebbrowserandnavigatetotheplacewherethefirstfile(index.html)islocated.Notethatyoushouldnotuseafilesystem,andboththefilesshouldbeaccessibleonthewebserver.Afterthepageisopened,youwillseeanimagefromthewebcamera.

Now,onanothermachine,openawebbrowserandnavigatetothesecondfile(index2.html).Youwillseethesimilarpicture.Inacoupleofseconds,theconnectionwillbeestablishedandyouwillseelocalandremoteimagesonboththemachines.Thefollowingscreenshotrepresentsthiscase:

Inmycase,Ihaveusedthesamemachine,butopenedthefilesintwodifferentwebbrowsers.

OpenToktakescareofsignalingandothertechnicalprocesses.Asyoucansee,theapplicationisverycompact,andthecodeisveryshortandclean.Youdon’tneedtospendtimeoninstallationandmaintenanceofservercomponents,theyareprovidedandtransparentlyservedbytheframework.

There’smore…WeconsideredjustasimpleexampleofusingOpenTok,butthistoolallowsyoutocreatemorecomplexapplicationswithadvancedfeatures.Fordetails,refertoOpenTok’shomepageathttps://tokbox.com/opentok/.

CreatingamultiuserconferenceusingWebRTCOInthisrecipe,wewillcreateasimpleapplicationthatsupportsamultiuservideoconference.WewilldoitusingWebRTCO—anopensourceJavaScriptframeworkfordevelopingWebRTCapplications.

GettingreadyForthisrecipe,youshouldhaveawebserverinstalledandconfigured.Theapplicationwewillcreatecanworkwhilerunningonthelocalfilesystem,butitismoreconvenienttouseitviathewebserver.

Tocreatetheapplication,wewillusethesignalingserverlocatedontheframework’shomepage.Theframeworkisopensource,soyoucandownloadthesignalingserverfromGitHubandinstallitlocallyonyourmachine.GitHub’spagefortheprojectcanbefoundathttps://github.com/Oslikas/WebRTCO.

Howtodoit…Thefollowingrecipeisbuiltontheframework’sinfrastructure.Wewillusetheframework’ssignalingserver.Whatweneedtodoisincludetheframework’scodeanddosomeinitializationprocedure:

1. CreateanHTMLfileandaddcommonHTMLheads:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<metacharset="utf-8">

2. Addsomestyledefinitionstomakethewebpagelookingnicer:

<styletype="text/css">

video{

width:384px;

height:288px;

border:1pxsolidblack;

text-align:center;

}

.container{

width:780px;

margin:0auto;

}

</style>

3. Includetheframeworkinyourproject:

<scripttype="text/javascript"src=

"https://cdn.oslikas.com/js/WebRTCO-1.0.0-beta-min.js"charset="utf-8">

</script>

</head>

4. DefinetheonLoadfunction—itwillbecalledafterthewebpageisloaded.Inthisfunction,wewillmakesomepreliminaryinitializingwork:

<bodyonload="onLoad();">

5. DefineHTMLcontainerswherethelocalvideowillbeplaced:

<divclass="container">

<videoid="localVideo"></video>

</div>

6. Defineaplacewheretheremotevideowillbeadded.Notethatwedon’tcreateHTMLvideoobjects,andwejustdefineaseparatediv.Further,videoobjectswillbecreatedandaddedtothepagebytheframeworkautomatically:

<divclass="container"id="remoteVideos"></div>

<divclass="container">

7. Createthecontrolsforthechatarea:

<divid="chat_area"style="width:100%;height:250px;overflow:auto;

margin:0auto0auto;border:1pxsolidrgb(200,200,200);background:

rgb(250,250,250);"></div>

</div>

<divclass="container"id="div_chat_input">

<inputtype="text"class="search-query"placeholder="chathere"

name="msgline"id="chat_input">

<inputtype="submit"class="btn"id="chat_submit_btn"

onclick="sendChatTxt();"/>

</div>

8. Initializeafewvariables:

<scripttype="text/javascript">

varvideoCount=0;

varwebrtco=null;

varparent=document.getElementById('remoteVideos');

varchatArea=document.getElementById("chat_area");

varchatColorLocal="#468847";

varchatColorRemote="#3a87ad";

9. Defineafunctionthatwillbecalledbytheframeworkwhenanewremotepeerisconnected.Thisfunctioncreatesanewvideoobjectandputsitonthepage:

functiongetRemoteVideo(remPid){

varvideo=document.createElement('video');

varid='remoteVideo_'+remPid;

video.setAttribute('id',id);

parent.appendChild(video);

returnvideo;

}

10. CreatetheonLoadfunction.Itinitializessomevariablesandresizesthecontrolsonthewebpage.Notethatthisisnotmandatory,andwedoitjusttomakethedemopagelooknicer:

functiononLoad(){

vardivChatInput=document.getElementById("div_chat_input");

vardivChatInputWidth=divChatInput.offsetWidth;

varchatSubmitButton=

document.getElementById("chat_submit_btn");

varchatSubmitButtonWidth=chatSubmitButton.offsetWidth;

varchatInput=document.getElementById("chat_input");

varchatInputWidth=divChatInputWidth-chatSubmitButtonWidth

-40;

chatInput.setAttribute("style","width:"+chatInputWidth+

"px");

chatInput.style.width=chatInputWidth+'px';

varlv=document.getElementById("localVideo");

11. CreateanewWebRTCOobjectandstarttheapplication.Afterthispoint,theframeworkwillstartsignalingconnection,getaccesstotheuser’smedia,andwillbereadyforincomeconnectionsfromremotepeers:

webrtco=newWebRTCO('wss://www.webrtcexample.com/signalling',lv,

OnRoomReceived,onChatMsgReceived,getRemoteVideo,OnBye);

};

Here,thefirstparameterofthefunctionistheURLofthesignalingserver.Inthisexample,weusedthesignalingserverprovidedbytheframework.However,youcaninstallyourownsignalingserveranduseanappropriateURL.ThesecondparameteristhelocalvideoobjectID.Then,wewillsupplyfunctionstoprocessmessagesofreceivedroom,receivedmessage,andreceivedremotevideostream.Thelastparameteristhefunctionthatwillbecalledwhensomeoftheremotepeershavebeendisconnected.

12. Thefollowingfunctionwillbecalledwhentheremotepeerhasclosedtheconnection.Itwillremovevideoobjectsthatbecameoutdated:

functionOnBye(pid){

varvideo=document.getElementById("remoteVideo_"+pid);

if(null!==video)video.remove();

};

13. WealsoneedafunctionthatwillcreateaURLtosharewithotherpeersinordertomakethemabletoconnecttothevirtualroom.Thefollowingpieceofcoderepresentssuchafunction:

functionOnRoomReceived(room){

addChatTxt("Now,ifsomebodywantstojoinyou,shouldusethis

link:<ahref=\""+window.location.href+"?

room="+room+"\">"+window.location.href+"?room="+room+"

</a>",chatColorRemote);

};

14. Thefollowingfunctionprintssometextinthechatarea.WewillalsouseittoprinttheURLtosharewithremotepeers:

functionaddChatTxt(msg,msgColor){

vartxt="<fontcolor="+msgColor+">"+getTime()+msg+"

</font><br/>";

chatArea.innerHTML=chatArea.innerHTML+txt;

chatArea.scrollTop=chatArea.scrollHeight;

};

15. Thenextfunctionisacallbackthatiscalledbytheframeworkwhenapeerhassentusamessage.Thisfunctionwillprintthemessageinthechatarea:

functiononChatMsgReceived(msg){

addChatTxt(msg,chatColorRemote);

};

16. Tosendmessagestoremotepeers,wewillcreateanotherfunction,whichisrepresentedinthefollowingcode:

functionsendChatTxt(){

varmsgline=document.getElementById("chat_input");

varmsg=msgline.value;

addChatTxt(msg,chatColorLocal);

msgline.value='';

webrtco.API_sendPutChatMsg(msg);

};

17. Wealsowanttoprintthetimewhileprintingmessages;sowehaveaspecialfunctionthatformatstimedataappropriately:

functiongetTime(){

vard=newDate();

varc_h=d.getHours();

varc_m=d.getMinutes();

varc_s=d.getSeconds();

if(c_h<10){c_h="0"+c_h;}

if(c_m<10){c_m="0"+c_m;}

if(c_s<10){c_s="0"+c_s;}

returnc_h+":"+c_m+":"+c_s+":";

};

18. Wehavesomehelpercodetomakeourlifeeasier.Wewilluseitwhileremovingobsoletevideoobjectsafterremotepeersaredisconnected:

Element.prototype.remove=function(){

this.parentElement.removeChild(this);

}

NodeList.prototype.remove=HTMLCollection.prototype.remove=

function(){

for(vari=0,len=this.length;i<len;i++){

if(this[i]&&this[i].parentElement){

this[i].parentElement.removeChild(this[i]);

}

}

}

</script>

</body>

</html>

Now,savethefileandputitonthewebserver,whereitcouldbeaccessiblefromwebbrowser.

Howitworks…Openawebbrowserandnavigatetotheplacewherethefileislocatedonthewebserver.Youwillseeanimagefromthewebcameraandachatareabeneathit.Atthisstage,theapplicationhascreatedtheWebRTCOobjectandinitiatedthesignalingconnection.Ifeverythingisgood,youwillseeanURLinthechatarea.OpenthisURLinanewbrowserwindoworonanothermachine—theframeworkwillcreateanewvideoobjectforeverynewpeerandwilladdittothewebpage.

Thenumberofpeersisnotlimitedbytheapplication.Inthefollowingscreenshot,Ihaveusedthreepeers:twowebbrowserwindowsonthesamemachineandanotebookasthethirdpeer:

Usingthisframework,youcanattainyourownsignalingserveroryoucanusetheonethatisprovidedbythetool.

There’smore…Fornow,thetoolsupportsbasicWebRTCfeaturesanditisinthebetastage.WebRTCOisunderdevelopmentanditmightbeimprovedinthefuture.

Fordetailsonthisframework,refertoitshomepageathttps://www.oslikas.com/.

SourcecodesandexamplescanbefoundontheGitHubpageathttps://github.com/Oslikas/WebRTCO.

Moreexamplescanbefoundonthedemopage,http://www.webrtcexample.com.

Chapter8.AdvancedFunctionsInthischapter,wewillcoverthefollowingtopics:

Visualizingamicrophone’ssoundlevelMutingamicrophonePausingavideoTakingascreenshotStreamingmedia

IntroductionThischaptercoversadvancedexamplesofusingWebRTCfeatures.Thefollowingrecipesallowyoutoimproveyourapplication’susabilityandmakeitfriendlierbyaddingadvancedfeaturesandfunctionality.

AlltherecipesinthischapterareorientedontheclientsideandimplementedinJavaScript.Someofthemappeartobeprettysimpleandothersmightbemorecomplex,butthemainpurposeoftheserecipesistomaketheapplicationmoreadaptabletoreallifeandfriendlyforcustomers.

Visualizingamicrophone’ssoundlevelIfyourapplicationworkswithaudioandvideo(forexample,you’redevelopingavideoconferencingservice),itwouldbeprobablyagoodideatoaddaliveindicationofthemicrophonesoundlevel.Usingthisfeature,peerscanestimateandcontroltheirmicrophone’saudiolevels.So,inthisrecipe,we’reimplementingmicrophoneactivityindication.

GettingreadyThisrecipeissimple,andyouwilljustneedatexteditortocreateandeditHTML.Totestthisrecipe,youshouldhaveawebserverinstalledandconfigured—itishighlyrecommendedtotesttheexampleviaawebserverratherthanjustonalocalfilesystem;otherwise,thewebbrowsermightblockcallstotheWebRTCAPI.

Howtodoit…Performthefollowingsteps:

1. CreateanHTMLfileandinsertthefollowingcodes.Notethattheimportantplacesarecommentedinline:

<!DOCTYPEhtml>

<html>

<headlang="en">

<metacharset="UTF-8">

2. IncludetheWebRTCadapterfromGoogle.Thisfileallowsyoutouseuniversalfunctionnamesinallsupportedwebbrowsers:

<scriptsrc=

"https://rawgit.com/GoogleChrome/webrtc/master/samples/web/js/adapter.j

s"></script>

</head>

<body>

3. CreateasimpleHTMLelementtodisplayalocalvideofromawebcamera:

<div><videowidth="384"id="lVideo"muted="true"autoplay="true">

</video></div>

4. Createacanvaselement—here,wewillrepresentthemicrophone’ssoundlevel:

<canvaswidth="384"height="20"id="micecanvas"style="background-

color:white;"></canvas>

<scripttype="text/javascript">

Thefollowingfunctiongetsaccesstousermedia:

functioninit(){

varconstraints={"audio":true,"video":{"mandatory":{},

"optional":[]}};

getUserMedia(constraints,onUserMediaSuccess,

onUserMediaError);

}

5. Weneedtohandleerrors,soasimpleerrorhandlerfunctioncanbefoundinthefollowingcode:

functiononUserMediaError(error){

console.log("Error:"+error);

}

Thefollowingcallbackfunctionwillbecalledaftertheapplicationhasaccesstotheusermedia:

functiononUserMediaSuccess(stream){

6. Toattachamediastreamtothevideocontrol,usethefollowingcode:

varlocalVideo=document.getElementById("lVideo");

attachMediaStream(localVideo,stream);

7. Setupafunctionaliastomakethisworkunderdifferentsupportedbrowsers:

window.AudioContext=window.AudioContext||

window.webkitAudioContext||window.mozAudioContext;

8. Initializethelocalvariablesandgetaccesstothemicrophone:

varaudioContext=newAudioContext();

varanalyser=audioContext.createAnalyser();

varmicrophone=

audioContext.createMediaStreamSource(stream);

9. Assignascriptprocessortotheaudiocontext.Byusingthescriptprocessor,wewillbeabletoprocessaudiodataandcalculatemicrophoneactivitylevel:

varjavascriptNode=

audioContext.createScriptProcessor(2048,1,1);

analyser.smoothingTimeConstant=0.3;

analyser.fftSize=1024;

microphone.connect(analyser);

analyser.connect(javascriptNode);

javascriptNode.connect(audioContext.destination);

varcanvasContext=

document.getElementById("micecanvas").getContext("2d");

10. Setupanaudiodataprocessingfunction—here,wewilldoallthecalculations:

javascriptNode.onaudioprocess=function(){

vararray=new

Uint8Array(analyser.frequencyBinCount);

analyser.getByteFrequencyData(array);

varvalues=0;

varlength=array.length;

for(vari=0;i<length;i++){

values+=array[i];

}

11. Calculatetheaveragesoundlevelvalueanddrawitonthecanvas:

varaverage=values/length;

canvasContext.clearRect(0,0,384,20);

canvasContext.fillStyle='red';

canvasContext.fillRect(0,0,average,20);

}

}

12. Thefollowingfunctionstartstheapplication:

init();

</script>

</body>

</html>

13. Now,savethefileandputitonthewebserver,makingitaccessiblethroughacertainURL.

14. NavigatetotheURL.Youwillseetheimagefromyourwebcamera,andashorthorizontalredbarbeneathit.Youwilljustseethelocalvideobecausewehaven’t

implementedaninterconnectionwithremotepeers.15. Now,talkthroughthemicrophoneandmakesomenoise—thebarwillrespondtothe

soundbychangingitslengthandtrembling.Thisbarrepresentsthemicrophone’ssoundactivitylevelandyoucanestimateitvisually.

Howitworks…UsingWebRTCAPI,wewillcreatetheaudiocontextandaudioanalyzerobjects.Then,wewillgetaccesstothemicrophone.WewillalsocreateScriptProcessorwithabufferof2048bytes,andoneinputandoneoutputchannel.UsingthefftSizeattributeoftheanalyzer,wewillsetthesizeoftheFastFourierTransform(FFT)bufferto1024.Wewillconnecttheanalyzerandthescriptprocessor,andthen,wewillsetuptheonaudioprocesshandlerfunction.Now,approximatelyevery0.3seconds,wewillgetasignalfromthebrowsertoourhandlerfunctionwhereweusereceiveddatatocalculatethesoundvolumeandtodrawitonthebar.

SeealsoRegardingdetailedexplanationsofthepossibleusageoftheaudioAPI,youcanrefertoitsofficialdocumentationathttp://webaudio.github.io/web-audio-api/

MutingamicrophoneUsually,voicecallingsoftwarehasamicrophonemutingfeature.So,youcanenableordisableyourmicrophoneduringthecall,decidingwhethertheremotepeershouldhearyourvoiceornot.Inthisrecipe,wewillimplementsuchafeatureforaWebRTCapplication.

GettingreadyForthisexample,youdon’tneedanypreliminaryspecificsteps.Useyourdevelopmentenvironmentasyouusuallydo.

Howtodoit…Followthesesteps:

1. Forthisfeature,youneedtoaddabuttonelementtoyourHTMLpage.Thisbuttonwillenableordisablethemicrophone:

<buttonid="mute_btn"onclick="muteBtnClick()">MuteMic</button>

2. Youalsoneedtosetupahandlerfortheonclickeventoftheelement—itwilldotheactualwork.Thefollowingcodeisanexampleofsuchahandler:

functionmuteBtnClick(){

3. Wewillupdateourbuttonwiththemicrophonestate,soweneedtogetthebuttonID:

varbtn=document.getElementById("mute_btn");

4. Beforewecandecidewhetherwewanttomuteorunmutethemicrophone,weshouldbeabletoknowitsactualstate—forthispurpose,wewillusetheisMicMutedfunction:

if(isMicMuted()){

5. Ourmicrophoneismuted,sowewanttounmuteitandupdatethebuttonwiththeappropriatestate:

muteMic(false);

btn.innerHTML="MuteMic";

}else{

6. Themicrophoneisunmuted,sowewillmuteitandupdatethebuttonaswell:

muteMic(true);

btn.innerHTML="UnmuteMic";

}

}

7. Inthehandler,wewillusetheisMicMutedfunctiontodetectwhetherthemicrophoneismuted.Let’simplementthisfunctionaswell:

functionisMicMuted(){

return!(localStream.getAudioTracks()[0].enabled);}

8. NotethattheWebRTCAPIcanletusknowwhethertheaudiotrackisenabled,butourfunctionreturnsthemicrophone’smutedvalue.So,wewillinverttheenabledvaluereceivedfromWebRTCstack.

9. Finally,weneedtoimplementtheactualmute/unmutefunction:

functionmuteMic(mute){

localStream.getAudioTracks()[0].enabled=!mute;

};

10. Here,localStreamisavariablethatcontainsalocalstreamobjectreceivedafterasuccessfulcallofthegetUserMediaWebRTCAPIfunction.

NoteInthisfunction,wewillsetuptheenabledvalue,butthefunctiongetstheshouldImutethemicrophoneparameter.Ifthisfunctiongetstrueasanargument,itshouldsetfalsetotheenabledpropertyoftheaudiotrack.Thisiswhywewillinvertthevalueagain,aswedoitintheisMicMutedfunction.

Howitworks…Themainideaistogetanappropriateaudiotrackofthelocalmediastream,andtochangeitsstatetodisabledorenabled.Inthefirstcase,thetrackwillbemutedandtheremotepeerwillnothearyourvoice.Changingthestatecanbedoneinrealtime.

There’smore…Ifyouhavemorethanoneaudiodevice,thegetAudioTracksfunctionmightreturnseveralaudiotracksanditmightbenecessarytogooverallofthem:

varaudiotracks=localStream.getAudioTracks();

for(vari=0,l=audiotracks.length;i<l;i++)

{

audiotracks[i].enabled=false;

}

SeealsoRefertothePausingavideorecipetoseeasimilartechniqueappliedtovideostreams

PausingavideoIfyou’reparticipatinginavideoconferencecall,youmightwanttotemporarilyswitchyourvideocameraoffandtakeapause.Duringthistime,yourremotepeershouldn’tseeanimagefromyourcamera.Inmostvideoconferencingsoftware,youcanenableordisableyourcameraduringthecall.Inthisrecipe,wewillimplementthisfeatureforaWebRTCapplication.

GettingreadyForthisrecipe,youdon’tneedanyspecificpreparations.JustcreateabasicconferencingWebRTCapplication.

Howtodoit…Performthefollowingsteps:

1. WeneedtoaddaPauseVideobuttontotheapplication’swebpage:

<buttonid="pause_video_btn"onclick="pauseVideoBtnClick()">Pause

Video</button>

2. Youalsoshouldsetupahandlerfortheonclickeventofthebutton:

functionpauseVideoBtnClick(){

3. Wewillupdateourbuttonwiththevideostreamstate(whetheritispausedornot),soweneedtogetthebuttonID:

varbtn=document.getElementById("pause_video_btn");

4. Beforewedecidewhetherweshouldpausethestreamorstartplayingitbackagain,weshouldbeabletoknowitscurrentstate—forthispurpose,wewillusetheisVideoPausedfunction:

if(isVideoPaused()){

5. Ifthevideostreamispaused,wewanttostartplayingitbackandupdatethebuttonwiththenewstate,thenusethefollowingcode:

pauseVideo(false);

btn.innerHTML="PauseVideo";

}else{

6. Incasethevideoisstreaming,wewillpauseitandupdatethebuttonaswell:

pauseVideo(true);

btn.innerHTML="StreamVideo";

}

}

7. Inthehandler,wewillusetheisVideoPausedfunctiontodetectwhetherthevideostreamispaused.Let’simplementthisfunctionaswell:

functionisVideoPaused(){

return!(localStream.getVideoTracks()[0].enabled);

}

8. NotethattheWebRTCAPIcanletusknowifacertainvideotrackisenabledornot,butourfunctionreturnstheisthevideopausedstate.So,wewillinverttheenabledvaluereceivedfromtheWebRTCstack.

9. Finally,weneedtoimplementthefunctionthatactuallyputsthevideoonpauseandviceversa:

functionpauseVideo(pause){

localStream.getVideoTracks()[0].enabled=!pause;

};

10. Here,localStreamisavariablethatcontainsalocalstreamobjectreceivedaftera

successfulcallofthegetUserMediaWebRTCAPIfunction.

NoteInthisfunction,wewillsetuptheenabledvalue,butthefunctiongetstheshouldIputthevideoonpauseparameter.So,ifitgetstrueasanargument,itshouldsettheenabledpropertyofthevideotracktofalse.

Howitworks…Therootideaofthedescribedsolutionistogetanappropriatevideotrackofthelocalmediastreamandtochangeitsstatetodisabledorenabled.Inthefirstcase,thevideotrackwillbepaused,streamingwillbestopped,andtheremotepeerwillnotseeyou.Changingthestatecanbedoneinrealtime.

SeealsoRefertotheMutingamicrophonerecipeforadditionaldetailsregardingtheusageofthissolutiontoworkwithaudiotracks

TakingascreenshotSometimes,itcanbeusefultobeabletotakescreenshotsfromavideoduringvideoconferencing.Inthisrecipe,wewillimplementsuchafeature.

GettingreadyNospecificpreparationisnecessaryforthisrecipe.YoucantakeanybasicWebRTCvideoconferencingapplication.WewilladdsomecodetotheHTMLandJavaScriptpartsoftheapplication.

Howtodoit…Followthesesteps:

1. Firstofall,addimageandcanvasobjectstothewebpageoftheapplication.Wewillusetheseobjectstotakescreenshotsanddisplaythemonthepage:

<imgid="localScreenshot"src="">

<canvasstyle="display:none;"id="localCanvas"></canvas>

2. Next,youhavetoaddabuttontothewebpage.Afterclickingonthisbutton,theappropriatefunctionwillbecalledtotakethescreenshotfromthelocalstreamvideo:

<buttononclick="btn_screenshot()"id="btn_screenshot">Makea

screenshot</button>

3. Finally,weneedtoimplementthescreenshottakingfunction:

functionbtn_screenshot(){

varv=document.getElementById("localVideo");

vars=document.getElementById("localScreenshot");

varc=document.getElementById("localCanvas");

varctx=c.getContext("2d");

4. Drawanimageonthecanvasobject—theimagewillbetakenfromthevideoobject:

ctx.drawImage(v,0,0);

5. Now,takereferenceofthecanvas,convertittotheDataURLobject,andinsertthevalueintothesrcoptionoftheimageobject.Asaresult,theimageobjectwillshowusthetakenscreenshot:

s.src=c.toDataURL('image/png');

}

6. Thatisit.Savethefileandopentheapplicationinawebbrowser.Now,whenyouclickontheMakeascreenshotbutton,youwillseethescreenshotintheappropriateimageobjectonthewebpage.Youcansavethescreenshottothediskusingright-clickandthepop-upmenu.

Howitworks…Weusethecanvasobjecttotakeaframeofthevideoobject.Then,wewillconvertthecanvas’datatoDataURLandassignthisvaluetothesrcparameteroftheimageobject.Afterthat,animageobjectisreferredtothevideoframe,whichisstoredinthecanvas.

SeealsoRefertotheVisualizingamicrophone’ssoundlevelandMutingamicrophonerecipesforexamplesregardinghowtoworkwithaudiodata

StreamingmediaThisrecipecoversanotherinterestingfeaturethatcanbeimplementedusingtheWebRTCstack:streamingprerecordedmediafromonepeertoanotherone.

GettingreadyWewillstreamaprerecordedWebMfile,soyouneedtohaveone.YoucandownloaddemoWebMfilesfromtheInternet.Forexample,fromhttp://www.webmfiles.org/demo-files/.

Inthisrecipe,wewillcreatetwofiles:anHTMLpageandaJavaScriptlibrary.

NoteThisfeaturedoesn’tworkonthelocalfilesystem.Toimplementthisfeature,youneedtohaveawebserverwhereyoucanplacealltheapplicationfiles,andwheretheapplicationisaccessibletothecustomer.

Asignalingserverisalsonecessaryforthisrecipe.YoucanusetheserverfromChapter1,PeerConnections.

Howtodoit…Openyourtexteditor,andlet’screatetheHTMLpagebyfollowingthegivensteps:

1. MakeasimpleHTMLheader:

<!DOCTYPEhtml>

<html>

<head>

<title>MyWebRTCfilemediastreamingdemo</title>

2. Addsomestyleforthevideocomponent:

<styletype="text/css">

video{

width:384px;

height:288px;

border:1pxsolidblack;

text-align:center;

}

</style>

3. IncludeaJavaScriptlibrarythatwewillwriteatthenextstage:

<scripttype="text/javascript"src="myrtclib.js"></script>

4. IncludeGoogle’sadaptertokeepcross-browsercompatibility:

<script

src="https://rawgit.com/GoogleChrome/webrtc/master/samples/web/js/adapt

er.js"></script>

</head>

<body>

5. Creatediv,whereaconnectionlinkwillbepublishedforpeers:

<divid="status"></div><br>

6. Createavideoelement.Thiselementwillshowthemediastreamedfromtheremotepeer:

<div><videoid="remotevideo"autoplay="true"controls="true"></video>

</div>

7. Createafilechoosingcomponentandabuttonthatwillstartthestreamingprocess:

<div>

fileyouwanttostream<inputtype="file"id="files"

name="files[]"/>thenpress<buttononclick="onSendBtnClick()">Start

streaming!</button>

</div>

<script>

varfilelist;

8. Checkwhetherthewebbrowsersupportscomponentsandtechnologiesthatweuseforthisfeature:

if(window.File&&window.FileReader&&window.FileList&&

window.Blob){

document.getElementById('files').addEventListener('change',

handleFileSelect,false);

9. ConnecttothesignalingserverandinitializeourWebRTClibrary.NotethatyoushoulduseanactualIPandportofthesignalingserverwhereitisrunningonyourmachine.Bydefault,theyare127.0.0.1and30001,asimplementedintheappropriaterecipesofChapter1,PeerConnections,whereweconsideredsignalingservers:

myrtclibinit("ws://127.0.0.1:30001",

document.getElementById("remotevideo"));

}else{

10. Createanalertforinstanceswhenthewebbrowserdoesn’tsupportnecessarytechnologies:

alert('TheFileAPIsarenotfullysupportedinthis

browser.');

}

11. Implementafunctionthathandlesthefilechoosingcomponent:

functionhandleFileSelect(evt){

filelist=evt.target.files;

};

12. Implementafunctionthatstartsthestreamingprocess.NotethatthedoStreamMediafunctionisimplementedintheJavaScriptlibrarythatwillbeconsideredinthenextstage:

functiononSendBtnClick(){

doStreamMedia(filelist[0]);

};

13. Implementacallbackfunctionthatconstructsaconnectionlinkandpublishesitonthewebpage:

functiononRoomReceived(room){

varst=document.getElementById("status");

st.innerHTML="Now,ifsomebodywantstojoinyou,shoulduse

thislink:<ahref=\""+window.location.href+"?

room="+room+"\">"+window.location.href+"?room="+room+"</a>";

};

</script></body></html>

Next,youneedtocreateaJavaScriptlibrarythatisusedintheHTMLpagewejustcreated.Mostofthecodeissimpleandidenticaltotheappropriatepartsoftherecipesfromotherchapters.Here,wewillcoveronlyspecificmomentsthatareimportantinthescopeofthefeature;knownpiecesofcodewillbeskipped.Notethatthefullsourcecodeforthisrecipeissuppliedalongwiththisbook.

ThisexampleactivelyusesWebRTCdatachannels,soyoucanrefertotheImplementingachatusingdatachannelsrecipefromChapter1,PeerConnections,formoredetailson

thistopic.Performthefollowingstepsforusingdatachannels:

1. Declareachunksize.Whilestreamingtheprerecordedmedia,theapplicationreadsthemediafilechunkbychunkandsendsittotheremotepeer.So,wehavetodeclarethechunksizevalue—1024,inthisparticularcase.Youcanplaywithothervaluesandseehowtheyaffectthedemo.Don’tusetoolowortoohighvalues:

varchunkSize=1024;

2. Declarevariablesthatwillhandlebufferandmediasource.Thebufferisastructurethathandlesrawmediadataontheclientside(wherethemediawillbestreamed).ThemediasourcerepresentsaWebRTCobjectthatwillbetiedwithavideoHTMLobject:

varreceiverBuffer=null;

varrecvMediaSource=null;

3. DeclareavariablethatwillhandletheHTMLvideoobjectwherethestreamedmediawillbeshown:

varremoteVideo=null;

4. Declareanarray.Thiswillbeusedasacachetotemporarilystorethereceivedchunksincasetheremotepeersendsthemfasterthanwecandrawthemonthevideo:

varqueue=[];

5. ThefollowingcodeisusedforcompatibilitybetweenFirefoxandChrome:

window.MediaSource=window.MediaSource||

window.WebKitMediaSource;

6. Establishanewpeer-to-peerdatachannel:

functioncreateDataChannel(role){

try{

data_channel=

pc.createDataChannel("datachannel_"+room+role,null);

}catch(e){

console.log('errorcreatingdatachannel'+e);

return;

}

initDataChannel();

}

7. Whilesettingasessiondescription,removebandwidthlimitations.Somewebbrowsers(forexample,someversionsofChrome)limitbandwidth,soconnectionperformancemightdegrade.Toavoidthat,wewillcallourcustomsetBandwidthfunction,whichremovessuchlimitations:

functionsetLocalAndSendMessage(sessionDescription){

sessionDescription.sdp=setBandwidth(sessionDescription.sdp);

pc.setLocalDescription(sessionDescription,function(){},

failureCallback);

sendMessage(sessionDescription);

};

8. ImplementthesetBandwidthfunction.Itsetsthebandwidthlimittoahighervalueinsteadofthedefaultone,whichmightbesetbythebrowser:

functionsetBandwidth(sdp){

sdp=sdp.replace(/a=mid:data\r\n/g,

'a=mid:data\r\nb=AS:1638400\r\n');

returnsdp;

}

9. ChangetheonReceiveMessageCallbackfunction,adoptingitforthenewfeature.YoushouldbefamiliarwiththisfunctionfromChapter1,PeerConnections.

functiononReceiveMessageCallback(event){

try{

varmsg=JSON.parse(event.data);

if(msg.type==='chunk'){

onChunk(msg.data);

}

}

catch(e){}

};

10. Declaretheauxiliaryvariablesforslicingthemediafile:

varstreamBlob=null;

varstreamIndex=0;

varstreamSize=0;

11. ImplementafunctionthatiscalledfromtheHTMLpage.Thisfunctionreadsthemediafile,slicesitintochunks,andsendsthemtotheremotepeer:

functiondoStreamMedia(fileName){

varfileReader=newwindow.FileReader();

fileReader.onload=function(e){

streamBlob=newwindow.Blob([new

window.Uint8Array(e.target.result)]);

streamSize=streamBlob.size;

streamIndex=0;

streamChunk();

};

fileReader.readAsArrayBuffer(fileName);

}

functionstreamChunk(){

if(streamIndex>=streamSize)sendDataMessage({end:true});

varfileReader=newwindow.FileReader();

fileReader.onload=function(e){

varchunk=newwindow.Uint8Array(e.target.result);

streamIndex+=chunkSize;

pushChunk(chunk);

window.requestAnimationFrame(streamChunk);

};

fileReader.readAsArrayBuffer(streamBlob.slice(streamIndex,

streamIndex+chunkSize));

}

12. Implementafunctiontoreceivemediadata.Thisfunctioninitializesthemediasourceandbufferobjects,andpreparestoreceivemediachunksthataresentbytheremotepeer:

functiondoReceiveStreaming(){

recvMediaSource=newMediaSource();

remoteVideo.src=window.URL.createObjectURL(recvMediaSource);

recvMediaSource.addEventListener('sourceopen',function(e){

remoteVideo.play();

13. WewillusetheWebMmediafile,soweshouldsetanappropriatemediatypeforthemediabuffer:

receiverBuffer=

recvMediaSource.addSourceBuffer('video/webm;codecs="vorbis,vp8"');

receiverBuffer.addEventListener('error',function(e){

console.log('error:'+receiverBuffer.readyState);});

receiverBuffer.addEventListener('abort',function(e){

console.log('abort:'+receiverBuffer.readyState);});

receiverBuffer.addEventListener('update',function(e){

if(queue.length>0&&!receiverBuffer.updating)

doAppendStreamingData(queue.shift());

});

console.log('mediasourcestate:',this.readyState);

doAppendStreamingData(queue.shift());

},false);

recvMediaSource.addEventListener('sourceended',function(e){

console.log('sourceended:'+this.readyState);});

recvMediaSource.addEventListener('sourceclose',function(e){

console.log('sourceclose:'+this.readyState);});

recvMediaSource.addEventListener('error',function(e){

console.log('error:'+this.readyState);});

};

14. Thefollowingfunctionactuallyputsthemediadataintothemediabuffer:

functiondoAppendStreamingData(data){

varuint8array=newwindow.Uint8Array(data);

receiverBuffer.appendBuffer(uint8array);

};

15. Implementafunctionthatwillstopplayingbackthemediawhenthemediadataisover:

functiondoEndStreamingData(){

recvMediaSource.endOfStream();

};

16. Createafunctiontosendmediadatachunkstotheremotepeer.WewillusetheJSONformatforsuchmessagestodeclaretypeanddatafields:

functionpushChunk(data){

varmsg=JSON.stringify({"type":"chunk","data":

Array.apply(null,data)});

sendDataMessage(msg);

};

17. Implementafunctionthattakesthereceivedchunksandprocessesthem:

functiononChunk(data){

18. WewillputthefirstchunkintoacacheandcallthedoReceiveStreamingfunctiontopreparemediacomponents:

chunks++;

if(chunks==1){

console.log("firstframe");

queue.push(data);

doReceiveStreaming();

return;

}

if(data.end){

console.log("lastframe");

doEndStreamingData();

return;

}

19. Incasethecache(queue)isnotemptyalready,wewillputthenewlyreceivedchunkinthequeue.That’sbecauseanon-emptyqueuemeansthatwe’rereceivingnewchunksfasterthanwecanprocessandshowthem:

if(receiverBuffer.updating||queue.length>0)

queue.push(data);

20. Incasethequeueisempty,wecancallthedoAppendStreamingDatafunctionthatwillputthechunkinthemediabuffer,andthemediadatawillbeshownonthepage:

elsedoAppendStreamingData(data);

};

So,youhavetheindexpageandtheJavaScriptlibrarynow.Putthembothinthewebserverfolder,andstartthesignalingserver.Navigateyourwebbrowsertowherethedemoisaccessible.Thennavigateanotherwebbrowser(orwebbrowsertab)tothelinkatthetopofthepage;afterthis,peerswillestablishadirectconnection.

Atthebottompartofthepage,youshouldseesomethingsimilartothefollowing:

NotethebuttonsChooseFileandStartstreaming!.ClickontheChooseFilebuttonandselectthepreloadedWebMmediafile.Then,clickontheStartstreaming!button.Thewebbrowserwhereyouclickedthebuttonswillstartreadingthemediafileandstreamingittothesecondbrowser.So,onanotherbrowserwindow,youshouldseeyourmediafileplaying.

Inthefollowingscreenshot,youcanseetwobrowserwindows:ChromeatthetopandFirefoxattheback.Here,I’mstreamingthemediafilefromChrometoFirefox.

Notethatthisfeatureisinthebetastage,andyoumightneedtomakeappropriatechangestomakethedemoworkonotherbrowserversions.

AnotherimportantnoteisthatFirefoxhasdisabledthemediasourcecomponentbydefault,soyoushouldcheckthatandenableitbeforeusingthisrecipewithFirefox.Todothat,youshouldnavigatetoabout:config,lookforthemedia.mediasource.enabledoptionandsetittotrue.Youcanseethissolutioninthefollowingscreenshot:

NotethatFirefoxstartsplayingimmediatelyafteritgetsthefirstbytesofthemediadata.

Chromewillwaituntilitgetsallthemediadataandonlythenwillstartplayingthem.Thisbehaviormightbechangedinotherbrowserversions.

Howitworks…Thelogicofthisfeatureissimple.Firstofall,peersestablishadirectconnectionandcreatedatachannel.Then,thesender(streamingpeer)actsasshowninthefollowingsteps:

1. ReadsthewholemediafileinthememoryandcreatesaBLOBobject.2. ReadstheBLOBobjectchunkbychunk,slicesthemintosmallerblocks.3. SendstheBLOBobjectchunkbychunktotheremotepeer.4. Repeatsstep3untiltheendofthemediafile.

Ontheotherhand,anotherpeerperformsthefollowingsteps:

1. Createsamediasourceobject.Preparesmediabuffer.TiestheobjectswiththevideoHTMLobjectonthepage.

2. Getschunksfromtheremotepeerandputsbinarydatainthemediabuffer,whichistiedtothevideoobject.

3. Incasethestreamersendsdatafasterthanthereceivercanprocessit,thereceiverusesaqueuetotemporarilystorethereceivedmediadata.

4. Repeatssteps2and3untilthereissomemediadatareceivedfromtheremotepeer.

Thus,thereceiverplaysbackthevideothatisstreamedbytheremotepeer.

SeealsoThisrecipeactivelyusesWebRTCdatachannels.Inthecode,weconsideredonlystreaming-relatedimportantpartsofcode.Forcodesspecifictodatachannels,refertoChapter1,PeerConnections,wherethistopicisexplainedinamoredetailedway.

IndexA

AndroidDeveloperTools(ADT)/InstallingAndroidDeveloperToolsAndroidVirtualDevice(AVD)tool/RunningontheAndroidsimulatorApache

configuring/ConfiguringApacheapplication

creating,RTCMultiConnectionused/CreatinganapplicationusingRTCMultiConnection,Howtodoit…,Howitworks…,There’smore…

ApplicationRequestRouting(ARR)/ConfiguringIISApplicationRequestRouting3.0/ConfiguringIISAsterisk

URL/There’smore…

Bbasicconfigurationitems,TURN

listeningIP/InstallingtheTURNserverrelayIP/InstallingtheTURNserververbosity/InstallingtheTURNserveranonymousaccess/InstallingtheTURNserver

blureffectimplementing/Implementingtheblureffect,Howtodoit…,Howitworks…

BriaURL/InstallingsipML5

brightnessworkingwith/Workingwithbrightness,Howtodoit…,Howitworks…

bweforvideo/Usingwebrtc-internals

C3CXPhone

URL/InstallingsipML5calls

making/Makingandansweringcalls,Makingacallanswering/Makingandansweringcalls,Answeringacall,There’smore…making,fromwebpage/Makingcallsfromawebpage,Howtodoit…

certificateauthority(CA)about/Generatingaself-signedcertificate

Chromeabout/DebuggingwithChromeWebRTCapplication,debuggingwith/DebuggingwithChrome,GettingreadyURL/Gettingready

Chromemechanisms,fordebuggingWebRTCapplicationswebrtc-internals,using/Usingwebrtc-internalsloggingmechanism,using/UsingChromeloggingmechanism,There’smore…

client-sidecode,TURNserverimplementing/Implementingtheclient-sidecode

colorsworkingwith/Workingwithcolorsandgrayscale,Howtodoit…inverting/Invertingcolors,Howtodoit…,Howitworks…

Conn-audioobject/Usingwebrtc-internalscontrast

workingwith/Workingwithcontrast,Howtodoit…customizedWebRTCdemo

building,foriOS/BuildingacustomizedWebRTCdemoforiOS,Howtodoit…

customvideoprocessingabout/Customvideoprocessing,Howtodoit…

Ddebugging

about/Introductiondemoproject

building,foriOSsimulator/BuildingademoprojectforaiOSsimulator,Seealso

demoWebMfilesURL/Gettingready

DoS(denialofservice)/Configuringafirewalldroppedshadoweffect

implementing/Implementingthedroppedshadoweffect,Howtodoit…DtlsSrtpKeyAgreementoption/Usingwebrtc-internals

EErlang

signalingserver,building/Gettingready,Howtodoit…URL/Gettingready

ExpressTalkURL/InstallingsipML5

FFastFourierTransform(FFT)buffer/Howitworks…filters

about/Introductioncombining/Combiningfilters,Howtodoit…,Howitworks…

FirebaseURL/Howitworks…

firewallconfiguring/Configuringafirewallconfiguring,onserver/Configuringafirewallonaserverconfiguring,onclient/Configuringafirewallonaclient

FreeSWITCHabout/There’smore…

GgetStatsWebRTCAPIfunction

about/Howtodoit…usecases/Howtodoit…

GLSurfaceViewbug,fixingwith/FixingabugwithGLSurfaceView

grayscaleworkingwith/Workingwithcolorsandgrayscale,Howtodoit…

Hhue

workingwith/Workingwithhue,Howtodoit…

IIIS

configuring/ConfiguringIIS,There’smore…InteractiveConnectivityEstablishment(ICE)

about/Howtodoit…/ConfiguringafirewallonaclientInternetInformationServices(IIS)ResourceKitTools/There’smore…inversionofcolors/Invertingcolors

JJava

signalingserver,building/BuildingasignalingserverinJava,Howtodoit…URL/Gettingready

Java7about/Gettingready

JavaDeveloperKit(JDK)/GettingreadyJSON

URL/GettingreadyJsSIP

URL/There’smore…

Mmedia

streaming/Streamingmedia,Howtodoit…,Howitworks…microphone

muting/Mutingamicrophone,Howtodoit…microphonelevel

visualizing/Visualizingamicrophone’ssoundlevel,Gettingready,Howtodoit…

mtr/There’smore…multiuserconference

creating,WebRTCOused/CreatingamultiuserconferenceusingWebRTCO,Howtodoit…,Howitworks…

Nnativeapplication

about/Introductionbuilding/Introduction

nativedemoWebRTCapplication,forAndroidcompiling/CompilingandrunningademoforAndroidsystem,preparing/PreparingthesystemOracleJDK,installing/InstallingOracleJDKWebRTCsourcecode,obtaining/GettingtheWebRTCsourcecodeAndroidDeveloperTools,installing/InstallingAndroidDeveloperTools,Howtodoit…running,onAndroidsimulator/RunningontheAndroidsimulatorbug,fixingwithGLSurfaceView/FixingabugwithGLSurfaceViewrunning,onphysicalAndroiddevice/RunningonaphysicalAndroiddevice

NetworkAddressTranslation(NAT)/ConfiguringafirewallonaclientNetworkAddressTranslator(NAT)/Howtodoit…Nginx

configuring/ConfiguringNginxNumb

about/There’smore…URL/There’smore…

Oopacityfilter

using/Usingtheopacityfilter,Howtodoit…OpenTok

about/UsingOpenToktocreateaWebRTCapplicationused,forcreatingWebRTCapplication/UsingOpenToktocreateaWebRTCapplication,Gettingready,Howtodoit…,Howitworks…

OpenWebRTClibrarybuilding/BuildinganOpenWebRTClibrary,Gettingready,There’smore…

originalGoogleWebRTCnativedemoapplicationcompiling/CompilingandrunninganoriginaldemoforiOSdemoproject,buildingforiOSdevice/BuildingademoprojectforaniOSdevicedemoproject,buildingforiOSsimulator/BuildingademoprojectforaniOSsimulator

Ppeer-to-peerprivatemessagingservice

implementing,datachannelsused/Implementingachatusingdatachannels,GettingreadymainHTMLpage,creating/Howtodoit…,CreatingthemainHTMLpageoftheapplicationJavaScripthelperlibrary,creating/CreatingtheJavaScripthelperlibraryworking/Howitworks…implementing,signalingserverused/Implementingachatusingasignalingserver,Howtodoit…,There’smore…

peerconnectionssignalingserver,buildinginErlang/BuildingasignalingserverinErlang,Howtodoit…signalingserver,buildinginJava/BuildingasignalingserverinJava,Howtodoit…calls,making/Gettingreadycalls,answering/Gettingready

PeerJSused,fordevelopingsimpleWebRTCchat/DevelopingasimpleWebRTCchatusingPeerJS,Howtodoit…,Howitworks…

publickeyinfrastructure(PKI)about/Generatingaself-signedcertificateURL/Generatingaself-signedcertificate

Rrfc5766-turn-server

about/Gettingreadyrootcertificates

about/Generatingaself-signedcertificatertc.io

used,forcreatingsimplevideochat/Makingasimplevideochatwithrtc.io,Howtodoit…

RTCMultiConnectionused,forcreatingapplication/CreatinganapplicationusingRTCMultiConnection,Howtodoit…,Howitworks…

Ssaturation

workingwith/Workingwithsaturation,Howtodoit…Sawbuck

about/UsingChromeloggingmechanismURL/UsingChromeloggingmechanism

screenshotcapturing/Takingascreenshot,Howtodoit…

SecureSocketsLayer(SSL)/Gettingreadysecurity

about/Introductionself-signedcertificate

generating/Generatingaself-signedcertificate,Gettingready,Howtodoit…sepiafilter

using/Usingthesepiafilter,Howtodoit…,Howitworks…server-sidecode,TURNserver

implementing/Implementingtheserver-sidecode,Howitworks…sessiondescription

about/IntroductionSessionDescriptionProtocol(SDP)

about/Howtodoit…signalingserver

about/Introductionbuilding/Introductionbuilding,inErlang/BuildingasignalingserverinErlang,Howtodoit…building,inJava/BuildingasignalingserverinJava,Howtodoit…

signalingstageabout/Introduction

simplevideochatcreating,withrtc.io/Makingasimplevideochatwithrtc.io,Howtodoit…

SimpleWebRTCabout/BuildingavideoconferenceusingSimpleWebRTCused,forbuildingvideoconference/Gettingready,Howtodoit…,Howitworks…

simpleWebRTCchatdeveloping,PeerJSused/DevelopingasimpleWebRTCchatusingPeerJS,Howtodoit…,Howitworks…

SIP.jsURL/There’smore…

sipML5about/InstallingsipML5,There’smore…installing/InstallingsipML5

SoftwareDevelopmentKit(SDK)/Introduction

Spring4about/There’smore…

statisticsAPIabout/Introduction

STUNabout/Introductionconfiguring/ConfiguringandusingSTUN,Howtodoit…using/Howitworks…

Ttcpdump/There’smore…Telephone

URL/InstallingsipML5TransportLayerSecurity(TLS)

about/GettingreadyTURN

about/Introductionconfiguring/ConfiguringandusingTURNinstalling/InstallingtheTURNserverbasicconfigurationitems/InstallingtheTURNserverusing,inWebRTCapplication/UsingTURNinWebRTCapplicationdebugging/DebuggingTURN,Howtodoit…

TURNRESTAPI/Howitworks…TurnServer

about/There’smore…URL/There’smore…

TURNserver,withauthenticationconfiguring/ConfiguringaTURNserverwithauthentication,Gettingreadyclient-sidecode,implementing/Implementingtheclient-sidecodeserver-sidecode,implementing/Implementingtheserver-sidecode,Howitworks…,There’smore…username/Howitworks…password/Howitworks…TTL/Howitworks…URIs/Howitworks…

UUseHostGPUoption/RunningontheAndroidsimulator

Vvideo

pausing/Pausingavideo,Howtodoit…videoconference

building,SimpleWebRTCused/BuildingavideoconferenceusingSimpleWebRTC,Howtodoit…,Howitworks…

WWebPlatformInstaller(WebPI)module/ConfiguringIISWebRTC

security/Introductionwebrtc-internals

about/Usingwebrtc-internalsWebRTCapplication

debugging,withChrome/DebuggingwithChrome,Gettingreadydebugging,withWireshark/DebuggingusingWireshark,Howtodoit…creating,OpenTokused/UsingOpenToktocreateaWebRTCapplication,Gettingready,Howtodoit…,Howitworks…

WebRTCfunctions,supportedbybrowserdetecting/DetectingWebRTCfunctionssupportedbyabrowser,Howitworks…

WebRTCintegrationabout/Introduction

WebRTCintegration,withAsteriskperforming/IntegratingWebRTCwithAsterisklibSRTP,installing/InstallinglibSRTPAsterisk,installing/InstallingAsteriskworking/Howitworks…about/There’smore…

WebRTCintegration,withFreeSWITCHperforming/IntegratingWebRTCwithFreeSWITCHFreeSWITCH,installing/InstallingFreeSWITCHWebRTC,enabling/EnablingWebRTCFreeSWITCH,starting/StartingFreeSWITCH

WebRTCintegration,withwebcamerasperforming/IntegrationofWebRTCwithwebcameras,Gettingreadywebcam,configuring/ConfiguringthewebcamWebRTCmediaserver/InstallingWebRTCmediaserver

WebRTCmediaserverimplementing/Timeformagic,Howitworks…

WebRTCOabout/CreatingamultiuserconferenceusingWebRTCOused,forcreatingmultiuserconference/Gettingready,Howtodoit…,Howitworks…

WebRTCstandarddraftURL/There’smore…

WebRTCstatisticsAPIworkingwith/WorkingwithaWebRTCstatisticsAPI,Howtodoit…,Howitworks…estimatedbandwidth,checking/Checkingestimatedbandwidth

packetloss,checking/Checkingpacketlosswebserver

configuring/ConfiguringawebservertoworkoverHTTPS,Howtodoit…WebSockets

about/ConfiguringaWebSocketsproxyonthewebserverWebSocketsproxyconfiguration

onwebserver/ConfiguringaWebSocketsproxyonthewebserver,Howitworks…Nginx,configuring/ConfiguringNginxApache,configuring/ConfiguringApacheIIS,configuring/ConfiguringIIS

Wiresharkabout/DebuggingusingWiresharkWebRTCapplication,debuggingwith/DebuggingusingWireshark,Howtodoit…URL/Gettingready

XX-Lite

URL/InstallingsipML5

ZZoiper

URL/InstallingsipML5