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<[email protected]>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<[email protected]>,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<[email protected]>withalinktothesuspectedpiratedmaterial.
Weappreciateyourhelpinprotectingourauthorsandourabilitytobringyouvaluablecontent.
QuestionsIfyouhaveaproblemwithanyaspectofthisbook,youcancontactusat<[email protected]>,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>
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
[email protected]: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
Top Related