guidesandinformationforWebRTCdevelopers
First,let’sreviewthearchitectureofaWebRTCapplication.
Youhavetosetupsignalingcodeinordertoestablishthepeertopeerconnectionbetweentwopeers.Oncethesignalingiscomplete(whichtakesplaceovera3rdpartyserver),thenyouhaveaPeertoPeer(P2P)connectionbetweentwouserswhichcancontainvideoandaudiostreams,andadatachannel.
Thesignalingforbothprocessesisverysimilar,exceptthatifyouarebuildingaDataChannelonlyapplicationthenyoudon’tneedtocallGetUserMediaorexchangestreamswiththeotherpeer.
ThereareacoupleofotherdifferencesaboutusingtheDataChannel.Themostobviousoneisthatusersdon’tneedtogiveyoutheirpermissioninordertoestablishaDataChanneloveranRTCPeerConnectionobject.That’sdifferentthanvideoandaudio,whichwillpromptthebrowsertoasktheuserforpermissionstoturnontheircameraandmicrophone.
Althoughit’sgeneratingsomedebaterightnow,datachannelsdon’trequireexplicitpermissionfromusers.Thatmakesitsimilartoawebsocketconnection,whichcanbeusedinawebsitewithouttheknowledgeofusers.
TheDataChannelcanbeusedformanydifferentthings.Themostcommonexamplesareforimplementingtextchattogowithyourvideochat.Ifyou’realreadysettingupanRTCPeerConnectionforvideochat,thenyoumightaswellusethesameconnectiontosupplyaDataChannelfortextchatinsteadofsettingupadifferentsocketconnectionfortextchat.
Likewise,youcanusetheDataChannelfortransferringfilesdirectlybetweenyourpeersintheRTCPeerConnection.ThisisnicerthananormalsocketstyleconnectionbecausejustlikeWebRTCvideo,theDataChanneliscompletelypeer-to-peerandencryptedintransit.Soyourfiletransferismoresecurethaninotherarchitectures.
Don’tlimityourDataChannelimaginationbythesecommonexamplesthough.Inthispost,I’mgoingtoshowyouhowtousetheDataChanneltobuildaverysimpletwo-playergame.YoucanusetheDataChanneltotransferanytypeofdatayoulikebetweentwobrowsers,sointhiscasewe’lluseittosendcommandsanddatabetweentwoplayersofagameyoumightremembercalled“Memory”.
Inthegameofmemory,youcanflipoveracard,andthenflipasecondcard,andiftheymatch,youwinthatroundandthecardsstayfaceup.Iftheydidn’tmatch,youputbothfacedownagain,andit’sthenextperson’sturn.Bytryingtorememberwhatyouandyouropponentshavebeenflipping,andwherethosecardswere,youcanwinthegamebycorrectlyflippingthemostpairs.
InthisexampleviewofmymodifiedMemorygame,theuserhascorrectlyflippedpairsofF,D,andB,sothosecardswillstayfaceup.ThecardsKandLwerejustflippedanddidnotmatch,sotheywillgobackfacedown.
IstartedwithasimpleNodeJSapplicationtoserveupmycode,andIaddedinExpresstocreateasimplevisuallayer.Myprojectstructurelookslikethis:
Theimportantfilesforyoutolookataredatachannel.js(wherethemajorityoftheWebRTClogicis),memorygame.js(whereAdam’sgamejavascriptis,andwhichIhavemodifiedslightlytoaccommodatetheDataChannelcommunications),andindex.ejs,whichcontainsaverylightweightpresentationlayer.
Indatachannel.js,IhaveincludedsomelogictosetuptheDataChannel.Let’stakealookatthat:
TheconfigurationvariableiswhatwepassintotheRTCPeerConnectionobject,andwe’reusingapublicSTUNserverfromGoogle,whichyouoftenseeusedinWebRTCdemosonline.Googleiskindenoughtoletpeopleusethisfordemos,butrememberthatitisnotsuitableforpublicuseandifyouarebuildingarealappforproductionuse,youshouldlookintosettingupyourownserversorusingacommercialservicelikeXirsystoprovideproductionreadySTUNandTURNsignalingforyou.
Thenextsetofoptionswedefinearethedatachanneloptions.Youcanchoosefor“ordered”tobeeithertrueorfalse.
Whenyouspecify“ordered:true”,thenyouarespecifyingthatyouwantaReliableDataChannel.Thatmeansthatthepacketsareguaranteedtoallarriveinthecorrectorder,withoutanyloss,otherwisethewholetransactionwillfail.Thisisagoodideaforapplicationswherethereissignificantburdenifpacketsareoccasionallylostduetoapoorconnection.However,itcanslowdownyourapplicationalittlebit.
We’vesetorderedtofalse,whichmeansweareokaywithanUnreliableDataChannel.Ourcommandsarenotguaranteedtoallarrive,buttheyprobablywillunlessweareexperiencingpoorconnectivity.UnlessyoutaketheMemorygameveryseriouslyandhavemoneyontheline,it’sprobablynotabigdealifyouhavetoclicktwice.Unreliabledatachannelsarealittlefaster.
Finally,wesetamaxRetransmitTimebeforetheDataChannelwillfailandgiveuponthatpacket.Alternatively,wecouldhavespecifiedanumberformaxRetransmits,butwecan’tspecifybothconstraintstogether.
Thosearethemostcommonoptionsforadatachannel,butyoucanalsospecifytheprotocolifyouwantsomethingotherthanthedefaultSCTP,andyoucansetnegotiatedtotrueifyouwanttokeepWebRTCfromsettingupadatachannelontheotherside.Ifyouchoosetodothat,thenyoumightalsowanttosupplyyourownidforthedatachannel.Typicallyyouwon’tneedtosetanyoftheseoptions,leavethemattheirdefaultsbynotincludingthemintheconfigurationvariable.
Thenextsectionofcodemaybedifferentbasedonyourfavoriteoptions,butIhavechosentouseexpress.ioinmyproject,whichisasocket.iopackagefornodethatintegratesnicelywiththeexpresstemplatingengine.
SothenextbitofcodeishowI’musingsocket.iotosignaltoanyothersonthewebpagethatIamhereandreadytoplayagame.Again,noneofthisisspecifiedbyWebRTC.YoucanchoosetokickofftheWebRTCsignalingprocessinadifferentway.
Inthenextsegmentofdatachannel.js,I’vesetuptheeventhandlerforwhenadifferentvisitortothesitesendsoutasocket.iomessagethattheyarereadytoplay.
Thereareseveralthingsgoingonhere.ThefirstonetobeexecutedisthatifthertcPeerConnobjecthasnotbeeninitializedyet,thenwecallalocalfunctiontostartthesignalingprocess.SowhenVisitor2announcesthemselvesashere,theywillcauseVisitor1toreceivethatmessageandstartthesignalingprocess.
Ifthetypeofsocket.iomessageisnot“user_here”,whichissomethingIarbitrarilydefinedinmysocket.iolayerandnotpartofWebRTCsignaling,thenthecodegoesintoacoupleofWebRTCspecificsignalingscenarios–handlinganSDP“offer”thatwassentandcraftingthe“answer”tosendback,aswellashandlingICEcandidatesthatweresent.
Forcompleteness’sake,I’mincludingbelowtheremainderofthesignalingcode,includingthestartSignalingmethodreferredtopreviously.
ThiscodehandlessettinguptheeventhandlersontheRTCPeerConnectionobjectfordealingwithICEcandidatestoestablishthePeertoPeerconnection.
ThisblogpostisfocusedontheDataChannelmorethanthesignalingprocess,sothefollowinglinesintheabovecodearethemostimportantthingforustodiscusshere:
InthiscodewhatyouareseeingisthatafteranRTCPeerConnectionobjectiscreated,wetakeacoupleextrastepsthatarenotneededinthemorecommonWebRTCvideochatusecase.
FirstweaskthertcPeerConntoalsocreateaDataChannel,whichIarbitrarilynamed‘textMessages’,andIpassedinthosedataChannelOptionswedefinedpreviously.
ThenwejustdefinewheretosendtwoimportantDataChannelevents:onopenandondatachannel.Thesedobasicallywhatthenamesimply,solet’slookatthosetwoevents.
Whenthedatachannelisopened,we’vetoldtheRTCPeerConnectiontocalldataChannelStateChanged,whichinturntellsthedataChanneltocallanothermethodwe’vedefined,receiveDataChannelMessage,wheneveradatachannelmessageisreceived.
ThereceiveDataChannelmethodgetscalledwhenwereceiveadatachannelfromourpeer,sothatbothpartieshaveareferencetothesamedatachannel.Hereagain,wearealsosettingtheonmessageeventofthedatachanneltocallourmethodreceiveDataChannelMessagemethod.
Solet’slookatthatmethodforreceivingaDataChannelmessage:
Dependingonyourapplication,thismethodmightjustprintoutachatmessagetothescreen.Youcansendanycharactersyouwantoverthedatachannel,sohowyouparseandprocessthemonthereceivingendisuptoyou.
Inourcase,we’resendingacoupleofspecificcommandsaboutflippingtilesoverthedatachannel.Somyimplementationisparsingoutthestringonspaces,andassumingthefirstiteminthestringisthecommanditself.
Ifthecommandis“memoryFlipTile”,thenthisisthecommandtoflipthesametileonourscreenthatourpeerjustflippedontheirscreen.
Ifthecommandis“newBoard”,thenthatisthecommandfromourpeertosetupanewboardonourscreenwithallthecardsfacedown.Thepeerisalsosendingusastringifiedarrayofvaluestogooneachcardsothatourboardsmatch.Wesplitthatbackintoanarrayandsaveittoalocalvariable.
TheactualflipTheTileandnewBoardmethodsthatarecalledresideinthememorygame.jsfile,whichisessentiallythesamecodethatwe’vemodifiedfromAdam.
Inmemorygame.js,thefollowingfunctiontellstheDataChanneltoletourpeerknowwhichcardtoflip,aswellasflipsthecardonourownscreen:
Noticehowsimpleitistosendamessagetoourpeersusingthedatachannel–justcallthesendmethodandpassanystringyouwant.AmoresophisticatedexamplemightsendwellformattedXMLorJSONinamessage,inanyformatyouspecify.Inmycase,Ijustsendacommandfollowedbytheidofthetiletoflip,withaspacebetween.
InAdam’ssingleplayermemorygame,anewboardissetupwheneveryouloadthepage.Inmytwoplayeradaptation,Idecidedtohaveanewboardtriggeredbyabuttonclickinstead:
Inthiscase,theonlyimportantthingtonoticeisthatI’vedefineda“newBoard”stringtosendoverthedatachannel,andinthiscaseIwanttosendastringifiedversionofthearraycontainingthevaluestoputbehindeachcard.
That’sreallyallthereistoit!There’salotmorewecoulddotomakethisabettergame.Ihaven’tbuiltinanylogictolimitthegametotwoplayers,keepscorebyplayers,orenforcetheturnsbetweentheplayers.Butit’senoughtoshowyouthebasicideabehindusingtheWebRTCdatachanneltosendcommandsinamultiplayergame.
ThenicethingaboutbuildingagamelikethisthatusestheWebRTCdatachannelisit’sveryscalable.Allmywebsitehadtodoishelpthetwoplayersgetaconnectionsetup,andafterthat,allthedatatheyneedtoexchangewitheachotherisdoneoveranencryptedpeer-to-peerchannelanditwon’tburdenmywebserveratall.
Here’savideoshowingthegameinaction:
AsIhopethisexampleshowsyou,thehardpartofWebRTCdatachannelsisreallyjustinthesignalingandconfiguration,andthat’snottoohard.Onceyouhavethedatachannelsetup,sendingmessagesbackandforthisverysimple.Youcansendmessagesthatareassimpleorcomplexasyoulike.
Sources:
Youremailaddresswillnotbepublished.Requiredfieldsaremarked*
Comment*
Name*
Email*
Website
Savemyname,email,andwebsiteinthisbrowserforthenexttimeIcomment.