| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779 | (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.adapter = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){/* *  Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * *  Use of this source code is governed by a BSD-style license *  that can be found in the LICENSE file in the root of the source *  tree. */ /* eslint-env node */'use strict';var SDPUtils = require('sdp');function writeMediaSection(transceiver, caps, type, stream, dtlsRole) {  var sdp = SDPUtils.writeRtpDescription(transceiver.kind, caps);  // Map ICE parameters (ufrag, pwd) to SDP.  sdp += SDPUtils.writeIceParameters(      transceiver.iceGatherer.getLocalParameters());  // Map DTLS parameters to SDP.  sdp += SDPUtils.writeDtlsParameters(      transceiver.dtlsTransport.getLocalParameters(),      type === 'offer' ? 'actpass' : dtlsRole || 'active');  sdp += 'a=mid:' + transceiver.mid + '\r\n';  if (transceiver.rtpSender && transceiver.rtpReceiver) {    sdp += 'a=sendrecv\r\n';  } else if (transceiver.rtpSender) {    sdp += 'a=sendonly\r\n';  } else if (transceiver.rtpReceiver) {    sdp += 'a=recvonly\r\n';  } else {    sdp += 'a=inactive\r\n';  }  if (transceiver.rtpSender) {    // spec.    var msid = 'msid:' + stream.id + ' ' +        transceiver.rtpSender.track.id + '\r\n';    sdp += 'a=' + msid;    // for Chrome.    sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc +        ' ' + msid;    if (transceiver.sendEncodingParameters[0].rtx) {      sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc +          ' ' + msid;      sdp += 'a=ssrc-group:FID ' +          transceiver.sendEncodingParameters[0].ssrc + ' ' +          transceiver.sendEncodingParameters[0].rtx.ssrc +          '\r\n';    }  }  // FIXME: this should be written by writeRtpDescription.  sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc +      ' cname:' + SDPUtils.localCName + '\r\n';  if (transceiver.rtpSender && transceiver.sendEncodingParameters[0].rtx) {    sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc +        ' cname:' + SDPUtils.localCName + '\r\n';  }  return sdp;}// Edge does not like// 1) stun: filtered after 14393 unless ?transport=udp is present// 2) turn: that does not have all of turn:host:port?transport=udp// 3) turn: with ipv6 addresses// 4) turn: occurring muliple timesfunction filterIceServers(iceServers, edgeVersion) {  var hasTurn = false;  iceServers = JSON.parse(JSON.stringify(iceServers));  return iceServers.filter(function(server) {    if (server && (server.urls || server.url)) {      var urls = server.urls || server.url;      if (server.url && !server.urls) {        console.warn('RTCIceServer.url is deprecated! Use urls instead.');      }      var isString = typeof urls === 'string';      if (isString) {        urls = [urls];      }      urls = urls.filter(function(url) {        var validTurn = url.indexOf('turn:') === 0 &&            url.indexOf('transport=udp') !== -1 &&            url.indexOf('turn:[') === -1 &&            !hasTurn;        if (validTurn) {          hasTurn = true;          return true;        }        return url.indexOf('stun:') === 0 && edgeVersion >= 14393 &&            url.indexOf('?transport=udp') === -1;      });      delete server.url;      server.urls = isString ? urls[0] : urls;      return !!urls.length;    }  });}// Determines the intersection of local and remote capabilities.function getCommonCapabilities(localCapabilities, remoteCapabilities) {  var commonCapabilities = {    codecs: [],    headerExtensions: [],    fecMechanisms: []  };  var findCodecByPayloadType = function(pt, codecs) {    pt = parseInt(pt, 10);    for (var i = 0; i < codecs.length; i++) {      if (codecs[i].payloadType === pt ||          codecs[i].preferredPayloadType === pt) {        return codecs[i];      }    }  };  var rtxCapabilityMatches = function(lRtx, rRtx, lCodecs, rCodecs) {    var lCodec = findCodecByPayloadType(lRtx.parameters.apt, lCodecs);    var rCodec = findCodecByPayloadType(rRtx.parameters.apt, rCodecs);    return lCodec && rCodec &&        lCodec.name.toLowerCase() === rCodec.name.toLowerCase();  };  localCapabilities.codecs.forEach(function(lCodec) {    for (var i = 0; i < remoteCapabilities.codecs.length; i++) {      var rCodec = remoteCapabilities.codecs[i];      if (lCodec.name.toLowerCase() === rCodec.name.toLowerCase() &&          lCodec.clockRate === rCodec.clockRate) {        if (lCodec.name.toLowerCase() === 'rtx' &&            lCodec.parameters && rCodec.parameters.apt) {          // for RTX we need to find the local rtx that has a apt          // which points to the same local codec as the remote one.          if (!rtxCapabilityMatches(lCodec, rCodec,              localCapabilities.codecs, remoteCapabilities.codecs)) {            continue;          }        }        rCodec = JSON.parse(JSON.stringify(rCodec)); // deepcopy        // number of channels is the highest common number of channels        rCodec.numChannels = Math.min(lCodec.numChannels,            rCodec.numChannels);        // push rCodec so we reply with offerer payload type        commonCapabilities.codecs.push(rCodec);        // determine common feedback mechanisms        rCodec.rtcpFeedback = rCodec.rtcpFeedback.filter(function(fb) {          for (var j = 0; j < lCodec.rtcpFeedback.length; j++) {            if (lCodec.rtcpFeedback[j].type === fb.type &&                lCodec.rtcpFeedback[j].parameter === fb.parameter) {              return true;            }          }          return false;        });        // FIXME: also need to determine .parameters        //  see https://github.com/openpeer/ortc/issues/569        break;      }    }  });  localCapabilities.headerExtensions.forEach(function(lHeaderExtension) {    for (var i = 0; i < remoteCapabilities.headerExtensions.length;         i++) {      var rHeaderExtension = remoteCapabilities.headerExtensions[i];      if (lHeaderExtension.uri === rHeaderExtension.uri) {        commonCapabilities.headerExtensions.push(rHeaderExtension);        break;      }    }  });  // FIXME: fecMechanisms  return commonCapabilities;}// is action=setLocalDescription with type allowed in signalingStatefunction isActionAllowedInSignalingState(action, type, signalingState) {  return {    offer: {      setLocalDescription: ['stable', 'have-local-offer'],      setRemoteDescription: ['stable', 'have-remote-offer']    },    answer: {      setLocalDescription: ['have-remote-offer', 'have-local-pranswer'],      setRemoteDescription: ['have-local-offer', 'have-remote-pranswer']    }  }[type][action].indexOf(signalingState) !== -1;}function maybeAddCandidate(iceTransport, candidate) {  // Edge's internal representation adds some fields therefore  // not all fieldѕ are taken into account.  var alreadyAdded = iceTransport.getRemoteCandidates()      .find(function(remoteCandidate) {        return candidate.foundation === remoteCandidate.foundation &&            candidate.ip === remoteCandidate.ip &&            candidate.port === remoteCandidate.port &&            candidate.priority === remoteCandidate.priority &&            candidate.protocol === remoteCandidate.protocol &&            candidate.type === remoteCandidate.type;      });  if (!alreadyAdded) {    iceTransport.addRemoteCandidate(candidate);  }  return !alreadyAdded;}// https://w3c.github.io/mediacapture-main/#mediastream// Helper function to add the track to the stream and// dispatch the event ourselves.function addTrackToStreamAndFireEvent(track, stream) {  stream.addTrack(track);  var e = new Event('addtrack'); // TODO: MediaStreamTrackEvent  e.track = track;  stream.dispatchEvent(e);}function removeTrackFromStreamAndFireEvent(track, stream) {  stream.removeTrack(track);  var e = new Event('removetrack'); // TODO: MediaStreamTrackEvent  e.track = track;  stream.dispatchEvent(e);}function fireAddTrack(pc, track, receiver, streams) {  var trackEvent = new Event('track');  trackEvent.track = track;  trackEvent.receiver = receiver;  trackEvent.transceiver = {receiver: receiver};  trackEvent.streams = streams;  window.setTimeout(function() {    pc._dispatchEvent('track', trackEvent);  });}function makeError(name, description) {  var e = new Error(description);  e.name = name;  return e;}module.exports = function(window, edgeVersion) {  var RTCPeerConnection = function(config) {    var pc = this;    var _eventTarget = document.createDocumentFragment();    ['addEventListener', 'removeEventListener', 'dispatchEvent']        .forEach(function(method) {          pc[method] = _eventTarget[method].bind(_eventTarget);        });    this.canTrickleIceCandidates = null;    this.needNegotiation = false;    this.localStreams = [];    this.remoteStreams = [];    this.localDescription = null;    this.remoteDescription = null;    this.signalingState = 'stable';    this.iceConnectionState = 'new';    this.iceGatheringState = 'new';    config = JSON.parse(JSON.stringify(config || {}));    this.usingBundle = config.bundlePolicy === 'max-bundle';    if (config.rtcpMuxPolicy === 'negotiate') {      throw(makeError('NotSupportedError',          'rtcpMuxPolicy \'negotiate\' is not supported'));    } else if (!config.rtcpMuxPolicy) {      config.rtcpMuxPolicy = 'require';    }    switch (config.iceTransportPolicy) {      case 'all':      case 'relay':        break;      default:        config.iceTransportPolicy = 'all';        break;    }    switch (config.bundlePolicy) {      case 'balanced':      case 'max-compat':      case 'max-bundle':        break;      default:        config.bundlePolicy = 'balanced';        break;    }    config.iceServers = filterIceServers(config.iceServers || [], edgeVersion);    this._iceGatherers = [];    if (config.iceCandidatePoolSize) {      for (var i = config.iceCandidatePoolSize; i > 0; i--) {        this._iceGatherers = new window.RTCIceGatherer({          iceServers: config.iceServers,          gatherPolicy: config.iceTransportPolicy        });      }    } else {      config.iceCandidatePoolSize = 0;    }    this._config = config;    // per-track iceGathers, iceTransports, dtlsTransports, rtpSenders, ...    // everything that is needed to describe a SDP m-line.    this.transceivers = [];    this._sdpSessionId = SDPUtils.generateSessionId();    this._sdpSessionVersion = 0;    this._dtlsRole = undefined; // role for a=setup to use in answers.    this._isClosed = false;  };  // set up event handlers on prototype  RTCPeerConnection.prototype.onicecandidate = null;  RTCPeerConnection.prototype.onaddstream = null;  RTCPeerConnection.prototype.ontrack = null;  RTCPeerConnection.prototype.onremovestream = null;  RTCPeerConnection.prototype.onsignalingstatechange = null;  RTCPeerConnection.prototype.oniceconnectionstatechange = null;  RTCPeerConnection.prototype.onicegatheringstatechange = null;  RTCPeerConnection.prototype.onnegotiationneeded = null;  RTCPeerConnection.prototype.ondatachannel = null;  RTCPeerConnection.prototype._dispatchEvent = function(name, event) {    if (this._isClosed) {      return;    }    this.dispatchEvent(event);    if (typeof this['on' + name] === 'function') {      this['on' + name](event);    }  };  RTCPeerConnection.prototype._emitGatheringStateChange = function() {    var event = new Event('icegatheringstatechange');    this._dispatchEvent('icegatheringstatechange', event);  };  RTCPeerConnection.prototype.getConfiguration = function() {    return this._config;  };  RTCPeerConnection.prototype.getLocalStreams = function() {    return this.localStreams;  };  RTCPeerConnection.prototype.getRemoteStreams = function() {    return this.remoteStreams;  };  // internal helper to create a transceiver object.  // (whih is not yet the same as the WebRTC 1.0 transceiver)  RTCPeerConnection.prototype._createTransceiver = function(kind) {    var hasBundleTransport = this.transceivers.length > 0;    var transceiver = {      track: null,      iceGatherer: null,      iceTransport: null,      dtlsTransport: null,      localCapabilities: null,      remoteCapabilities: null,      rtpSender: null,      rtpReceiver: null,      kind: kind,      mid: null,      sendEncodingParameters: null,      recvEncodingParameters: null,      stream: null,      associatedRemoteMediaStreams: [],      wantReceive: true    };    if (this.usingBundle && hasBundleTransport) {      transceiver.iceTransport = this.transceivers[0].iceTransport;      transceiver.dtlsTransport = this.transceivers[0].dtlsTransport;    } else {      var transports = this._createIceAndDtlsTransports();      transceiver.iceTransport = transports.iceTransport;      transceiver.dtlsTransport = transports.dtlsTransport;    }    this.transceivers.push(transceiver);    return transceiver;  };  RTCPeerConnection.prototype.addTrack = function(track, stream) {    var alreadyExists = this.transceivers.find(function(s) {      return s.track === track;    });    if (alreadyExists) {      throw makeError('InvalidAccessError', 'Track already exists.');    }    if (this.signalingState === 'closed') {      throw makeError('InvalidStateError',          'Attempted to call addTrack on a closed peerconnection.');    }    var transceiver;    for (var i = 0; i < this.transceivers.length; i++) {      if (!this.transceivers[i].track &&          this.transceivers[i].kind === track.kind) {        transceiver = this.transceivers[i];      }    }    if (!transceiver) {      transceiver = this._createTransceiver(track.kind);    }    this._maybeFireNegotiationNeeded();    if (this.localStreams.indexOf(stream) === -1) {      this.localStreams.push(stream);    }    transceiver.track = track;    transceiver.stream = stream;    transceiver.rtpSender = new window.RTCRtpSender(track,        transceiver.dtlsTransport);    return transceiver.rtpSender;  };  RTCPeerConnection.prototype.addStream = function(stream) {    var pc = this;    if (edgeVersion >= 15025) {      stream.getTracks().forEach(function(track) {        pc.addTrack(track, stream);      });    } else {      // Clone is necessary for local demos mostly, attaching directly      // to two different senders does not work (build 10547).      // Fixed in 15025 (or earlier)      var clonedStream = stream.clone();      stream.getTracks().forEach(function(track, idx) {        var clonedTrack = clonedStream.getTracks()[idx];        track.addEventListener('enabled', function(event) {          clonedTrack.enabled = event.enabled;        });      });      clonedStream.getTracks().forEach(function(track) {        pc.addTrack(track, clonedStream);      });    }  };  RTCPeerConnection.prototype.removeTrack = function(sender) {    if (!(sender instanceof window.RTCRtpSender)) {      throw new TypeError('Argument 1 of RTCPeerConnection.removeTrack ' +          'does not implement interface RTCRtpSender.');    }    var transceiver = this.transceivers.find(function(t) {      return t.rtpSender === sender;    });    if (!transceiver) {      throw makeError('InvalidAccessError',          'Sender was not created by this connection.');    }    var stream = transceiver.stream;    transceiver.rtpSender.stop();    transceiver.rtpSender = null;    transceiver.track = null;    transceiver.stream = null;    // remove the stream from the set of local streams    var localStreams = this.transceivers.map(function(t) {      return t.stream;    });    if (localStreams.indexOf(stream) === -1 &&        this.localStreams.indexOf(stream) > -1) {      this.localStreams.splice(this.localStreams.indexOf(stream), 1);    }    this._maybeFireNegotiationNeeded();  };  RTCPeerConnection.prototype.removeStream = function(stream) {    var pc = this;    stream.getTracks().forEach(function(track) {      var sender = pc.getSenders().find(function(s) {        return s.track === track;      });      if (sender) {        pc.removeTrack(sender);      }    });  };  RTCPeerConnection.prototype.getSenders = function() {    return this.transceivers.filter(function(transceiver) {      return !!transceiver.rtpSender;    })    .map(function(transceiver) {      return transceiver.rtpSender;    });  };  RTCPeerConnection.prototype.getReceivers = function() {    return this.transceivers.filter(function(transceiver) {      return !!transceiver.rtpReceiver;    })    .map(function(transceiver) {      return transceiver.rtpReceiver;    });  };  RTCPeerConnection.prototype._createIceGatherer = function(sdpMLineIndex,      usingBundle) {    var pc = this;    if (usingBundle && sdpMLineIndex > 0) {      return this.transceivers[0].iceGatherer;    } else if (this._iceGatherers.length) {      return this._iceGatherers.shift();    }    var iceGatherer = new window.RTCIceGatherer({      iceServers: this._config.iceServers,      gatherPolicy: this._config.iceTransportPolicy    });    Object.defineProperty(iceGatherer, 'state',        {value: 'new', writable: true}    );    this.transceivers[sdpMLineIndex].candidates = [];    this.transceivers[sdpMLineIndex].bufferCandidates = function(event) {      var end = !event.candidate || Object.keys(event.candidate).length === 0;      // polyfill since RTCIceGatherer.state is not implemented in      // Edge 10547 yet.      iceGatherer.state = end ? 'completed' : 'gathering';      if (pc.transceivers[sdpMLineIndex].candidates !== null) {        pc.transceivers[sdpMLineIndex].candidates.push(event.candidate);      }    };    iceGatherer.addEventListener('localcandidate',      this.transceivers[sdpMLineIndex].bufferCandidates);    return iceGatherer;  };  // start gathering from an RTCIceGatherer.  RTCPeerConnection.prototype._gather = function(mid, sdpMLineIndex) {    var pc = this;    var iceGatherer = this.transceivers[sdpMLineIndex].iceGatherer;    if (iceGatherer.onlocalcandidate) {      return;    }    var candidates = this.transceivers[sdpMLineIndex].candidates;    this.transceivers[sdpMLineIndex].candidates = null;    iceGatherer.removeEventListener('localcandidate',      this.transceivers[sdpMLineIndex].bufferCandidates);    iceGatherer.onlocalcandidate = function(evt) {      if (pc.usingBundle && sdpMLineIndex > 0) {        // if we know that we use bundle we can drop candidates with        // ѕdpMLineIndex > 0. If we don't do this then our state gets        // confused since we dispose the extra ice gatherer.        return;      }      var event = new Event('icecandidate');      event.candidate = {sdpMid: mid, sdpMLineIndex: sdpMLineIndex};      var cand = evt.candidate;      // Edge emits an empty object for RTCIceCandidateComplete‥      var end = !cand || Object.keys(cand).length === 0;      if (end) {        // polyfill since RTCIceGatherer.state is not implemented in        // Edge 10547 yet.        if (iceGatherer.state === 'new' || iceGatherer.state === 'gathering') {          iceGatherer.state = 'completed';        }      } else {        if (iceGatherer.state === 'new') {          iceGatherer.state = 'gathering';        }        // RTCIceCandidate doesn't have a component, needs to be added        cand.component = 1;        event.candidate.candidate = SDPUtils.writeCandidate(cand);      }      // update local description.      var sections = SDPUtils.splitSections(pc.localDescription.sdp);      if (!end) {        sections[event.candidate.sdpMLineIndex + 1] +=            'a=' + event.candidate.candidate + '\r\n';      } else {        sections[event.candidate.sdpMLineIndex + 1] +=            'a=end-of-candidates\r\n';      }      pc.localDescription.sdp = sections.join('');      var complete = pc.transceivers.every(function(transceiver) {        return transceiver.iceGatherer &&            transceiver.iceGatherer.state === 'completed';      });      if (pc.iceGatheringState !== 'gathering') {        pc.iceGatheringState = 'gathering';        pc._emitGatheringStateChange();      }      // Emit candidate. Also emit null candidate when all gatherers are      // complete.      if (!end) {        pc._dispatchEvent('icecandidate', event);      }      if (complete) {        pc._dispatchEvent('icecandidate', new Event('icecandidate'));        pc.iceGatheringState = 'complete';        pc._emitGatheringStateChange();      }    };    // emit already gathered candidates.    window.setTimeout(function() {      candidates.forEach(function(candidate) {        var e = new Event('RTCIceGatherEvent');        e.candidate = candidate;        iceGatherer.onlocalcandidate(e);      });    }, 0);  };  // Create ICE transport and DTLS transport.  RTCPeerConnection.prototype._createIceAndDtlsTransports = function() {    var pc = this;    var iceTransport = new window.RTCIceTransport(null);    iceTransport.onicestatechange = function() {      pc._updateConnectionState();    };    var dtlsTransport = new window.RTCDtlsTransport(iceTransport);    dtlsTransport.ondtlsstatechange = function() {      pc._updateConnectionState();    };    dtlsTransport.onerror = function() {      // onerror does not set state to failed by itpc.      Object.defineProperty(dtlsTransport, 'state',          {value: 'failed', writable: true});      pc._updateConnectionState();    };    return {      iceTransport: iceTransport,      dtlsTransport: dtlsTransport    };  };  // Destroy ICE gatherer, ICE transport and DTLS transport.  // Without triggering the callbacks.  RTCPeerConnection.prototype._disposeIceAndDtlsTransports = function(      sdpMLineIndex) {    var iceGatherer = this.transceivers[sdpMLineIndex].iceGatherer;    if (iceGatherer) {      delete iceGatherer.onlocalcandidate;      delete this.transceivers[sdpMLineIndex].iceGatherer;    }    var iceTransport = this.transceivers[sdpMLineIndex].iceTransport;    if (iceTransport) {      delete iceTransport.onicestatechange;      delete this.transceivers[sdpMLineIndex].iceTransport;    }    var dtlsTransport = this.transceivers[sdpMLineIndex].dtlsTransport;    if (dtlsTransport) {      delete dtlsTransport.ondtlsstatechange;      delete dtlsTransport.onerror;      delete this.transceivers[sdpMLineIndex].dtlsTransport;    }  };  // Start the RTP Sender and Receiver for a transceiver.  RTCPeerConnection.prototype._transceive = function(transceiver,      send, recv) {    var params = getCommonCapabilities(transceiver.localCapabilities,        transceiver.remoteCapabilities);    if (send && transceiver.rtpSender) {      params.encodings = transceiver.sendEncodingParameters;      params.rtcp = {        cname: SDPUtils.localCName,        compound: transceiver.rtcpParameters.compound      };      if (transceiver.recvEncodingParameters.length) {        params.rtcp.ssrc = transceiver.recvEncodingParameters[0].ssrc;      }      transceiver.rtpSender.send(params);    }    if (recv && transceiver.rtpReceiver && params.codecs.length > 0) {      // remove RTX field in Edge 14942      if (transceiver.kind === 'video'          && transceiver.recvEncodingParameters          && edgeVersion < 15019) {        transceiver.recvEncodingParameters.forEach(function(p) {          delete p.rtx;        });      }      if (transceiver.recvEncodingParameters.length) {        params.encodings = transceiver.recvEncodingParameters;      }      params.rtcp = {        compound: transceiver.rtcpParameters.compound      };      if (transceiver.rtcpParameters.cname) {        params.rtcp.cname = transceiver.rtcpParameters.cname;      }      if (transceiver.sendEncodingParameters.length) {        params.rtcp.ssrc = transceiver.sendEncodingParameters[0].ssrc;      }      transceiver.rtpReceiver.receive(params);    }  };  RTCPeerConnection.prototype.setLocalDescription = function(description) {    var pc = this;    if (!isActionAllowedInSignalingState('setLocalDescription',        description.type, this.signalingState) || this._isClosed) {      return Promise.reject(makeError('InvalidStateError',          'Can not set local ' + description.type +          ' in state ' + pc.signalingState));    }    var sections;    var sessionpart;    if (description.type === 'offer') {      // VERY limited support for SDP munging. Limited to:      // * changing the order of codecs      sections = SDPUtils.splitSections(description.sdp);      sessionpart = sections.shift();      sections.forEach(function(mediaSection, sdpMLineIndex) {        var caps = SDPUtils.parseRtpParameters(mediaSection);        pc.transceivers[sdpMLineIndex].localCapabilities = caps;      });      this.transceivers.forEach(function(transceiver, sdpMLineIndex) {        pc._gather(transceiver.mid, sdpMLineIndex);      });    } else if (description.type === 'answer') {      sections = SDPUtils.splitSections(pc.remoteDescription.sdp);      sessionpart = sections.shift();      var isIceLite = SDPUtils.matchPrefix(sessionpart,          'a=ice-lite').length > 0;      sections.forEach(function(mediaSection, sdpMLineIndex) {        var transceiver = pc.transceivers[sdpMLineIndex];        var iceGatherer = transceiver.iceGatherer;        var iceTransport = transceiver.iceTransport;        var dtlsTransport = transceiver.dtlsTransport;        var localCapabilities = transceiver.localCapabilities;        var remoteCapabilities = transceiver.remoteCapabilities;        // treat bundle-only as not-rejected.        var rejected = SDPUtils.isRejected(mediaSection) &&            SDPUtils.matchPrefix(mediaSection, 'a=bundle-only').length === 0;        if (!rejected && !transceiver.isDatachannel) {          var remoteIceParameters = SDPUtils.getIceParameters(              mediaSection, sessionpart);          var remoteDtlsParameters = SDPUtils.getDtlsParameters(              mediaSection, sessionpart);          if (isIceLite) {            remoteDtlsParameters.role = 'server';          }          if (!pc.usingBundle || sdpMLineIndex === 0) {            pc._gather(transceiver.mid, sdpMLineIndex);            if (iceTransport.state === 'new') {              iceTransport.start(iceGatherer, remoteIceParameters,                  isIceLite ? 'controlling' : 'controlled');            }            if (dtlsTransport.state === 'new') {              dtlsTransport.start(remoteDtlsParameters);            }          }          // Calculate intersection of capabilities.          var params = getCommonCapabilities(localCapabilities,              remoteCapabilities);          // Start the RTCRtpSender. The RTCRtpReceiver for this          // transceiver has already been started in setRemoteDescription.          pc._transceive(transceiver,              params.codecs.length > 0,              false);        }      });    }    this.localDescription = {      type: description.type,      sdp: description.sdp    };    switch (description.type) {      case 'offer':        this._updateSignalingState('have-local-offer');        break;      case 'answer':        this._updateSignalingState('stable');        break;      default:        throw new TypeError('unsupported type "' + description.type +            '"');    }    return Promise.resolve();  };  RTCPeerConnection.prototype.setRemoteDescription = function(description) {    var pc = this;    if (!isActionAllowedInSignalingState('setRemoteDescription',        description.type, this.signalingState) || this._isClosed) {      return Promise.reject(makeError('InvalidStateError',          'Can not set remote ' + description.type +          ' in state ' + pc.signalingState));    }    var streams = {};    this.remoteStreams.forEach(function(stream) {      streams[stream.id] = stream;    });    var receiverList = [];    var sections = SDPUtils.splitSections(description.sdp);    var sessionpart = sections.shift();    var isIceLite = SDPUtils.matchPrefix(sessionpart,        'a=ice-lite').length > 0;    var usingBundle = SDPUtils.matchPrefix(sessionpart,        'a=group:BUNDLE ').length > 0;    this.usingBundle = usingBundle;    var iceOptions = SDPUtils.matchPrefix(sessionpart,        'a=ice-options:')[0];    if (iceOptions) {      this.canTrickleIceCandidates = iceOptions.substr(14).split(' ')          .indexOf('trickle') >= 0;    } else {      this.canTrickleIceCandidates = false;    }    sections.forEach(function(mediaSection, sdpMLineIndex) {      var lines = SDPUtils.splitLines(mediaSection);      var kind = SDPUtils.getKind(mediaSection);      // treat bundle-only as not-rejected.      var rejected = SDPUtils.isRejected(mediaSection) &&          SDPUtils.matchPrefix(mediaSection, 'a=bundle-only').length === 0;      var protocol = lines[0].substr(2).split(' ')[2];      var direction = SDPUtils.getDirection(mediaSection, sessionpart);      var remoteMsid = SDPUtils.parseMsid(mediaSection);      var mid = SDPUtils.getMid(mediaSection) || SDPUtils.generateIdentifier();      // Reject datachannels which are not implemented yet.      if (kind === 'application' && protocol === 'DTLS/SCTP') {        pc.transceivers[sdpMLineIndex] = {          mid: mid,          isDatachannel: true        };        return;      }      var transceiver;      var iceGatherer;      var iceTransport;      var dtlsTransport;      var rtpReceiver;      var sendEncodingParameters;      var recvEncodingParameters;      var localCapabilities;      var track;      // FIXME: ensure the mediaSection has rtcp-mux set.      var remoteCapabilities = SDPUtils.parseRtpParameters(mediaSection);      var remoteIceParameters;      var remoteDtlsParameters;      if (!rejected) {        remoteIceParameters = SDPUtils.getIceParameters(mediaSection,            sessionpart);        remoteDtlsParameters = SDPUtils.getDtlsParameters(mediaSection,            sessionpart);        remoteDtlsParameters.role = 'client';      }      recvEncodingParameters =          SDPUtils.parseRtpEncodingParameters(mediaSection);      var rtcpParameters = SDPUtils.parseRtcpParameters(mediaSection);      var isComplete = SDPUtils.matchPrefix(mediaSection,          'a=end-of-candidates', sessionpart).length > 0;      var cands = SDPUtils.matchPrefix(mediaSection, 'a=candidate:')          .map(function(cand) {            return SDPUtils.parseCandidate(cand);          })          .filter(function(cand) {            return cand.component === 1;          });      // Check if we can use BUNDLE and dispose transports.      if ((description.type === 'offer' || description.type === 'answer') &&          !rejected && usingBundle && sdpMLineIndex > 0 &&          pc.transceivers[sdpMLineIndex]) {        pc._disposeIceAndDtlsTransports(sdpMLineIndex);        pc.transceivers[sdpMLineIndex].iceGatherer =            pc.transceivers[0].iceGatherer;        pc.transceivers[sdpMLineIndex].iceTransport =            pc.transceivers[0].iceTransport;        pc.transceivers[sdpMLineIndex].dtlsTransport =            pc.transceivers[0].dtlsTransport;        if (pc.transceivers[sdpMLineIndex].rtpSender) {          pc.transceivers[sdpMLineIndex].rtpSender.setTransport(              pc.transceivers[0].dtlsTransport);        }        if (pc.transceivers[sdpMLineIndex].rtpReceiver) {          pc.transceivers[sdpMLineIndex].rtpReceiver.setTransport(              pc.transceivers[0].dtlsTransport);        }      }      if (description.type === 'offer' && !rejected) {        transceiver = pc.transceivers[sdpMLineIndex] ||            pc._createTransceiver(kind);        transceiver.mid = mid;        if (!transceiver.iceGatherer) {          transceiver.iceGatherer = pc._createIceGatherer(sdpMLineIndex,              usingBundle);        }        if (cands.length && transceiver.iceTransport.state === 'new') {          if (isComplete && (!usingBundle || sdpMLineIndex === 0)) {            transceiver.iceTransport.setRemoteCandidates(cands);          } else {            cands.forEach(function(candidate) {              maybeAddCandidate(transceiver.iceTransport, candidate);            });          }        }        localCapabilities = window.RTCRtpReceiver.getCapabilities(kind);        // filter RTX until additional stuff needed for RTX is implemented        // in adapter.js        if (edgeVersion < 15019) {          localCapabilities.codecs = localCapabilities.codecs.filter(              function(codec) {                return codec.name !== 'rtx';              });        }        sendEncodingParameters = transceiver.sendEncodingParameters || [{          ssrc: (2 * sdpMLineIndex + 2) * 1001        }];        // TODO: rewrite to use http://w3c.github.io/webrtc-pc/#set-associated-remote-streams        var isNewTrack = false;        if (direction === 'sendrecv' || direction === 'sendonly') {          isNewTrack = !transceiver.rtpReceiver;          rtpReceiver = transceiver.rtpReceiver ||              new window.RTCRtpReceiver(transceiver.dtlsTransport, kind);          if (isNewTrack) {            var stream;            track = rtpReceiver.track;            // FIXME: does not work with Plan B.            if (remoteMsid && remoteMsid.stream === '-') {              // no-op. a stream id of '-' means: no associated stream.            } else if (remoteMsid) {              if (!streams[remoteMsid.stream]) {                streams[remoteMsid.stream] = new window.MediaStream();                Object.defineProperty(streams[remoteMsid.stream], 'id', {                  get: function() {                    return remoteMsid.stream;                  }                });              }              Object.defineProperty(track, 'id', {                get: function() {                  return remoteMsid.track;                }              });              stream = streams[remoteMsid.stream];            } else {              if (!streams.default) {                streams.default = new window.MediaStream();              }              stream = streams.default;            }            if (stream) {              addTrackToStreamAndFireEvent(track, stream);              transceiver.associatedRemoteMediaStreams.push(stream);            }            receiverList.push([track, rtpReceiver, stream]);          }        } else if (transceiver.rtpReceiver && transceiver.rtpReceiver.track) {          transceiver.associatedRemoteMediaStreams.forEach(function(s) {            var nativeTrack = s.getTracks().find(function(t) {              return t.id === transceiver.rtpReceiver.track.id;            });            if (nativeTrack) {              removeTrackFromStreamAndFireEvent(nativeTrack, s);            }          });          transceiver.associatedRemoteMediaStreams = [];        }        transceiver.localCapabilities = localCapabilities;        transceiver.remoteCapabilities = remoteCapabilities;        transceiver.rtpReceiver = rtpReceiver;        transceiver.rtcpParameters = rtcpParameters;        transceiver.sendEncodingParameters = sendEncodingParameters;        transceiver.recvEncodingParameters = recvEncodingParameters;        // Start the RTCRtpReceiver now. The RTPSender is started in        // setLocalDescription.        pc._transceive(pc.transceivers[sdpMLineIndex],            false,            isNewTrack);      } else if (description.type === 'answer' && !rejected) {        transceiver = pc.transceivers[sdpMLineIndex];        iceGatherer = transceiver.iceGatherer;        iceTransport = transceiver.iceTransport;        dtlsTransport = transceiver.dtlsTransport;        rtpReceiver = transceiver.rtpReceiver;        sendEncodingParameters = transceiver.sendEncodingParameters;        localCapabilities = transceiver.localCapabilities;        pc.transceivers[sdpMLineIndex].recvEncodingParameters =            recvEncodingParameters;        pc.transceivers[sdpMLineIndex].remoteCapabilities =            remoteCapabilities;        pc.transceivers[sdpMLineIndex].rtcpParameters = rtcpParameters;        if (cands.length && iceTransport.state === 'new') {          if ((isIceLite || isComplete) &&              (!usingBundle || sdpMLineIndex === 0)) {            iceTransport.setRemoteCandidates(cands);          } else {            cands.forEach(function(candidate) {              maybeAddCandidate(transceiver.iceTransport, candidate);            });          }        }        if (!usingBundle || sdpMLineIndex === 0) {          if (iceTransport.state === 'new') {            iceTransport.start(iceGatherer, remoteIceParameters,                'controlling');          }          if (dtlsTransport.state === 'new') {            dtlsTransport.start(remoteDtlsParameters);          }        }        pc._transceive(transceiver,            direction === 'sendrecv' || direction === 'recvonly',            direction === 'sendrecv' || direction === 'sendonly');        // TODO: rewrite to use http://w3c.github.io/webrtc-pc/#set-associated-remote-streams        if (rtpReceiver &&            (direction === 'sendrecv' || direction === 'sendonly')) {          track = rtpReceiver.track;          if (remoteMsid) {            if (!streams[remoteMsid.stream]) {              streams[remoteMsid.stream] = new window.MediaStream();            }            addTrackToStreamAndFireEvent(track, streams[remoteMsid.stream]);            receiverList.push([track, rtpReceiver, streams[remoteMsid.stream]]);          } else {            if (!streams.default) {              streams.default = new window.MediaStream();            }            addTrackToStreamAndFireEvent(track, streams.default);            receiverList.push([track, rtpReceiver, streams.default]);          }        } else {          // FIXME: actually the receiver should be created later.          delete transceiver.rtpReceiver;        }      }    });    if (this._dtlsRole === undefined) {      this._dtlsRole = description.type === 'offer' ? 'active' : 'passive';    }    this.remoteDescription = {      type: description.type,      sdp: description.sdp    };    switch (description.type) {      case 'offer':        this._updateSignalingState('have-remote-offer');        break;      case 'answer':        this._updateSignalingState('stable');        break;      default:        throw new TypeError('unsupported type "' + description.type +            '"');    }    Object.keys(streams).forEach(function(sid) {      var stream = streams[sid];      if (stream.getTracks().length) {        if (pc.remoteStreams.indexOf(stream) === -1) {          pc.remoteStreams.push(stream);          var event = new Event('addstream');          event.stream = stream;          window.setTimeout(function() {            pc._dispatchEvent('addstream', event);          });        }        receiverList.forEach(function(item) {          var track = item[0];          var receiver = item[1];          if (stream.id !== item[2].id) {            return;          }          fireAddTrack(pc, track, receiver, [stream]);        });      }    });    receiverList.forEach(function(item) {      if (item[2]) {        return;      }      fireAddTrack(pc, item[0], item[1], []);    });    // check whether addIceCandidate({}) was called within four seconds after    // setRemoteDescription.    window.setTimeout(function() {      if (!(pc && pc.transceivers)) {        return;      }      pc.transceivers.forEach(function(transceiver) {        if (transceiver.iceTransport &&            transceiver.iceTransport.state === 'new' &&            transceiver.iceTransport.getRemoteCandidates().length > 0) {          console.warn('Timeout for addRemoteCandidate. Consider sending ' +              'an end-of-candidates notification');          transceiver.iceTransport.addRemoteCandidate({});        }      });    }, 4000);    return Promise.resolve();  };  RTCPeerConnection.prototype.close = function() {    this.transceivers.forEach(function(transceiver) {      /* not yet      if (transceiver.iceGatherer) {        transceiver.iceGatherer.close();      }      */      if (transceiver.iceTransport) {        transceiver.iceTransport.stop();      }      if (transceiver.dtlsTransport) {        transceiver.dtlsTransport.stop();      }      if (transceiver.rtpSender) {        transceiver.rtpSender.stop();      }      if (transceiver.rtpReceiver) {        transceiver.rtpReceiver.stop();      }    });    // FIXME: clean up tracks, local streams, remote streams, etc    this._isClosed = true;    this._updateSignalingState('closed');  };  // Update the signaling state.  RTCPeerConnection.prototype._updateSignalingState = function(newState) {    this.signalingState = newState;    var event = new Event('signalingstatechange');    this._dispatchEvent('signalingstatechange', event);  };  // Determine whether to fire the negotiationneeded event.  RTCPeerConnection.prototype._maybeFireNegotiationNeeded = function() {    var pc = this;    if (this.signalingState !== 'stable' || this.needNegotiation === true) {      return;    }    this.needNegotiation = true;    window.setTimeout(function() {      if (pc.needNegotiation === false) {        return;      }      pc.needNegotiation = false;      var event = new Event('negotiationneeded');      pc._dispatchEvent('negotiationneeded', event);    }, 0);  };  // Update the connection state.  RTCPeerConnection.prototype._updateConnectionState = function() {    var newState;    var states = {      'new': 0,      closed: 0,      connecting: 0,      checking: 0,      connected: 0,      completed: 0,      disconnected: 0,      failed: 0    };    this.transceivers.forEach(function(transceiver) {      states[transceiver.iceTransport.state]++;      states[transceiver.dtlsTransport.state]++;    });    // ICETransport.completed and connected are the same for this purpose.    states.connected += states.completed;    newState = 'new';    if (states.failed > 0) {      newState = 'failed';    } else if (states.connecting > 0 || states.checking > 0) {      newState = 'connecting';    } else if (states.disconnected > 0) {      newState = 'disconnected';    } else if (states.new > 0) {      newState = 'new';    } else if (states.connected > 0 || states.completed > 0) {      newState = 'connected';    }    if (newState !== this.iceConnectionState) {      this.iceConnectionState = newState;      var event = new Event('iceconnectionstatechange');      this._dispatchEvent('iceconnectionstatechange', event);    }  };  RTCPeerConnection.prototype.createOffer = function() {    var pc = this;    if (this._isClosed) {      return Promise.reject(makeError('InvalidStateError',          'Can not call createOffer after close'));    }    var numAudioTracks = this.transceivers.filter(function(t) {      return t.kind === 'audio';    }).length;    var numVideoTracks = this.transceivers.filter(function(t) {      return t.kind === 'video';    }).length;    // Determine number of audio and video tracks we need to send/recv.    var offerOptions = arguments[0];    if (offerOptions) {      // Reject Chrome legacy constraints.      if (offerOptions.mandatory || offerOptions.optional) {        throw new TypeError(            'Legacy mandatory/optional constraints not supported.');      }      if (offerOptions.offerToReceiveAudio !== undefined) {        if (offerOptions.offerToReceiveAudio === true) {          numAudioTracks = 1;        } else if (offerOptions.offerToReceiveAudio === false) {          numAudioTracks = 0;        } else {          numAudioTracks = offerOptions.offerToReceiveAudio;        }      }      if (offerOptions.offerToReceiveVideo !== undefined) {        if (offerOptions.offerToReceiveVideo === true) {          numVideoTracks = 1;        } else if (offerOptions.offerToReceiveVideo === false) {          numVideoTracks = 0;        } else {          numVideoTracks = offerOptions.offerToReceiveVideo;        }      }    }    this.transceivers.forEach(function(transceiver) {      if (transceiver.kind === 'audio') {        numAudioTracks--;        if (numAudioTracks < 0) {          transceiver.wantReceive = false;        }      } else if (transceiver.kind === 'video') {        numVideoTracks--;        if (numVideoTracks < 0) {          transceiver.wantReceive = false;        }      }    });    // Create M-lines for recvonly streams.    while (numAudioTracks > 0 || numVideoTracks > 0) {      if (numAudioTracks > 0) {        this._createTransceiver('audio');        numAudioTracks--;      }      if (numVideoTracks > 0) {        this._createTransceiver('video');        numVideoTracks--;      }    }    var sdp = SDPUtils.writeSessionBoilerplate(this._sdpSessionId,        this._sdpSessionVersion++);    this.transceivers.forEach(function(transceiver, sdpMLineIndex) {      // For each track, create an ice gatherer, ice transport,      // dtls transport, potentially rtpsender and rtpreceiver.      var track = transceiver.track;      var kind = transceiver.kind;      var mid = SDPUtils.generateIdentifier();      transceiver.mid = mid;      if (!transceiver.iceGatherer) {        transceiver.iceGatherer = pc._createIceGatherer(sdpMLineIndex,            pc.usingBundle);      }      var localCapabilities = window.RTCRtpSender.getCapabilities(kind);      // filter RTX until additional stuff needed for RTX is implemented      // in adapter.js      if (edgeVersion < 15019) {        localCapabilities.codecs = localCapabilities.codecs.filter(            function(codec) {              return codec.name !== 'rtx';            });      }      localCapabilities.codecs.forEach(function(codec) {        // work around https://bugs.chromium.org/p/webrtc/issues/detail?id=6552        // by adding level-asymmetry-allowed=1        if (codec.name === 'H264' &&            codec.parameters['level-asymmetry-allowed'] === undefined) {          codec.parameters['level-asymmetry-allowed'] = '1';        }      });      // generate an ssrc now, to be used later in rtpSender.send      var sendEncodingParameters = transceiver.sendEncodingParameters || [{        ssrc: (2 * sdpMLineIndex + 1) * 1001      }];      if (track) {        // add RTX        if (edgeVersion >= 15019 && kind === 'video' &&            !sendEncodingParameters[0].rtx) {          sendEncodingParameters[0].rtx = {            ssrc: sendEncodingParameters[0].ssrc + 1          };        }      }      if (transceiver.wantReceive) {        transceiver.rtpReceiver = new window.RTCRtpReceiver(            transceiver.dtlsTransport, kind);      }      transceiver.localCapabilities = localCapabilities;      transceiver.sendEncodingParameters = sendEncodingParameters;    });    // always offer BUNDLE and dispose on return if not supported.    if (this._config.bundlePolicy !== 'max-compat') {      sdp += 'a=group:BUNDLE ' + this.transceivers.map(function(t) {        return t.mid;      }).join(' ') + '\r\n';    }    sdp += 'a=ice-options:trickle\r\n';    this.transceivers.forEach(function(transceiver, sdpMLineIndex) {      sdp += writeMediaSection(transceiver, transceiver.localCapabilities,          'offer', transceiver.stream, pc._dtlsRole);      sdp += 'a=rtcp-rsize\r\n';      if (transceiver.iceGatherer && pc.iceGatheringState !== 'new' &&          (sdpMLineIndex === 0 || !pc.usingBundle)) {        transceiver.iceGatherer.getLocalCandidates().forEach(function(cand) {          cand.component = 1;          sdp += 'a=' + SDPUtils.writeCandidate(cand) + '\r\n';        });        if (transceiver.iceGatherer.state === 'completed') {          sdp += 'a=end-of-candidates\r\n';        }      }    });    var desc = new window.RTCSessionDescription({      type: 'offer',      sdp: sdp    });    return Promise.resolve(desc);  };  RTCPeerConnection.prototype.createAnswer = function() {    var pc = this;    if (this._isClosed) {      return Promise.reject(makeError('InvalidStateError',          'Can not call createAnswer after close'));    }    var sdp = SDPUtils.writeSessionBoilerplate(this._sdpSessionId,        this._sdpSessionVersion++);    if (this.usingBundle) {      sdp += 'a=group:BUNDLE ' + this.transceivers.map(function(t) {        return t.mid;      }).join(' ') + '\r\n';    }    var mediaSectionsInOffer = SDPUtils.splitSections(        this.remoteDescription.sdp).length - 1;    this.transceivers.forEach(function(transceiver, sdpMLineIndex) {      if (sdpMLineIndex + 1 > mediaSectionsInOffer) {        return;      }      if (transceiver.isDatachannel) {        sdp += 'm=application 0 DTLS/SCTP 5000\r\n' +            'c=IN IP4 0.0.0.0\r\n' +            'a=mid:' + transceiver.mid + '\r\n';        return;      }      // FIXME: look at direction.      if (transceiver.stream) {        var localTrack;        if (transceiver.kind === 'audio') {          localTrack = transceiver.stream.getAudioTracks()[0];        } else if (transceiver.kind === 'video') {          localTrack = transceiver.stream.getVideoTracks()[0];        }        if (localTrack) {          // add RTX          if (edgeVersion >= 15019 && transceiver.kind === 'video' &&              !transceiver.sendEncodingParameters[0].rtx) {            transceiver.sendEncodingParameters[0].rtx = {              ssrc: transceiver.sendEncodingParameters[0].ssrc + 1            };          }        }      }      // Calculate intersection of capabilities.      var commonCapabilities = getCommonCapabilities(          transceiver.localCapabilities,          transceiver.remoteCapabilities);      var hasRtx = commonCapabilities.codecs.filter(function(c) {        return c.name.toLowerCase() === 'rtx';      }).length;      if (!hasRtx && transceiver.sendEncodingParameters[0].rtx) {        delete transceiver.sendEncodingParameters[0].rtx;      }      sdp += writeMediaSection(transceiver, commonCapabilities,          'answer', transceiver.stream, pc._dtlsRole);      if (transceiver.rtcpParameters &&          transceiver.rtcpParameters.reducedSize) {        sdp += 'a=rtcp-rsize\r\n';      }    });    var desc = new window.RTCSessionDescription({      type: 'answer',      sdp: sdp    });    return Promise.resolve(desc);  };  RTCPeerConnection.prototype.addIceCandidate = function(candidate) {    var sections;    if (!candidate || candidate.candidate === '') {      for (var j = 0; j < this.transceivers.length; j++) {        if (this.transceivers[j].isDatachannel) {          continue;        }        this.transceivers[j].iceTransport.addRemoteCandidate({});        sections = SDPUtils.splitSections(this.remoteDescription.sdp);        sections[j + 1] += 'a=end-of-candidates\r\n';        this.remoteDescription.sdp = sections.join('');        if (this.usingBundle) {          break;        }      }    } else if (!(candidate.sdpMLineIndex !== undefined || candidate.sdpMid)) {      throw new TypeError('sdpMLineIndex or sdpMid required');    } else if (!this.remoteDescription) {      return Promise.reject(makeError('InvalidStateError',          'Can not add ICE candidate without a remote description'));    } else {      var sdpMLineIndex = candidate.sdpMLineIndex;      if (candidate.sdpMid) {        for (var i = 0; i < this.transceivers.length; i++) {          if (this.transceivers[i].mid === candidate.sdpMid) {            sdpMLineIndex = i;            break;          }        }      }      var transceiver = this.transceivers[sdpMLineIndex];      if (transceiver) {        if (transceiver.isDatachannel) {          return Promise.resolve();        }        var cand = Object.keys(candidate.candidate).length > 0 ?            SDPUtils.parseCandidate(candidate.candidate) : {};        // Ignore Chrome's invalid candidates since Edge does not like them.        if (cand.protocol === 'tcp' && (cand.port === 0 || cand.port === 9)) {          return Promise.resolve();        }        // Ignore RTCP candidates, we assume RTCP-MUX.        if (cand.component && cand.component !== 1) {          return Promise.resolve();        }        // when using bundle, avoid adding candidates to the wrong        // ice transport. And avoid adding candidates added in the SDP.        if (sdpMLineIndex === 0 || (sdpMLineIndex > 0 &&            transceiver.iceTransport !== this.transceivers[0].iceTransport)) {          if (!maybeAddCandidate(transceiver.iceTransport, cand)) {            return Promise.reject(makeError('OperationError',                'Can not add ICE candidate'));          }        }        // update the remoteDescription.        var candidateString = candidate.candidate.trim();        if (candidateString.indexOf('a=') === 0) {          candidateString = candidateString.substr(2);        }        sections = SDPUtils.splitSections(this.remoteDescription.sdp);        sections[sdpMLineIndex + 1] += 'a=' +            (cand.type ? candidateString : 'end-of-candidates')            + '\r\n';        this.remoteDescription.sdp = sections.join('');      } else {        return Promise.reject(makeError('OperationError',            'Can not add ICE candidate'));      }    }    return Promise.resolve();  };  RTCPeerConnection.prototype.getStats = function() {    var promises = [];    this.transceivers.forEach(function(transceiver) {      ['rtpSender', 'rtpReceiver', 'iceGatherer', 'iceTransport',          'dtlsTransport'].forEach(function(method) {            if (transceiver[method]) {              promises.push(transceiver[method].getStats());            }          });    });    var fixStatsType = function(stat) {      return {        inboundrtp: 'inbound-rtp',        outboundrtp: 'outbound-rtp',        candidatepair: 'candidate-pair',        localcandidate: 'local-candidate',        remotecandidate: 'remote-candidate'      }[stat.type] || stat.type;    };    return new Promise(function(resolve) {      // shim getStats with maplike support      var results = new Map();      Promise.all(promises).then(function(res) {        res.forEach(function(result) {          Object.keys(result).forEach(function(id) {            result[id].type = fixStatsType(result[id]);            results.set(id, result[id]);          });        });        resolve(results);      });    });  };  // legacy callback shims. Should be moved to adapter.js some days.  var methods = ['createOffer', 'createAnswer'];  methods.forEach(function(method) {    var nativeMethod = RTCPeerConnection.prototype[method];    RTCPeerConnection.prototype[method] = function() {      var args = arguments;      if (typeof args[0] === 'function' ||          typeof args[1] === 'function') { // legacy        return nativeMethod.apply(this, [arguments[2]])        .then(function(description) {          if (typeof args[0] === 'function') {            args[0].apply(null, [description]);          }        }, function(error) {          if (typeof args[1] === 'function') {            args[1].apply(null, [error]);          }        });      }      return nativeMethod.apply(this, arguments);    };  });  methods = ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'];  methods.forEach(function(method) {    var nativeMethod = RTCPeerConnection.prototype[method];    RTCPeerConnection.prototype[method] = function() {      var args = arguments;      if (typeof args[1] === 'function' ||          typeof args[2] === 'function') { // legacy        return nativeMethod.apply(this, arguments)        .then(function() {          if (typeof args[1] === 'function') {            args[1].apply(null);          }        }, function(error) {          if (typeof args[2] === 'function') {            args[2].apply(null, [error]);          }        });      }      return nativeMethod.apply(this, arguments);    };  });  // getStats is special. It doesn't have a spec legacy method yet we support  // getStats(something, cb) without error callbacks.  ['getStats'].forEach(function(method) {    var nativeMethod = RTCPeerConnection.prototype[method];    RTCPeerConnection.prototype[method] = function() {      var args = arguments;      if (typeof args[1] === 'function') {        return nativeMethod.apply(this, arguments)        .then(function() {          if (typeof args[1] === 'function') {            args[1].apply(null);          }        });      }      return nativeMethod.apply(this, arguments);    };  });  return RTCPeerConnection;};},{"sdp":2}],2:[function(require,module,exports){ /* eslint-env node */'use strict';// SDP helpers.var SDPUtils = {};// Generate an alphanumeric identifier for cname or mids.// TODO: use UUIDs instead? https://gist.github.com/jed/982883SDPUtils.generateIdentifier = function() {  return Math.random().toString(36).substr(2, 10);};// The RTCP CNAME used by all peerconnections from the same JS.SDPUtils.localCName = SDPUtils.generateIdentifier();// Splits SDP into lines, dealing with both CRLF and LF.SDPUtils.splitLines = function(blob) {  return blob.trim().split('\n').map(function(line) {    return line.trim();  });};// Splits SDP into sessionpart and mediasections. Ensures CRLF.SDPUtils.splitSections = function(blob) {  var parts = blob.split('\nm=');  return parts.map(function(part, index) {    return (index > 0 ? 'm=' + part : part).trim() + '\r\n';  });};// Returns lines that start with a certain prefix.SDPUtils.matchPrefix = function(blob, prefix) {  return SDPUtils.splitLines(blob).filter(function(line) {    return line.indexOf(prefix) === 0;  });};// Parses an ICE candidate line. Sample input:// candidate:702786350 2 udp 41819902 8.8.8.8 60769 typ relay raddr 8.8.8.8// rport 55996"SDPUtils.parseCandidate = function(line) {  var parts;  // Parse both variants.  if (line.indexOf('a=candidate:') === 0) {    parts = line.substring(12).split(' ');  } else {    parts = line.substring(10).split(' ');  }  var candidate = {    foundation: parts[0],    component: parseInt(parts[1], 10),    protocol: parts[2].toLowerCase(),    priority: parseInt(parts[3], 10),    ip: parts[4],    port: parseInt(parts[5], 10),    // skip parts[6] == 'typ'    type: parts[7]  };  for (var i = 8; i < parts.length; i += 2) {    switch (parts[i]) {      case 'raddr':        candidate.relatedAddress = parts[i + 1];        break;      case 'rport':        candidate.relatedPort = parseInt(parts[i + 1], 10);        break;      case 'tcptype':        candidate.tcpType = parts[i + 1];        break;      case 'ufrag':        candidate.ufrag = parts[i + 1]; // for backward compability.        candidate.usernameFragment = parts[i + 1];        break;      default: // extension handling, in particular ufrag        candidate[parts[i]] = parts[i + 1];        break;    }  }  return candidate;};// Translates a candidate object into SDP candidate attribute.SDPUtils.writeCandidate = function(candidate) {  var sdp = [];  sdp.push(candidate.foundation);  sdp.push(candidate.component);  sdp.push(candidate.protocol.toUpperCase());  sdp.push(candidate.priority);  sdp.push(candidate.ip);  sdp.push(candidate.port);  var type = candidate.type;  sdp.push('typ');  sdp.push(type);  if (type !== 'host' && candidate.relatedAddress &&      candidate.relatedPort) {    sdp.push('raddr');    sdp.push(candidate.relatedAddress); // was: relAddr    sdp.push('rport');    sdp.push(candidate.relatedPort); // was: relPort  }  if (candidate.tcpType && candidate.protocol.toLowerCase() === 'tcp') {    sdp.push('tcptype');    sdp.push(candidate.tcpType);  }  if (candidate.ufrag) {    sdp.push('ufrag');    sdp.push(candidate.ufrag);  }  return 'candidate:' + sdp.join(' ');};// Parses an ice-options line, returns an array of option tags.// a=ice-options:foo barSDPUtils.parseIceOptions = function(line) {  return line.substr(14).split(' ');}// Parses an rtpmap line, returns RTCRtpCoddecParameters. Sample input:// a=rtpmap:111 opus/48000/2SDPUtils.parseRtpMap = function(line) {  var parts = line.substr(9).split(' ');  var parsed = {    payloadType: parseInt(parts.shift(), 10) // was: id  };  parts = parts[0].split('/');  parsed.name = parts[0];  parsed.clockRate = parseInt(parts[1], 10); // was: clockrate  // was: channels  parsed.numChannels = parts.length === 3 ? parseInt(parts[2], 10) : 1;  return parsed;};// Generate an a=rtpmap line from RTCRtpCodecCapability or// RTCRtpCodecParameters.SDPUtils.writeRtpMap = function(codec) {  var pt = codec.payloadType;  if (codec.preferredPayloadType !== undefined) {    pt = codec.preferredPayloadType;  }  return 'a=rtpmap:' + pt + ' ' + codec.name + '/' + codec.clockRate +      (codec.numChannels !== 1 ? '/' + codec.numChannels : '') + '\r\n';};// Parses an a=extmap line (headerextension from RFC 5285). Sample input:// a=extmap:2 urn:ietf:params:rtp-hdrext:toffset// a=extmap:2/sendonly urn:ietf:params:rtp-hdrext:toffsetSDPUtils.parseExtmap = function(line) {  var parts = line.substr(9).split(' ');  return {    id: parseInt(parts[0], 10),    direction: parts[0].indexOf('/') > 0 ? parts[0].split('/')[1] : 'sendrecv',    uri: parts[1]  };};// Generates a=extmap line from RTCRtpHeaderExtensionParameters or// RTCRtpHeaderExtension.SDPUtils.writeExtmap = function(headerExtension) {  return 'a=extmap:' + (headerExtension.id || headerExtension.preferredId) +      (headerExtension.direction && headerExtension.direction !== 'sendrecv'          ? '/' + headerExtension.direction          : '') +      ' ' + headerExtension.uri + '\r\n';};// Parses an ftmp line, returns dictionary. Sample input:// a=fmtp:96 vbr=on;cng=on// Also deals with vbr=on; cng=onSDPUtils.parseFmtp = function(line) {  var parsed = {};  var kv;  var parts = line.substr(line.indexOf(' ') + 1).split(';');  for (var j = 0; j < parts.length; j++) {    kv = parts[j].trim().split('=');    parsed[kv[0].trim()] = kv[1];  }  return parsed;};// Generates an a=ftmp line from RTCRtpCodecCapability or RTCRtpCodecParameters.SDPUtils.writeFmtp = function(codec) {  var line = '';  var pt = codec.payloadType;  if (codec.preferredPayloadType !== undefined) {    pt = codec.preferredPayloadType;  }  if (codec.parameters && Object.keys(codec.parameters).length) {    var params = [];    Object.keys(codec.parameters).forEach(function(param) {      params.push(param + '=' + codec.parameters[param]);    });    line += 'a=fmtp:' + pt + ' ' + params.join(';') + '\r\n';  }  return line;};// Parses an rtcp-fb line, returns RTCPRtcpFeedback object. Sample input:// a=rtcp-fb:98 nack rpsiSDPUtils.parseRtcpFb = function(line) {  var parts = line.substr(line.indexOf(' ') + 1).split(' ');  return {    type: parts.shift(),    parameter: parts.join(' ')  };};// Generate a=rtcp-fb lines from RTCRtpCodecCapability or RTCRtpCodecParameters.SDPUtils.writeRtcpFb = function(codec) {  var lines = '';  var pt = codec.payloadType;  if (codec.preferredPayloadType !== undefined) {    pt = codec.preferredPayloadType;  }  if (codec.rtcpFeedback && codec.rtcpFeedback.length) {    // FIXME: special handling for trr-int?    codec.rtcpFeedback.forEach(function(fb) {      lines += 'a=rtcp-fb:' + pt + ' ' + fb.type +      (fb.parameter && fb.parameter.length ? ' ' + fb.parameter : '') +          '\r\n';    });  }  return lines;};// Parses an RFC 5576 ssrc media attribute. Sample input:// a=ssrc:3735928559 cname:somethingSDPUtils.parseSsrcMedia = function(line) {  var sp = line.indexOf(' ');  var parts = {    ssrc: parseInt(line.substr(7, sp - 7), 10)  };  var colon = line.indexOf(':', sp);  if (colon > -1) {    parts.attribute = line.substr(sp + 1, colon - sp - 1);    parts.value = line.substr(colon + 1);  } else {    parts.attribute = line.substr(sp + 1);  }  return parts;};// Extracts the MID (RFC 5888) from a media section.// returns the MID or undefined if no mid line was found.SDPUtils.getMid = function(mediaSection) {  var mid = SDPUtils.matchPrefix(mediaSection, 'a=mid:')[0];  if (mid) {    return mid.substr(6);  }}SDPUtils.parseFingerprint = function(line) {  var parts = line.substr(14).split(' ');  return {    algorithm: parts[0].toLowerCase(), // algorithm is case-sensitive in Edge.    value: parts[1]  };};// Extracts DTLS parameters from SDP media section or sessionpart.// FIXME: for consistency with other functions this should only//   get the fingerprint line as input. See also getIceParameters.SDPUtils.getDtlsParameters = function(mediaSection, sessionpart) {  var lines = SDPUtils.matchPrefix(mediaSection + sessionpart,      'a=fingerprint:');  // Note: a=setup line is ignored since we use the 'auto' role.  // Note2: 'algorithm' is not case sensitive except in Edge.  return {    role: 'auto',    fingerprints: lines.map(SDPUtils.parseFingerprint)  };};// Serializes DTLS parameters to SDP.SDPUtils.writeDtlsParameters = function(params, setupType) {  var sdp = 'a=setup:' + setupType + '\r\n';  params.fingerprints.forEach(function(fp) {    sdp += 'a=fingerprint:' + fp.algorithm + ' ' + fp.value + '\r\n';  });  return sdp;};// Parses ICE information from SDP media section or sessionpart.// FIXME: for consistency with other functions this should only//   get the ice-ufrag and ice-pwd lines as input.SDPUtils.getIceParameters = function(mediaSection, sessionpart) {  var lines = SDPUtils.splitLines(mediaSection);  // Search in session part, too.  lines = lines.concat(SDPUtils.splitLines(sessionpart));  var iceParameters = {    usernameFragment: lines.filter(function(line) {      return line.indexOf('a=ice-ufrag:') === 0;    })[0].substr(12),    password: lines.filter(function(line) {      return line.indexOf('a=ice-pwd:') === 0;    })[0].substr(10)  };  return iceParameters;};// Serializes ICE parameters to SDP.SDPUtils.writeIceParameters = function(params) {  return 'a=ice-ufrag:' + params.usernameFragment + '\r\n' +      'a=ice-pwd:' + params.password + '\r\n';};// Parses the SDP media section and returns RTCRtpParameters.SDPUtils.parseRtpParameters = function(mediaSection) {  var description = {    codecs: [],    headerExtensions: [],    fecMechanisms: [],    rtcp: []  };  var lines = SDPUtils.splitLines(mediaSection);  var mline = lines[0].split(' ');  for (var i = 3; i < mline.length; i++) { // find all codecs from mline[3..]    var pt = mline[i];    var rtpmapline = SDPUtils.matchPrefix(        mediaSection, 'a=rtpmap:' + pt + ' ')[0];    if (rtpmapline) {      var codec = SDPUtils.parseRtpMap(rtpmapline);      var fmtps = SDPUtils.matchPrefix(          mediaSection, 'a=fmtp:' + pt + ' ');      // Only the first a=fmtp:<pt> is considered.      codec.parameters = fmtps.length ? SDPUtils.parseFmtp(fmtps[0]) : {};      codec.rtcpFeedback = SDPUtils.matchPrefix(          mediaSection, 'a=rtcp-fb:' + pt + ' ')        .map(SDPUtils.parseRtcpFb);      description.codecs.push(codec);      // parse FEC mechanisms from rtpmap lines.      switch (codec.name.toUpperCase()) {        case 'RED':        case 'ULPFEC':          description.fecMechanisms.push(codec.name.toUpperCase());          break;        default: // only RED and ULPFEC are recognized as FEC mechanisms.          break;      }    }  }  SDPUtils.matchPrefix(mediaSection, 'a=extmap:').forEach(function(line) {    description.headerExtensions.push(SDPUtils.parseExtmap(line));  });  // FIXME: parse rtcp.  return description;};// Generates parts of the SDP media section describing the capabilities /// parameters.SDPUtils.writeRtpDescription = function(kind, caps) {  var sdp = '';  // Build the mline.  sdp += 'm=' + kind + ' ';  sdp += caps.codecs.length > 0 ? '9' : '0'; // reject if no codecs.  sdp += ' UDP/TLS/RTP/SAVPF ';  sdp += caps.codecs.map(function(codec) {    if (codec.preferredPayloadType !== undefined) {      return codec.preferredPayloadType;    }    return codec.payloadType;  }).join(' ') + '\r\n';  sdp += 'c=IN IP4 0.0.0.0\r\n';  sdp += 'a=rtcp:9 IN IP4 0.0.0.0\r\n';  // Add a=rtpmap lines for each codec. Also fmtp and rtcp-fb.  caps.codecs.forEach(function(codec) {    sdp += SDPUtils.writeRtpMap(codec);    sdp += SDPUtils.writeFmtp(codec);    sdp += SDPUtils.writeRtcpFb(codec);  });  var maxptime = 0;  caps.codecs.forEach(function(codec) {    if (codec.maxptime > maxptime) {      maxptime = codec.maxptime;    }  });  if (maxptime > 0) {    sdp += 'a=maxptime:' + maxptime + '\r\n';  }  sdp += 'a=rtcp-mux\r\n';  caps.headerExtensions.forEach(function(extension) {    sdp += SDPUtils.writeExtmap(extension);  });  // FIXME: write fecMechanisms.  return sdp;};// Parses the SDP media section and returns an array of// RTCRtpEncodingParameters.SDPUtils.parseRtpEncodingParameters = function(mediaSection) {  var encodingParameters = [];  var description = SDPUtils.parseRtpParameters(mediaSection);  var hasRed = description.fecMechanisms.indexOf('RED') !== -1;  var hasUlpfec = description.fecMechanisms.indexOf('ULPFEC') !== -1;  // filter a=ssrc:... cname:, ignore PlanB-msid  var ssrcs = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:')  .map(function(line) {    return SDPUtils.parseSsrcMedia(line);  })  .filter(function(parts) {    return parts.attribute === 'cname';  });  var primarySsrc = ssrcs.length > 0 && ssrcs[0].ssrc;  var secondarySsrc;  var flows = SDPUtils.matchPrefix(mediaSection, 'a=ssrc-group:FID')  .map(function(line) {    var parts = line.split(' ');    parts.shift();    return parts.map(function(part) {      return parseInt(part, 10);    });  });  if (flows.length > 0 && flows[0].length > 1 && flows[0][0] === primarySsrc) {    secondarySsrc = flows[0][1];  }  description.codecs.forEach(function(codec) {    if (codec.name.toUpperCase() === 'RTX' && codec.parameters.apt) {      var encParam = {        ssrc: primarySsrc,        codecPayloadType: parseInt(codec.parameters.apt, 10),        rtx: {          ssrc: secondarySsrc        }      };      encodingParameters.push(encParam);      if (hasRed) {        encParam = JSON.parse(JSON.stringify(encParam));        encParam.fec = {          ssrc: secondarySsrc,          mechanism: hasUlpfec ? 'red+ulpfec' : 'red'        };        encodingParameters.push(encParam);      }    }  });  if (encodingParameters.length === 0 && primarySsrc) {    encodingParameters.push({      ssrc: primarySsrc    });  }  // we support both b=AS and b=TIAS but interpret AS as TIAS.  var bandwidth = SDPUtils.matchPrefix(mediaSection, 'b=');  if (bandwidth.length) {    if (bandwidth[0].indexOf('b=TIAS:') === 0) {      bandwidth = parseInt(bandwidth[0].substr(7), 10);    } else if (bandwidth[0].indexOf('b=AS:') === 0) {      // use formula from JSEP to convert b=AS to TIAS value.      bandwidth = parseInt(bandwidth[0].substr(5), 10) * 1000 * 0.95          - (50 * 40 * 8);    } else {      bandwidth = undefined;    }    encodingParameters.forEach(function(params) {      params.maxBitrate = bandwidth;    });  }  return encodingParameters;};// parses http://draft.ortc.org/#rtcrtcpparameters*SDPUtils.parseRtcpParameters = function(mediaSection) {  var rtcpParameters = {};  var cname;  // Gets the first SSRC. Note that with RTX there might be multiple  // SSRCs.  var remoteSsrc = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:')      .map(function(line) {        return SDPUtils.parseSsrcMedia(line);      })      .filter(function(obj) {        return obj.attribute === 'cname';      })[0];  if (remoteSsrc) {    rtcpParameters.cname = remoteSsrc.value;    rtcpParameters.ssrc = remoteSsrc.ssrc;  }  // Edge uses the compound attribute instead of reducedSize  // compound is !reducedSize  var rsize = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-rsize');  rtcpParameters.reducedSize = rsize.length > 0;  rtcpParameters.compound = rsize.length === 0;  // parses the rtcp-mux attrіbute.  // Note that Edge does not support unmuxed RTCP.  var mux = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-mux');  rtcpParameters.mux = mux.length > 0;  return rtcpParameters;};// parses either a=msid: or a=ssrc:... msid lines and returns// the id of the MediaStream and MediaStreamTrack.SDPUtils.parseMsid = function(mediaSection) {  var parts;  var spec = SDPUtils.matchPrefix(mediaSection, 'a=msid:');  if (spec.length === 1) {    parts = spec[0].substr(7).split(' ');    return {stream: parts[0], track: parts[1]};  }  var planB = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:')  .map(function(line) {    return SDPUtils.parseSsrcMedia(line);  })  .filter(function(parts) {    return parts.attribute === 'msid';  });  if (planB.length > 0) {    parts = planB[0].value.split(' ');    return {stream: parts[0], track: parts[1]};  }};// Generate a session ID for SDP.// https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-20#section-5.2.1// recommends using a cryptographically random +ve 64-bit value// but right now this should be acceptable and within the right rangeSDPUtils.generateSessionId = function() {  return Math.random().toString().substr(2, 21);};// Write boilder plate for start of SDP// sessId argument is optional - if not supplied it will// be generated randomly// sessVersion is optional and defaults to 2SDPUtils.writeSessionBoilerplate = function(sessId, sessVer) {  var sessionId;  var version = sessVer !== undefined ? sessVer : 2;  if (sessId) {    sessionId = sessId;  } else {    sessionId = SDPUtils.generateSessionId();  }  // FIXME: sess-id should be an NTP timestamp.  return 'v=0\r\n' +      'o=thisisadapterortc ' + sessionId + ' ' + version + ' IN IP4 127.0.0.1\r\n' +      's=-\r\n' +      't=0 0\r\n';};SDPUtils.writeMediaSection = function(transceiver, caps, type, stream) {  var sdp = SDPUtils.writeRtpDescription(transceiver.kind, caps);  // Map ICE parameters (ufrag, pwd) to SDP.  sdp += SDPUtils.writeIceParameters(      transceiver.iceGatherer.getLocalParameters());  // Map DTLS parameters to SDP.  sdp += SDPUtils.writeDtlsParameters(      transceiver.dtlsTransport.getLocalParameters(),      type === 'offer' ? 'actpass' : 'active');  sdp += 'a=mid:' + transceiver.mid + '\r\n';  if (transceiver.direction) {    sdp += 'a=' + transceiver.direction + '\r\n';  } else if (transceiver.rtpSender && transceiver.rtpReceiver) {    sdp += 'a=sendrecv\r\n';  } else if (transceiver.rtpSender) {    sdp += 'a=sendonly\r\n';  } else if (transceiver.rtpReceiver) {    sdp += 'a=recvonly\r\n';  } else {    sdp += 'a=inactive\r\n';  }  if (transceiver.rtpSender) {    // spec.    var msid = 'msid:' + stream.id + ' ' +        transceiver.rtpSender.track.id + '\r\n';    sdp += 'a=' + msid;    // for Chrome.    sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc +        ' ' + msid;    if (transceiver.sendEncodingParameters[0].rtx) {      sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc +          ' ' + msid;      sdp += 'a=ssrc-group:FID ' +          transceiver.sendEncodingParameters[0].ssrc + ' ' +          transceiver.sendEncodingParameters[0].rtx.ssrc +          '\r\n';    }  }  // FIXME: this should be written by writeRtpDescription.  sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc +      ' cname:' + SDPUtils.localCName + '\r\n';  if (transceiver.rtpSender && transceiver.sendEncodingParameters[0].rtx) {    sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc +        ' cname:' + SDPUtils.localCName + '\r\n';  }  return sdp;};// Gets the direction from the mediaSection or the sessionpart.SDPUtils.getDirection = function(mediaSection, sessionpart) {  // Look for sendrecv, sendonly, recvonly, inactive, default to sendrecv.  var lines = SDPUtils.splitLines(mediaSection);  for (var i = 0; i < lines.length; i++) {    switch (lines[i]) {      case 'a=sendrecv':      case 'a=sendonly':      case 'a=recvonly':      case 'a=inactive':        return lines[i].substr(2);      default:        // FIXME: What should happen here?    }  }  if (sessionpart) {    return SDPUtils.getDirection(sessionpart);  }  return 'sendrecv';};SDPUtils.getKind = function(mediaSection) {  var lines = SDPUtils.splitLines(mediaSection);  var mline = lines[0].split(' ');  return mline[0].substr(2);};SDPUtils.isRejected = function(mediaSection) {  return mediaSection.split(' ', 2)[1] === '0';};SDPUtils.parseMLine = function(mediaSection) {  var lines = SDPUtils.splitLines(mediaSection);  var mline = lines[0].split(' ');  return {    kind: mline[0].substr(2),    port: parseInt(mline[1], 10),    protocol: mline[2],    fmt: mline.slice(3).join(' ')  };};// Expose public methods.if (typeof module === 'object') {  module.exports = SDPUtils;}},{}],3:[function(require,module,exports){(function (global){/* *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * *  Use of this source code is governed by a BSD-style license *  that can be found in the LICENSE file in the root of the source *  tree. */ /* eslint-env node */'use strict';var adapterFactory = require('./adapter_factory.js');module.exports = adapterFactory({window: global.window});}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})},{"./adapter_factory.js":4}],4:[function(require,module,exports){/* *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * *  Use of this source code is governed by a BSD-style license *  that can be found in the LICENSE file in the root of the source *  tree. */ /* eslint-env node */'use strict';var utils = require('./utils');// Shimming starts here.module.exports = function(dependencies, opts) {  var window = dependencies && dependencies.window;  var options = {    shimChrome: true,    shimFirefox: true,    shimEdge: true,    shimSafari: true,  };  for (var key in opts) {    if (hasOwnProperty.call(opts, key)) {      options[key] = opts[key];    }  }  // Utils.  var logging = utils.log;  var browserDetails = utils.detectBrowser(window);  // Uncomment the line below if you want logging to occur, including logging  // for the switch statement below. Can also be turned on in the browser via  // adapter.disableLog(false), but then logging from the switch statement below  // will not appear.  // require('./utils').disableLog(false);  // Browser shims.  var chromeShim = require('./chrome/chrome_shim') || null;  var edgeShim = require('./edge/edge_shim') || null;  var firefoxShim = require('./firefox/firefox_shim') || null;  var safariShim = require('./safari/safari_shim') || null;  var commonShim = require('./common_shim') || null;  // Export to the adapter global object visible in the browser.  var adapter = {    browserDetails: browserDetails,    commonShim: commonShim,    extractVersion: utils.extractVersion,    disableLog: utils.disableLog,    disableWarnings: utils.disableWarnings  };  // Shim browser if found.  switch (browserDetails.browser) {    case 'chrome':      if (!chromeShim || !chromeShim.shimPeerConnection ||          !options.shimChrome) {        logging('Chrome shim is not included in this adapter release.');        return adapter;      }      logging('adapter.js shimming chrome.');      // Export to the adapter global object visible in the browser.      adapter.browserShim = chromeShim;      commonShim.shimCreateObjectURL(window);      chromeShim.shimGetUserMedia(window);      chromeShim.shimMediaStream(window);      chromeShim.shimSourceObject(window);      chromeShim.shimPeerConnection(window);      chromeShim.shimOnTrack(window);      chromeShim.shimAddTrackRemoveTrack(window);      chromeShim.shimGetSendersWithDtmf(window);      commonShim.shimRTCIceCandidate(window);      commonShim.shimMaxMessageSize(window);      commonShim.shimSendThrowTypeError(window);      break;    case 'firefox':      if (!firefoxShim || !firefoxShim.shimPeerConnection ||          !options.shimFirefox) {        logging('Firefox shim is not included in this adapter release.');        return adapter;      }      logging('adapter.js shimming firefox.');      // Export to the adapter global object visible in the browser.      adapter.browserShim = firefoxShim;      commonShim.shimCreateObjectURL(window);      firefoxShim.shimGetUserMedia(window);      firefoxShim.shimSourceObject(window);      firefoxShim.shimPeerConnection(window);      firefoxShim.shimOnTrack(window);      firefoxShim.shimRemoveStream(window);      commonShim.shimRTCIceCandidate(window);      commonShim.shimMaxMessageSize(window);      commonShim.shimSendThrowTypeError(window);      break;    case 'edge':      if (!edgeShim || !edgeShim.shimPeerConnection || !options.shimEdge) {        logging('MS edge shim is not included in this adapter release.');        return adapter;      }      logging('adapter.js shimming edge.');      // Export to the adapter global object visible in the browser.      adapter.browserShim = edgeShim;      commonShim.shimCreateObjectURL(window);      edgeShim.shimGetUserMedia(window);      edgeShim.shimPeerConnection(window);      edgeShim.shimReplaceTrack(window);      // the edge shim implements the full RTCIceCandidate object.      commonShim.shimMaxMessageSize(window);      commonShim.shimSendThrowTypeError(window);      break;    case 'safari':      if (!safariShim || !options.shimSafari) {        logging('Safari shim is not included in this adapter release.');        return adapter;      }      logging('adapter.js shimming safari.');      // Export to the adapter global object visible in the browser.      adapter.browserShim = safariShim;      commonShim.shimCreateObjectURL(window);      safariShim.shimRTCIceServerUrls(window);      safariShim.shimCallbacksAPI(window);      safariShim.shimLocalStreamsAPI(window);      safariShim.shimRemoteStreamsAPI(window);      safariShim.shimTrackEventTransceiver(window);      safariShim.shimGetUserMedia(window);      safariShim.shimCreateOfferLegacy(window);      commonShim.shimRTCIceCandidate(window);      commonShim.shimMaxMessageSize(window);      commonShim.shimSendThrowTypeError(window);      break;    default:      logging('Unsupported browser!');      break;  }  return adapter;};},{"./chrome/chrome_shim":5,"./common_shim":7,"./edge/edge_shim":8,"./firefox/firefox_shim":10,"./safari/safari_shim":12,"./utils":13}],5:[function(require,module,exports){/* *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * *  Use of this source code is governed by a BSD-style license *  that can be found in the LICENSE file in the root of the source *  tree. */ /* eslint-env node */'use strict';var utils = require('../utils.js');var logging = utils.log;module.exports = {  shimGetUserMedia: require('./getusermedia'),  shimMediaStream: function(window) {    window.MediaStream = window.MediaStream || window.webkitMediaStream;  },  shimOnTrack: function(window) {    if (typeof window === 'object' && window.RTCPeerConnection && !('ontrack' in        window.RTCPeerConnection.prototype)) {      Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', {        get: function() {          return this._ontrack;        },        set: function(f) {          if (this._ontrack) {            this.removeEventListener('track', this._ontrack);          }          this.addEventListener('track', this._ontrack = f);        }      });      var origSetRemoteDescription =          window.RTCPeerConnection.prototype.setRemoteDescription;      window.RTCPeerConnection.prototype.setRemoteDescription = function() {        var pc = this;        if (!pc._ontrackpoly) {          pc._ontrackpoly = function(e) {            // onaddstream does not fire when a track is added to an existing            // stream. But stream.onaddtrack is implemented so we use that.            e.stream.addEventListener('addtrack', function(te) {              var receiver;              if (window.RTCPeerConnection.prototype.getReceivers) {                receiver = pc.getReceivers().find(function(r) {                  return r.track && r.track.id === te.track.id;                });              } else {                receiver = {track: te.track};              }              var event = new Event('track');              event.track = te.track;              event.receiver = receiver;              event.transceiver = {receiver: receiver};              event.streams = [e.stream];              pc.dispatchEvent(event);            });            e.stream.getTracks().forEach(function(track) {              var receiver;              if (window.RTCPeerConnection.prototype.getReceivers) {                receiver = pc.getReceivers().find(function(r) {                  return r.track && r.track.id === track.id;                });              } else {                receiver = {track: track};              }              var event = new Event('track');              event.track = track;              event.receiver = receiver;              event.transceiver = {receiver: receiver};              event.streams = [e.stream];              pc.dispatchEvent(event);            });          };          pc.addEventListener('addstream', pc._ontrackpoly);        }        return origSetRemoteDescription.apply(pc, arguments);      };    } else if (!('RTCRtpTransceiver' in window)) {      utils.wrapPeerConnectionEvent(window, 'track', function(e) {        if (!e.transceiver) {          e.transceiver = {receiver: e.receiver};        }        return e;      });    }  },  shimGetSendersWithDtmf: function(window) {    // Overrides addTrack/removeTrack, depends on shimAddTrackRemoveTrack.    if (typeof window === 'object' && window.RTCPeerConnection &&        !('getSenders' in window.RTCPeerConnection.prototype) &&        'createDTMFSender' in window.RTCPeerConnection.prototype) {      var shimSenderWithDtmf = function(pc, track) {        return {          track: track,          get dtmf() {            if (this._dtmf === undefined) {              if (track.kind === 'audio') {                this._dtmf = pc.createDTMFSender(track);              } else {                this._dtmf = null;              }            }            return this._dtmf;          },          _pc: pc        };      };      // augment addTrack when getSenders is not available.      if (!window.RTCPeerConnection.prototype.getSenders) {        window.RTCPeerConnection.prototype.getSenders = function() {          this._senders = this._senders || [];          return this._senders.slice(); // return a copy of the internal state.        };        var origAddTrack = window.RTCPeerConnection.prototype.addTrack;        window.RTCPeerConnection.prototype.addTrack = function(track, stream) {          var pc = this;          var sender = origAddTrack.apply(pc, arguments);          if (!sender) {            sender = shimSenderWithDtmf(pc, track);            pc._senders.push(sender);          }          return sender;        };        var origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack;        window.RTCPeerConnection.prototype.removeTrack = function(sender) {          var pc = this;          origRemoveTrack.apply(pc, arguments);          var idx = pc._senders.indexOf(sender);          if (idx !== -1) {            pc._senders.splice(idx, 1);          }        };      }      var origAddStream = window.RTCPeerConnection.prototype.addStream;      window.RTCPeerConnection.prototype.addStream = function(stream) {        var pc = this;        pc._senders = pc._senders || [];        origAddStream.apply(pc, [stream]);        stream.getTracks().forEach(function(track) {          pc._senders.push(shimSenderWithDtmf(pc, track));        });      };      var origRemoveStream = window.RTCPeerConnection.prototype.removeStream;      window.RTCPeerConnection.prototype.removeStream = function(stream) {        var pc = this;        pc._senders = pc._senders || [];        origRemoveStream.apply(pc, [stream]);        stream.getTracks().forEach(function(track) {          var sender = pc._senders.find(function(s) {            return s.track === track;          });          if (sender) {            pc._senders.splice(pc._senders.indexOf(sender), 1); // remove sender          }        });      };    } else if (typeof window === 'object' && window.RTCPeerConnection &&               'getSenders' in window.RTCPeerConnection.prototype &&               'createDTMFSender' in window.RTCPeerConnection.prototype &&               window.RTCRtpSender &&               !('dtmf' in window.RTCRtpSender.prototype)) {      var origGetSenders = window.RTCPeerConnection.prototype.getSenders;      window.RTCPeerConnection.prototype.getSenders = function() {        var pc = this;        var senders = origGetSenders.apply(pc, []);        senders.forEach(function(sender) {          sender._pc = pc;        });        return senders;      };      Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', {        get: function() {          if (this._dtmf === undefined) {            if (this.track.kind === 'audio') {              this._dtmf = this._pc.createDTMFSender(this.track);            } else {              this._dtmf = null;            }          }          return this._dtmf;        }      });    }  },  shimSourceObject: function(window) {    var URL = window && window.URL;    if (typeof window === 'object') {      if (window.HTMLMediaElement &&        !('srcObject' in window.HTMLMediaElement.prototype)) {        // Shim the srcObject property, once, when HTMLMediaElement is found.        Object.defineProperty(window.HTMLMediaElement.prototype, 'srcObject', {          get: function() {            return this._srcObject;          },          set: function(stream) {            var self = this;            // Use _srcObject as a private property for this shim            this._srcObject = stream;            if (this.src) {              URL.revokeObjectURL(this.src);            }            if (!stream) {              this.src = '';              return undefined;            }            this.src = URL.createObjectURL(stream);            // We need to recreate the blob url when a track is added or            // removed. Doing it manually since we want to avoid a recursion.            stream.addEventListener('addtrack', function() {              if (self.src) {                URL.revokeObjectURL(self.src);              }              self.src = URL.createObjectURL(stream);            });            stream.addEventListener('removetrack', function() {              if (self.src) {                URL.revokeObjectURL(self.src);              }              self.src = URL.createObjectURL(stream);            });          }        });      }    }  },  shimAddTrackRemoveTrackWithNative: function(window) {    // shim addTrack/removeTrack with native variants in order to make    // the interactions with legacy getLocalStreams behave as in other browsers.    // Keeps a mapping stream.id => [stream, rtpsenders...]    window.RTCPeerConnection.prototype.getLocalStreams = function() {      var pc = this;      this._shimmedLocalStreams = this._shimmedLocalStreams || {};      return Object.keys(this._shimmedLocalStreams).map(function(streamId) {        return pc._shimmedLocalStreams[streamId][0];      });    };    var origAddTrack = window.RTCPeerConnection.prototype.addTrack;    window.RTCPeerConnection.prototype.addTrack = function(track, stream) {      if (!stream) {        return origAddTrack.apply(this, arguments);      }      this._shimmedLocalStreams = this._shimmedLocalStreams || {};      var sender = origAddTrack.apply(this, arguments);      if (!this._shimmedLocalStreams[stream.id]) {        this._shimmedLocalStreams[stream.id] = [stream, sender];      } else if (this._shimmedLocalStreams[stream.id].indexOf(sender) === -1) {        this._shimmedLocalStreams[stream.id].push(sender);      }      return sender;    };    var origAddStream = window.RTCPeerConnection.prototype.addStream;    window.RTCPeerConnection.prototype.addStream = function(stream) {      var pc = this;      this._shimmedLocalStreams = this._shimmedLocalStreams || {};      stream.getTracks().forEach(function(track) {        var alreadyExists = pc.getSenders().find(function(s) {          return s.track === track;        });        if (alreadyExists) {          throw new DOMException('Track already exists.',              'InvalidAccessError');        }      });      var existingSenders = pc.getSenders();      origAddStream.apply(this, arguments);      var newSenders = pc.getSenders().filter(function(newSender) {        return existingSenders.indexOf(newSender) === -1;      });      this._shimmedLocalStreams[stream.id] = [stream].concat(newSenders);    };    var origRemoveStream = window.RTCPeerConnection.prototype.removeStream;    window.RTCPeerConnection.prototype.removeStream = function(stream) {      this._shimmedLocalStreams = this._shimmedLocalStreams || {};      delete this._shimmedLocalStreams[stream.id];      return origRemoveStream.apply(this, arguments);    };    var origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack;    window.RTCPeerConnection.prototype.removeTrack = function(sender) {      var pc = this;      this._shimmedLocalStreams = this._shimmedLocalStreams || {};      if (sender) {        Object.keys(this._shimmedLocalStreams).forEach(function(streamId) {          var idx = pc._shimmedLocalStreams[streamId].indexOf(sender);          if (idx !== -1) {            pc._shimmedLocalStreams[streamId].splice(idx, 1);          }          if (pc._shimmedLocalStreams[streamId].length === 1) {            delete pc._shimmedLocalStreams[streamId];          }        });      }      return origRemoveTrack.apply(this, arguments);    };  },  shimAddTrackRemoveTrack: function(window) {    var browserDetails = utils.detectBrowser(window);    // shim addTrack and removeTrack.    if (window.RTCPeerConnection.prototype.addTrack &&        browserDetails.version >= 65) {      return this.shimAddTrackRemoveTrackWithNative(window);    }    // also shim pc.getLocalStreams when addTrack is shimmed    // to return the original streams.    var origGetLocalStreams = window.RTCPeerConnection.prototype        .getLocalStreams;    window.RTCPeerConnection.prototype.getLocalStreams = function() {      var pc = this;      var nativeStreams = origGetLocalStreams.apply(this);      pc._reverseStreams = pc._reverseStreams || {};      return nativeStreams.map(function(stream) {        return pc._reverseStreams[stream.id];      });    };    var origAddStream = window.RTCPeerConnection.prototype.addStream;    window.RTCPeerConnection.prototype.addStream = function(stream) {      var pc = this;      pc._streams = pc._streams || {};      pc._reverseStreams = pc._reverseStreams || {};      stream.getTracks().forEach(function(track) {        var alreadyExists = pc.getSenders().find(function(s) {          return s.track === track;        });        if (alreadyExists) {          throw new DOMException('Track already exists.',              'InvalidAccessError');        }      });      // Add identity mapping for consistency with addTrack.      // Unless this is being used with a stream from addTrack.      if (!pc._reverseStreams[stream.id]) {        var newStream = new window.MediaStream(stream.getTracks());        pc._streams[stream.id] = newStream;        pc._reverseStreams[newStream.id] = stream;        stream = newStream;      }      origAddStream.apply(pc, [stream]);    };    var origRemoveStream = window.RTCPeerConnection.prototype.removeStream;    window.RTCPeerConnection.prototype.removeStream = function(stream) {      var pc = this;      pc._streams = pc._streams || {};      pc._reverseStreams = pc._reverseStreams || {};      origRemoveStream.apply(pc, [(pc._streams[stream.id] || stream)]);      delete pc._reverseStreams[(pc._streams[stream.id] ?          pc._streams[stream.id].id : stream.id)];      delete pc._streams[stream.id];    };    window.RTCPeerConnection.prototype.addTrack = function(track, stream) {      var pc = this;      if (pc.signalingState === 'closed') {        throw new DOMException(          'The RTCPeerConnection\'s signalingState is \'closed\'.',          'InvalidStateError');      }      var streams = [].slice.call(arguments, 1);      if (streams.length !== 1 ||          !streams[0].getTracks().find(function(t) {            return t === track;          })) {        // this is not fully correct but all we can manage without        // [[associated MediaStreams]] internal slot.        throw new DOMException(          'The adapter.js addTrack polyfill only supports a single ' +          ' stream which is associated with the specified track.',          'NotSupportedError');      }      var alreadyExists = pc.getSenders().find(function(s) {        return s.track === track;      });      if (alreadyExists) {        throw new DOMException('Track already exists.',            'InvalidAccessError');      }      pc._streams = pc._streams || {};      pc._reverseStreams = pc._reverseStreams || {};      var oldStream = pc._streams[stream.id];      if (oldStream) {        // this is using odd Chrome behaviour, use with caution:        // https://bugs.chromium.org/p/webrtc/issues/detail?id=7815        // Note: we rely on the high-level addTrack/dtmf shim to        // create the sender with a dtmf sender.        oldStream.addTrack(track);        // Trigger ONN async.        Promise.resolve().then(function() {          pc.dispatchEvent(new Event('negotiationneeded'));        });      } else {        var newStream = new window.MediaStream([track]);        pc._streams[stream.id] = newStream;        pc._reverseStreams[newStream.id] = stream;        pc.addStream(newStream);      }      return pc.getSenders().find(function(s) {        return s.track === track;      });    };    // replace the internal stream id with the external one and    // vice versa.    function replaceInternalStreamId(pc, description) {      var sdp = description.sdp;      Object.keys(pc._reverseStreams || []).forEach(function(internalId) {        var externalStream = pc._reverseStreams[internalId];        var internalStream = pc._streams[externalStream.id];        sdp = sdp.replace(new RegExp(internalStream.id, 'g'),            externalStream.id);      });      return new RTCSessionDescription({        type: description.type,        sdp: sdp      });    }    function replaceExternalStreamId(pc, description) {      var sdp = description.sdp;      Object.keys(pc._reverseStreams || []).forEach(function(internalId) {        var externalStream = pc._reverseStreams[internalId];        var internalStream = pc._streams[externalStream.id];        sdp = sdp.replace(new RegExp(externalStream.id, 'g'),            internalStream.id);      });      return new RTCSessionDescription({        type: description.type,        sdp: sdp      });    }    ['createOffer', 'createAnswer'].forEach(function(method) {      var nativeMethod = window.RTCPeerConnection.prototype[method];      window.RTCPeerConnection.prototype[method] = function() {        var pc = this;        var args = arguments;        var isLegacyCall = arguments.length &&            typeof arguments[0] === 'function';        if (isLegacyCall) {          return nativeMethod.apply(pc, [            function(description) {              var desc = replaceInternalStreamId(pc, description);              args[0].apply(null, [desc]);            },            function(err) {              if (args[1]) {                args[1].apply(null, err);              }            }, arguments[2]          ]);        }        return nativeMethod.apply(pc, arguments)        .then(function(description) {          return replaceInternalStreamId(pc, description);        });      };    });    var origSetLocalDescription =        window.RTCPeerConnection.prototype.setLocalDescription;    window.RTCPeerConnection.prototype.setLocalDescription = function() {      var pc = this;      if (!arguments.length || !arguments[0].type) {        return origSetLocalDescription.apply(pc, arguments);      }      arguments[0] = replaceExternalStreamId(pc, arguments[0]);      return origSetLocalDescription.apply(pc, arguments);    };    // TODO: mangle getStats: https://w3c.github.io/webrtc-stats/#dom-rtcmediastreamstats-streamidentifier    var origLocalDescription = Object.getOwnPropertyDescriptor(        window.RTCPeerConnection.prototype, 'localDescription');    Object.defineProperty(window.RTCPeerConnection.prototype,        'localDescription', {          get: function() {            var pc = this;            var description = origLocalDescription.get.apply(this);            if (description.type === '') {              return description;            }            return replaceInternalStreamId(pc, description);          }        });    window.RTCPeerConnection.prototype.removeTrack = function(sender) {      var pc = this;      if (pc.signalingState === 'closed') {        throw new DOMException(          'The RTCPeerConnection\'s signalingState is \'closed\'.',          'InvalidStateError');      }      // We can not yet check for sender instanceof RTCRtpSender      // since we shim RTPSender. So we check if sender._pc is set.      if (!sender._pc) {        throw new DOMException('Argument 1 of RTCPeerConnection.removeTrack ' +            'does not implement interface RTCRtpSender.', 'TypeError');      }      var isLocal = sender._pc === pc;      if (!isLocal) {        throw new DOMException('Sender was not created by this connection.',            'InvalidAccessError');      }      // Search for the native stream the senders track belongs to.      pc._streams = pc._streams || {};      var stream;      Object.keys(pc._streams).forEach(function(streamid) {        var hasTrack = pc._streams[streamid].getTracks().find(function(track) {          return sender.track === track;        });        if (hasTrack) {          stream = pc._streams[streamid];        }      });      if (stream) {        if (stream.getTracks().length === 1) {          // if this is the last track of the stream, remove the stream. This          // takes care of any shimmed _senders.          pc.removeStream(pc._reverseStreams[stream.id]);        } else {          // relying on the same odd chrome behaviour as above.          stream.removeTrack(sender.track);        }        pc.dispatchEvent(new Event('negotiationneeded'));      }    };  },  shimPeerConnection: function(window) {    var browserDetails = utils.detectBrowser(window);    // The RTCPeerConnection object.    if (!window.RTCPeerConnection) {      window.RTCPeerConnection = function(pcConfig, pcConstraints) {        // Translate iceTransportPolicy to iceTransports,        // see https://code.google.com/p/webrtc/issues/detail?id=4869        // this was fixed in M56 along with unprefixing RTCPeerConnection.        logging('PeerConnection');        if (pcConfig && pcConfig.iceTransportPolicy) {          pcConfig.iceTransports = pcConfig.iceTransportPolicy;        }        return new window.webkitRTCPeerConnection(pcConfig, pcConstraints);      };      window.RTCPeerConnection.prototype =          window.webkitRTCPeerConnection.prototype;      // wrap static methods. Currently just generateCertificate.      if (window.webkitRTCPeerConnection.generateCertificate) {        Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', {          get: function() {            return window.webkitRTCPeerConnection.generateCertificate;          }        });      }    } else {      // migrate from non-spec RTCIceServer.url to RTCIceServer.urls      var OrigPeerConnection = window.RTCPeerConnection;      window.RTCPeerConnection = function(pcConfig, pcConstraints) {        if (pcConfig && pcConfig.iceServers) {          var newIceServers = [];          for (var i = 0; i < pcConfig.iceServers.length; i++) {            var server = pcConfig.iceServers[i];            if (!server.hasOwnProperty('urls') &&                server.hasOwnProperty('url')) {              utils.deprecated('RTCIceServer.url', 'RTCIceServer.urls');              server = JSON.parse(JSON.stringify(server));              server.urls = server.url;              newIceServers.push(server);            } else {              newIceServers.push(pcConfig.iceServers[i]);            }          }          pcConfig.iceServers = newIceServers;        }        return new OrigPeerConnection(pcConfig, pcConstraints);      };      window.RTCPeerConnection.prototype = OrigPeerConnection.prototype;      // wrap static methods. Currently just generateCertificate.      Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', {        get: function() {          return OrigPeerConnection.generateCertificate;        }      });    }    var origGetStats = window.RTCPeerConnection.prototype.getStats;    window.RTCPeerConnection.prototype.getStats = function(selector,        successCallback, errorCallback) {      var pc = this;      var args = arguments;      // If selector is a function then we are in the old style stats so just      // pass back the original getStats format to avoid breaking old users.      if (arguments.length > 0 && typeof selector === 'function') {        return origGetStats.apply(this, arguments);      }      // When spec-style getStats is supported, return those when called with      // either no arguments or the selector argument is null.      if (origGetStats.length === 0 && (arguments.length === 0 ||          typeof arguments[0] !== 'function')) {        return origGetStats.apply(this, []);      }      var fixChromeStats_ = function(response) {        var standardReport = {};        var reports = response.result();        reports.forEach(function(report) {          var standardStats = {            id: report.id,            timestamp: report.timestamp,            type: {              localcandidate: 'local-candidate',              remotecandidate: 'remote-candidate'            }[report.type] || report.type          };          report.names().forEach(function(name) {            standardStats[name] = report.stat(name);          });          standardReport[standardStats.id] = standardStats;        });        return standardReport;      };      // shim getStats with maplike support      var makeMapStats = function(stats) {        return new Map(Object.keys(stats).map(function(key) {          return [key, stats[key]];        }));      };      if (arguments.length >= 2) {        var successCallbackWrapper_ = function(response) {          args[1](makeMapStats(fixChromeStats_(response)));        };        return origGetStats.apply(this, [successCallbackWrapper_,          arguments[0]]);      }      // promise-support      return new Promise(function(resolve, reject) {        origGetStats.apply(pc, [          function(response) {            resolve(makeMapStats(fixChromeStats_(response)));          }, reject]);      }).then(successCallback, errorCallback);    };    // add promise support -- natively available in Chrome 51    if (browserDetails.version < 51) {      ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate']          .forEach(function(method) {            var nativeMethod = window.RTCPeerConnection.prototype[method];            window.RTCPeerConnection.prototype[method] = function() {              var args = arguments;              var pc = this;              var promise = new Promise(function(resolve, reject) {                nativeMethod.apply(pc, [args[0], resolve, reject]);              });              if (args.length < 2) {                return promise;              }              return promise.then(function() {                args[1].apply(null, []);              },              function(err) {                if (args.length >= 3) {                  args[2].apply(null, [err]);                }              });            };          });    }    // promise support for createOffer and createAnswer. Available (without    // bugs) since M52: crbug/619289    if (browserDetails.version < 52) {      ['createOffer', 'createAnswer'].forEach(function(method) {        var nativeMethod = window.RTCPeerConnection.prototype[method];        window.RTCPeerConnection.prototype[method] = function() {          var pc = this;          if (arguments.length < 1 || (arguments.length === 1 &&              typeof arguments[0] === 'object')) {            var opts = arguments.length === 1 ? arguments[0] : undefined;            return new Promise(function(resolve, reject) {              nativeMethod.apply(pc, [resolve, reject, opts]);            });          }          return nativeMethod.apply(this, arguments);        };      });    }    // shim implicit creation of RTCSessionDescription/RTCIceCandidate    ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate']        .forEach(function(method) {          var nativeMethod = window.RTCPeerConnection.prototype[method];          window.RTCPeerConnection.prototype[method] = function() {            arguments[0] = new ((method === 'addIceCandidate') ?                window.RTCIceCandidate :                window.RTCSessionDescription)(arguments[0]);            return nativeMethod.apply(this, arguments);          };        });    // support for addIceCandidate(null or undefined)    var nativeAddIceCandidate =        window.RTCPeerConnection.prototype.addIceCandidate;    window.RTCPeerConnection.prototype.addIceCandidate = function() {      if (!arguments[0]) {        if (arguments[1]) {          arguments[1].apply(null);        }        return Promise.resolve();      }      return nativeAddIceCandidate.apply(this, arguments);    };  }};},{"../utils.js":13,"./getusermedia":6}],6:[function(require,module,exports){/* *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * *  Use of this source code is governed by a BSD-style license *  that can be found in the LICENSE file in the root of the source *  tree. */ /* eslint-env node */'use strict';var utils = require('../utils.js');var logging = utils.log;// Expose public methods.module.exports = function(window) {  var browserDetails = utils.detectBrowser(window);  var navigator = window && window.navigator;  var constraintsToChrome_ = function(c) {    if (typeof c !== 'object' || c.mandatory || c.optional) {      return c;    }    var cc = {};    Object.keys(c).forEach(function(key) {      if (key === 'require' || key === 'advanced' || key === 'mediaSource') {        return;      }      var r = (typeof c[key] === 'object') ? c[key] : {ideal: c[key]};      if (r.exact !== undefined && typeof r.exact === 'number') {        r.min = r.max = r.exact;      }      var oldname_ = function(prefix, name) {        if (prefix) {          return prefix + name.charAt(0).toUpperCase() + name.slice(1);        }        return (name === 'deviceId') ? 'sourceId' : name;      };      if (r.ideal !== undefined) {        cc.optional = cc.optional || [];        var oc = {};        if (typeof r.ideal === 'number') {          oc[oldname_('min', key)] = r.ideal;          cc.optional.push(oc);          oc = {};          oc[oldname_('max', key)] = r.ideal;          cc.optional.push(oc);        } else {          oc[oldname_('', key)] = r.ideal;          cc.optional.push(oc);        }      }      if (r.exact !== undefined && typeof r.exact !== 'number') {        cc.mandatory = cc.mandatory || {};        cc.mandatory[oldname_('', key)] = r.exact;      } else {        ['min', 'max'].forEach(function(mix) {          if (r[mix] !== undefined) {            cc.mandatory = cc.mandatory || {};            cc.mandatory[oldname_(mix, key)] = r[mix];          }        });      }    });    if (c.advanced) {      cc.optional = (cc.optional || []).concat(c.advanced);    }    return cc;  };  var shimConstraints_ = function(constraints, func) {    if (browserDetails.version >= 61) {      return func(constraints);    }    constraints = JSON.parse(JSON.stringify(constraints));    if (constraints && typeof constraints.audio === 'object') {      var remap = function(obj, a, b) {        if (a in obj && !(b in obj)) {          obj[b] = obj[a];          delete obj[a];        }      };      constraints = JSON.parse(JSON.stringify(constraints));      remap(constraints.audio, 'autoGainControl', 'googAutoGainControl');      remap(constraints.audio, 'noiseSuppression', 'googNoiseSuppression');      constraints.audio = constraintsToChrome_(constraints.audio);    }    if (constraints && typeof constraints.video === 'object') {      // Shim facingMode for mobile & surface pro.      var face = constraints.video.facingMode;      face = face && ((typeof face === 'object') ? face : {ideal: face});      var getSupportedFacingModeLies = browserDetails.version < 66;      if ((face && (face.exact === 'user' || face.exact === 'environment' ||                    face.ideal === 'user' || face.ideal === 'environment')) &&          !(navigator.mediaDevices.getSupportedConstraints &&            navigator.mediaDevices.getSupportedConstraints().facingMode &&            !getSupportedFacingModeLies)) {        delete constraints.video.facingMode;        var matches;        if (face.exact === 'environment' || face.ideal === 'environment') {          matches = ['back', 'rear'];        } else if (face.exact === 'user' || face.ideal === 'user') {          matches = ['front'];        }        if (matches) {          // Look for matches in label, or use last cam for back (typical).          return navigator.mediaDevices.enumerateDevices()          .then(function(devices) {            devices = devices.filter(function(d) {              return d.kind === 'videoinput';            });            var dev = devices.find(function(d) {              return matches.some(function(match) {                return d.label.toLowerCase().indexOf(match) !== -1;              });            });            if (!dev && devices.length && matches.indexOf('back') !== -1) {              dev = devices[devices.length - 1]; // more likely the back cam            }            if (dev) {              constraints.video.deviceId = face.exact ? {exact: dev.deviceId} :                                                        {ideal: dev.deviceId};            }            constraints.video = constraintsToChrome_(constraints.video);            logging('chrome: ' + JSON.stringify(constraints));            return func(constraints);          });        }      }      constraints.video = constraintsToChrome_(constraints.video);    }    logging('chrome: ' + JSON.stringify(constraints));    return func(constraints);  };  var shimError_ = function(e) {    return {      name: {        PermissionDeniedError: 'NotAllowedError',        InvalidStateError: 'NotReadableError',        DevicesNotFoundError: 'NotFoundError',        ConstraintNotSatisfiedError: 'OverconstrainedError',        TrackStartError: 'NotReadableError',        MediaDeviceFailedDueToShutdown: 'NotReadableError',        MediaDeviceKillSwitchOn: 'NotReadableError'      }[e.name] || e.name,      message: e.message,      constraint: e.constraintName,      toString: function() {        return this.name + (this.message && ': ') + this.message;      }    };  };  var getUserMedia_ = function(constraints, onSuccess, onError) {    shimConstraints_(constraints, function(c) {      navigator.webkitGetUserMedia(c, onSuccess, function(e) {        if (onError) {          onError(shimError_(e));        }      });    });  };  navigator.getUserMedia = getUserMedia_;  // Returns the result of getUserMedia as a Promise.  var getUserMediaPromise_ = function(constraints) {    return new Promise(function(resolve, reject) {      navigator.getUserMedia(constraints, resolve, reject);    });  };  if (!navigator.mediaDevices) {    navigator.mediaDevices = {      getUserMedia: getUserMediaPromise_,      enumerateDevices: function() {        return new Promise(function(resolve) {          var kinds = {audio: 'audioinput', video: 'videoinput'};          return window.MediaStreamTrack.getSources(function(devices) {            resolve(devices.map(function(device) {              return {label: device.label,                kind: kinds[device.kind],                deviceId: device.id,                groupId: ''};            }));          });        });      },      getSupportedConstraints: function() {        return {          deviceId: true, echoCancellation: true, facingMode: true,          frameRate: true, height: true, width: true        };      }    };  }  // A shim for getUserMedia method on the mediaDevices object.  // TODO(KaptenJansson) remove once implemented in Chrome stable.  if (!navigator.mediaDevices.getUserMedia) {    navigator.mediaDevices.getUserMedia = function(constraints) {      return getUserMediaPromise_(constraints);    };  } else {    // Even though Chrome 45 has navigator.mediaDevices and a getUserMedia    // function which returns a Promise, it does not accept spec-style    // constraints.    var origGetUserMedia = navigator.mediaDevices.getUserMedia.        bind(navigator.mediaDevices);    navigator.mediaDevices.getUserMedia = function(cs) {      return shimConstraints_(cs, function(c) {        return origGetUserMedia(c).then(function(stream) {          if (c.audio && !stream.getAudioTracks().length ||              c.video && !stream.getVideoTracks().length) {            stream.getTracks().forEach(function(track) {              track.stop();            });            throw new DOMException('', 'NotFoundError');          }          return stream;        }, function(e) {          return Promise.reject(shimError_(e));        });      });    };  }  // Dummy devicechange event methods.  // TODO(KaptenJansson) remove once implemented in Chrome stable.  if (typeof navigator.mediaDevices.addEventListener === 'undefined') {    navigator.mediaDevices.addEventListener = function() {      logging('Dummy mediaDevices.addEventListener called.');    };  }  if (typeof navigator.mediaDevices.removeEventListener === 'undefined') {    navigator.mediaDevices.removeEventListener = function() {      logging('Dummy mediaDevices.removeEventListener called.');    };  }};},{"../utils.js":13}],7:[function(require,module,exports){/* *  Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * *  Use of this source code is governed by a BSD-style license *  that can be found in the LICENSE file in the root of the source *  tree. */ /* eslint-env node */'use strict';var SDPUtils = require('sdp');var utils = require('./utils');module.exports = {  shimRTCIceCandidate: function(window) {    // foundation is arbitrarily chosen as an indicator for full support for    // https://w3c.github.io/webrtc-pc/#rtcicecandidate-interface    if (window.RTCIceCandidate && 'foundation' in        window.RTCIceCandidate.prototype) {      return;    }    var NativeRTCIceCandidate = window.RTCIceCandidate;    window.RTCIceCandidate = function(args) {      // Remove the a= which shouldn't be part of the candidate string.      if (typeof args === 'object' && args.candidate &&          args.candidate.indexOf('a=') === 0) {        args = JSON.parse(JSON.stringify(args));        args.candidate = args.candidate.substr(2);      }      // Augment the native candidate with the parsed fields.      var nativeCandidate = new NativeRTCIceCandidate(args);      var parsedCandidate = SDPUtils.parseCandidate(args.candidate);      var augmentedCandidate = Object.assign(nativeCandidate,          parsedCandidate);      // Add a serializer that does not serialize the extra attributes.      augmentedCandidate.toJSON = function() {        return {          candidate: augmentedCandidate.candidate,          sdpMid: augmentedCandidate.sdpMid,          sdpMLineIndex: augmentedCandidate.sdpMLineIndex,          usernameFragment: augmentedCandidate.usernameFragment,        };      };      return augmentedCandidate;    };    // Hook up the augmented candidate in onicecandidate and    // addEventListener('icecandidate', ...)    utils.wrapPeerConnectionEvent(window, 'icecandidate', function(e) {      if (e.candidate) {        Object.defineProperty(e, 'candidate', {          value: new window.RTCIceCandidate(e.candidate),          writable: 'false'        });      }      return e;    });  },  // shimCreateObjectURL must be called before shimSourceObject to avoid loop.  shimCreateObjectURL: function(window) {    var URL = window && window.URL;    if (!(typeof window === 'object' && window.HTMLMediaElement &&          'srcObject' in window.HTMLMediaElement.prototype &&        URL.createObjectURL && URL.revokeObjectURL)) {      // Only shim CreateObjectURL using srcObject if srcObject exists.      return undefined;    }    var nativeCreateObjectURL = URL.createObjectURL.bind(URL);    var nativeRevokeObjectURL = URL.revokeObjectURL.bind(URL);    var streams = new Map(), newId = 0;    URL.createObjectURL = function(stream) {      if ('getTracks' in stream) {        var url = 'polyblob:' + (++newId);        streams.set(url, stream);        utils.deprecated('URL.createObjectURL(stream)',            'elem.srcObject = stream');        return url;      }      return nativeCreateObjectURL(stream);    };    URL.revokeObjectURL = function(url) {      nativeRevokeObjectURL(url);      streams.delete(url);    };    var dsc = Object.getOwnPropertyDescriptor(window.HTMLMediaElement.prototype,                                              'src');    Object.defineProperty(window.HTMLMediaElement.prototype, 'src', {      get: function() {        return dsc.get.apply(this);      },      set: function(url) {        this.srcObject = streams.get(url) || null;        return dsc.set.apply(this, [url]);      }    });    var nativeSetAttribute = window.HTMLMediaElement.prototype.setAttribute;    window.HTMLMediaElement.prototype.setAttribute = function() {      if (arguments.length === 2 &&          ('' + arguments[0]).toLowerCase() === 'src') {        this.srcObject = streams.get(arguments[1]) || null;      }      return nativeSetAttribute.apply(this, arguments);    };  },  shimMaxMessageSize: function(window) {    if (window.RTCSctpTransport) {      return;    }    var browserDetails = utils.detectBrowser(window);    if (!('sctp' in window.RTCPeerConnection.prototype)) {      Object.defineProperty(window.RTCPeerConnection.prototype, 'sctp', {        get: function() {          return typeof this._sctp === 'undefined' ? null : this._sctp;        }      });    }    var sctpInDescription = function(description) {      var sections = SDPUtils.splitSections(description.sdp);      sections.shift();      return sections.some(function(mediaSection) {        var mLine = SDPUtils.parseMLine(mediaSection);        return mLine && mLine.kind === 'application'            && mLine.protocol.indexOf('SCTP') !== -1;      });    };    var getRemoteFirefoxVersion = function(description) {      // TODO: Is there a better solution for detecting Firefox?      var match = description.sdp.match(/mozilla...THIS_IS_SDPARTA-(\d+)/);      if (match === null || match.length < 2) {        return -1;      }      var version = parseInt(match[1], 10);      // Test for NaN (yes, this is ugly)      return version !== version ? -1 : version;    };    var getCanSendMaxMessageSize = function(remoteIsFirefox) {      // Every implementation we know can send at least 64 KiB.      // Note: Although Chrome is technically able to send up to 256 KiB, the      //       data does not reach the other peer reliably.      //       See: https://bugs.chromium.org/p/webrtc/issues/detail?id=8419      var canSendMaxMessageSize = 65536;      if (browserDetails.browser === 'firefox') {        if (browserDetails.version < 57) {          if (remoteIsFirefox === -1) {            // FF < 57 will send in 16 KiB chunks using the deprecated PPID            // fragmentation.            canSendMaxMessageSize = 16384;          } else {            // However, other FF (and RAWRTC) can reassemble PPID-fragmented            // messages. Thus, supporting ~2 GiB when sending.            canSendMaxMessageSize = 2147483637;          }        } else {          // Currently, all FF >= 57 will reset the remote maximum message size          // to the default value when a data channel is created at a later          // stage. :(          // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1426831          canSendMaxMessageSize =            browserDetails.version === 57 ? 65535 : 65536;        }      }      return canSendMaxMessageSize;    };    var getMaxMessageSize = function(description, remoteIsFirefox) {      // Note: 65536 bytes is the default value from the SDP spec. Also,      //       every implementation we know supports receiving 65536 bytes.      var maxMessageSize = 65536;      // FF 57 has a slightly incorrect default remote max message size, so      // we need to adjust it here to avoid a failure when sending.      // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1425697      if (browserDetails.browser === 'firefox'           && browserDetails.version === 57) {        maxMessageSize = 65535;      }      var match = SDPUtils.matchPrefix(description.sdp, 'a=max-message-size:');      if (match.length > 0) {        maxMessageSize = parseInt(match[0].substr(19), 10);      } else if (browserDetails.browser === 'firefox' &&                  remoteIsFirefox !== -1) {        // If the maximum message size is not present in the remote SDP and        // both local and remote are Firefox, the remote peer can receive        // ~2 GiB.        maxMessageSize = 2147483637;      }      return maxMessageSize;    };    var origSetRemoteDescription =        window.RTCPeerConnection.prototype.setRemoteDescription;    window.RTCPeerConnection.prototype.setRemoteDescription = function() {      var pc = this;      pc._sctp = null;      if (sctpInDescription(arguments[0])) {        // Check if the remote is FF.        var isFirefox = getRemoteFirefoxVersion(arguments[0]);        // Get the maximum message size the local peer is capable of sending        var canSendMMS = getCanSendMaxMessageSize(isFirefox);        // Get the maximum message size of the remote peer.        var remoteMMS = getMaxMessageSize(arguments[0], isFirefox);        // Determine final maximum message size        var maxMessageSize;        if (canSendMMS === 0 && remoteMMS === 0) {          maxMessageSize = Number.POSITIVE_INFINITY;        } else if (canSendMMS === 0 || remoteMMS === 0) {          maxMessageSize = Math.max(canSendMMS, remoteMMS);        } else {          maxMessageSize = Math.min(canSendMMS, remoteMMS);        }        // Create a dummy RTCSctpTransport object and the 'maxMessageSize'        // attribute.        var sctp = {};        Object.defineProperty(sctp, 'maxMessageSize', {          get: function() {            return maxMessageSize;          }        });        pc._sctp = sctp;      }      return origSetRemoteDescription.apply(pc, arguments);    };  },  shimSendThrowTypeError: function(window) {    // Note: Although Firefox >= 57 has a native implementation, the maximum    //       message size can be reset for all data channels at a later stage.    //       See: https://bugzilla.mozilla.org/show_bug.cgi?id=1426831    var origCreateDataChannel =      window.RTCPeerConnection.prototype.createDataChannel;    window.RTCPeerConnection.prototype.createDataChannel = function() {      var pc = this;      var dataChannel = origCreateDataChannel.apply(pc, arguments);      var origDataChannelSend = dataChannel.send;      // Patch 'send' method      dataChannel.send = function() {        var dc = this;        var data = arguments[0];        var length = data.length || data.size || data.byteLength;        if (length > pc.sctp.maxMessageSize) {          throw new DOMException('Message too large (can send a maximum of ' +            pc.sctp.maxMessageSize + ' bytes)', 'TypeError');        }        return origDataChannelSend.apply(dc, arguments);      };      return dataChannel;    };  }};},{"./utils":13,"sdp":2}],8:[function(require,module,exports){/* *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * *  Use of this source code is governed by a BSD-style license *  that can be found in the LICENSE file in the root of the source *  tree. */ /* eslint-env node */'use strict';var utils = require('../utils');var shimRTCPeerConnection = require('rtcpeerconnection-shim');module.exports = {  shimGetUserMedia: require('./getusermedia'),  shimPeerConnection: function(window) {    var browserDetails = utils.detectBrowser(window);    if (window.RTCIceGatherer) {      // ORTC defines an RTCIceCandidate object but no constructor.      // Not implemented in Edge.      if (!window.RTCIceCandidate) {        window.RTCIceCandidate = function(args) {          return args;        };      }      // ORTC does not have a session description object but      // other browsers (i.e. Chrome) that will support both PC and ORTC      // in the future might have this defined already.      if (!window.RTCSessionDescription) {        window.RTCSessionDescription = function(args) {          return args;        };      }      // this adds an additional event listener to MediaStrackTrack that signals      // when a tracks enabled property was changed. Workaround for a bug in      // addStream, see below. No longer required in 15025+      if (browserDetails.version < 15025) {        var origMSTEnabled = Object.getOwnPropertyDescriptor(            window.MediaStreamTrack.prototype, 'enabled');        Object.defineProperty(window.MediaStreamTrack.prototype, 'enabled', {          set: function(value) {            origMSTEnabled.set.call(this, value);            var ev = new Event('enabled');            ev.enabled = value;            this.dispatchEvent(ev);          }        });      }    }    // ORTC defines the DTMF sender a bit different.    // https://github.com/w3c/ortc/issues/714    if (window.RTCRtpSender && !('dtmf' in window.RTCRtpSender.prototype)) {      Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', {        get: function() {          if (this._dtmf === undefined) {            if (this.track.kind === 'audio') {              this._dtmf = new window.RTCDtmfSender(this);            } else if (this.track.kind === 'video') {              this._dtmf = null;            }          }          return this._dtmf;        }      });    }    window.RTCPeerConnection =        shimRTCPeerConnection(window, browserDetails.version);  },  shimReplaceTrack: function(window) {    // ORTC has replaceTrack -- https://github.com/w3c/ortc/issues/614    if (window.RTCRtpSender &&        !('replaceTrack' in window.RTCRtpSender.prototype)) {      window.RTCRtpSender.prototype.replaceTrack =          window.RTCRtpSender.prototype.setTrack;    }  }};},{"../utils":13,"./getusermedia":9,"rtcpeerconnection-shim":1}],9:[function(require,module,exports){/* *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * *  Use of this source code is governed by a BSD-style license *  that can be found in the LICENSE file in the root of the source *  tree. */ /* eslint-env node */'use strict';// Expose public methods.module.exports = function(window) {  var navigator = window && window.navigator;  var shimError_ = function(e) {    return {      name: {PermissionDeniedError: 'NotAllowedError'}[e.name] || e.name,      message: e.message,      constraint: e.constraint,      toString: function() {        return this.name;      }    };  };  // getUserMedia error shim.  var origGetUserMedia = navigator.mediaDevices.getUserMedia.      bind(navigator.mediaDevices);  navigator.mediaDevices.getUserMedia = function(c) {    return origGetUserMedia(c).catch(function(e) {      return Promise.reject(shimError_(e));    });  };};},{}],10:[function(require,module,exports){/* *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * *  Use of this source code is governed by a BSD-style license *  that can be found in the LICENSE file in the root of the source *  tree. */ /* eslint-env node */'use strict';var utils = require('../utils');module.exports = {  shimGetUserMedia: require('./getusermedia'),  shimOnTrack: function(window) {    if (typeof window === 'object' && window.RTCPeerConnection && !('ontrack' in        window.RTCPeerConnection.prototype)) {      Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', {        get: function() {          return this._ontrack;        },        set: function(f) {          if (this._ontrack) {            this.removeEventListener('track', this._ontrack);            this.removeEventListener('addstream', this._ontrackpoly);          }          this.addEventListener('track', this._ontrack = f);          this.addEventListener('addstream', this._ontrackpoly = function(e) {            e.stream.getTracks().forEach(function(track) {              var event = new Event('track');              event.track = track;              event.receiver = {track: track};              event.transceiver = {receiver: event.receiver};              event.streams = [e.stream];              this.dispatchEvent(event);            }.bind(this));          }.bind(this));        }      });    }    if (typeof window === 'object' && window.RTCTrackEvent &&        ('receiver' in window.RTCTrackEvent.prototype) &&        !('transceiver' in window.RTCTrackEvent.prototype)) {      Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', {        get: function() {          return {receiver: this.receiver};        }      });    }  },  shimSourceObject: function(window) {    // Firefox has supported mozSrcObject since FF22, unprefixed in 42.    if (typeof window === 'object') {      if (window.HTMLMediaElement &&        !('srcObject' in window.HTMLMediaElement.prototype)) {        // Shim the srcObject property, once, when HTMLMediaElement is found.        Object.defineProperty(window.HTMLMediaElement.prototype, 'srcObject', {          get: function() {            return this.mozSrcObject;          },          set: function(stream) {            this.mozSrcObject = stream;          }        });      }    }  },  shimPeerConnection: function(window) {    var browserDetails = utils.detectBrowser(window);    if (typeof window !== 'object' || !(window.RTCPeerConnection ||        window.mozRTCPeerConnection)) {      return; // probably media.peerconnection.enabled=false in about:config    }    // The RTCPeerConnection object.    if (!window.RTCPeerConnection) {      window.RTCPeerConnection = function(pcConfig, pcConstraints) {        if (browserDetails.version < 38) {          // .urls is not supported in FF < 38.          // create RTCIceServers with a single url.          if (pcConfig && pcConfig.iceServers) {            var newIceServers = [];            for (var i = 0; i < pcConfig.iceServers.length; i++) {              var server = pcConfig.iceServers[i];              if (server.hasOwnProperty('urls')) {                for (var j = 0; j < server.urls.length; j++) {                  var newServer = {                    url: server.urls[j]                  };                  if (server.urls[j].indexOf('turn') === 0) {                    newServer.username = server.username;                    newServer.credential = server.credential;                  }                  newIceServers.push(newServer);                }              } else {                newIceServers.push(pcConfig.iceServers[i]);              }            }            pcConfig.iceServers = newIceServers;          }        }        return new window.mozRTCPeerConnection(pcConfig, pcConstraints);      };      window.RTCPeerConnection.prototype =          window.mozRTCPeerConnection.prototype;      // wrap static methods. Currently just generateCertificate.      if (window.mozRTCPeerConnection.generateCertificate) {        Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', {          get: function() {            return window.mozRTCPeerConnection.generateCertificate;          }        });      }      window.RTCSessionDescription = window.mozRTCSessionDescription;      window.RTCIceCandidate = window.mozRTCIceCandidate;    }    // shim away need for obsolete RTCIceCandidate/RTCSessionDescription.    ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate']        .forEach(function(method) {          var nativeMethod = window.RTCPeerConnection.prototype[method];          window.RTCPeerConnection.prototype[method] = function() {            arguments[0] = new ((method === 'addIceCandidate') ?                window.RTCIceCandidate :                window.RTCSessionDescription)(arguments[0]);            return nativeMethod.apply(this, arguments);          };        });    // support for addIceCandidate(null or undefined)    var nativeAddIceCandidate =        window.RTCPeerConnection.prototype.addIceCandidate;    window.RTCPeerConnection.prototype.addIceCandidate = function() {      if (!arguments[0]) {        if (arguments[1]) {          arguments[1].apply(null);        }        return Promise.resolve();      }      return nativeAddIceCandidate.apply(this, arguments);    };    // shim getStats with maplike support    var makeMapStats = function(stats) {      var map = new Map();      Object.keys(stats).forEach(function(key) {        map.set(key, stats[key]);        map[key] = stats[key];      });      return map;    };    var modernStatsTypes = {      inboundrtp: 'inbound-rtp',      outboundrtp: 'outbound-rtp',      candidatepair: 'candidate-pair',      localcandidate: 'local-candidate',      remotecandidate: 'remote-candidate'    };    var nativeGetStats = window.RTCPeerConnection.prototype.getStats;    window.RTCPeerConnection.prototype.getStats = function(      selector,      onSucc,      onErr    ) {      return nativeGetStats.apply(this, [selector || null])        .then(function(stats) {          if (browserDetails.version < 48) {            stats = makeMapStats(stats);          }          if (browserDetails.version < 53 && !onSucc) {            // Shim only promise getStats with spec-hyphens in type names            // Leave callback version alone; misc old uses of forEach before Map            try {              stats.forEach(function(stat) {                stat.type = modernStatsTypes[stat.type] || stat.type;              });            } catch (e) {              if (e.name !== 'TypeError') {                throw e;              }              // Avoid TypeError: "type" is read-only, in old versions. 34-43ish              stats.forEach(function(stat, i) {                stats.set(i, Object.assign({}, stat, {                  type: modernStatsTypes[stat.type] || stat.type                }));              });            }          }          return stats;        })        .then(onSucc, onErr);    };  },  shimRemoveStream: function(window) {    if (!window.RTCPeerConnection ||        'removeStream' in window.RTCPeerConnection.prototype) {      return;    }    window.RTCPeerConnection.prototype.removeStream = function(stream) {      var pc = this;      utils.deprecated('removeStream', 'removeTrack');      this.getSenders().forEach(function(sender) {        if (sender.track && stream.getTracks().indexOf(sender.track) !== -1) {          pc.removeTrack(sender);        }      });    };  }};},{"../utils":13,"./getusermedia":11}],11:[function(require,module,exports){/* *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * *  Use of this source code is governed by a BSD-style license *  that can be found in the LICENSE file in the root of the source *  tree. */ /* eslint-env node */'use strict';var utils = require('../utils');var logging = utils.log;// Expose public methods.module.exports = function(window) {  var browserDetails = utils.detectBrowser(window);  var navigator = window && window.navigator;  var MediaStreamTrack = window && window.MediaStreamTrack;  var shimError_ = function(e) {    return {      name: {        InternalError: 'NotReadableError',        NotSupportedError: 'TypeError',        PermissionDeniedError: 'NotAllowedError',        SecurityError: 'NotAllowedError'      }[e.name] || e.name,      message: {        'The operation is insecure.': 'The request is not allowed by the ' +        'user agent or the platform in the current context.'      }[e.message] || e.message,      constraint: e.constraint,      toString: function() {        return this.name + (this.message && ': ') + this.message;      }    };  };  // getUserMedia constraints shim.  var getUserMedia_ = function(constraints, onSuccess, onError) {    var constraintsToFF37_ = function(c) {      if (typeof c !== 'object' || c.require) {        return c;      }      var require = [];      Object.keys(c).forEach(function(key) {        if (key === 'require' || key === 'advanced' || key === 'mediaSource') {          return;        }        var r = c[key] = (typeof c[key] === 'object') ?            c[key] : {ideal: c[key]};        if (r.min !== undefined ||            r.max !== undefined || r.exact !== undefined) {          require.push(key);        }        if (r.exact !== undefined) {          if (typeof r.exact === 'number') {            r. min = r.max = r.exact;          } else {            c[key] = r.exact;          }          delete r.exact;        }        if (r.ideal !== undefined) {          c.advanced = c.advanced || [];          var oc = {};          if (typeof r.ideal === 'number') {            oc[key] = {min: r.ideal, max: r.ideal};          } else {            oc[key] = r.ideal;          }          c.advanced.push(oc);          delete r.ideal;          if (!Object.keys(r).length) {            delete c[key];          }        }      });      if (require.length) {        c.require = require;      }      return c;    };    constraints = JSON.parse(JSON.stringify(constraints));    if (browserDetails.version < 38) {      logging('spec: ' + JSON.stringify(constraints));      if (constraints.audio) {        constraints.audio = constraintsToFF37_(constraints.audio);      }      if (constraints.video) {        constraints.video = constraintsToFF37_(constraints.video);      }      logging('ff37: ' + JSON.stringify(constraints));    }    return navigator.mozGetUserMedia(constraints, onSuccess, function(e) {      onError(shimError_(e));    });  };  // Returns the result of getUserMedia as a Promise.  var getUserMediaPromise_ = function(constraints) {    return new Promise(function(resolve, reject) {      getUserMedia_(constraints, resolve, reject);    });  };  // Shim for mediaDevices on older versions.  if (!navigator.mediaDevices) {    navigator.mediaDevices = {getUserMedia: getUserMediaPromise_,      addEventListener: function() { },      removeEventListener: function() { }    };  }  navigator.mediaDevices.enumerateDevices =      navigator.mediaDevices.enumerateDevices || function() {        return new Promise(function(resolve) {          var infos = [            {kind: 'audioinput', deviceId: 'default', label: '', groupId: ''},            {kind: 'videoinput', deviceId: 'default', label: '', groupId: ''}          ];          resolve(infos);        });      };  if (browserDetails.version < 41) {    // Work around http://bugzil.la/1169665    var orgEnumerateDevices =        navigator.mediaDevices.enumerateDevices.bind(navigator.mediaDevices);    navigator.mediaDevices.enumerateDevices = function() {      return orgEnumerateDevices().then(undefined, function(e) {        if (e.name === 'NotFoundError') {          return [];        }        throw e;      });    };  }  if (browserDetails.version < 49) {    var origGetUserMedia = navigator.mediaDevices.getUserMedia.        bind(navigator.mediaDevices);    navigator.mediaDevices.getUserMedia = function(c) {      return origGetUserMedia(c).then(function(stream) {        // Work around https://bugzil.la/802326        if (c.audio && !stream.getAudioTracks().length ||            c.video && !stream.getVideoTracks().length) {          stream.getTracks().forEach(function(track) {            track.stop();          });          throw new DOMException('The object can not be found here.',                                 'NotFoundError');        }        return stream;      }, function(e) {        return Promise.reject(shimError_(e));      });    };  }  if (!(browserDetails.version > 55 &&      'autoGainControl' in navigator.mediaDevices.getSupportedConstraints())) {    var remap = function(obj, a, b) {      if (a in obj && !(b in obj)) {        obj[b] = obj[a];        delete obj[a];      }    };    var nativeGetUserMedia = navigator.mediaDevices.getUserMedia.        bind(navigator.mediaDevices);    navigator.mediaDevices.getUserMedia = function(c) {      if (typeof c === 'object' && typeof c.audio === 'object') {        c = JSON.parse(JSON.stringify(c));        remap(c.audio, 'autoGainControl', 'mozAutoGainControl');        remap(c.audio, 'noiseSuppression', 'mozNoiseSuppression');      }      return nativeGetUserMedia(c);    };    if (MediaStreamTrack && MediaStreamTrack.prototype.getSettings) {      var nativeGetSettings = MediaStreamTrack.prototype.getSettings;      MediaStreamTrack.prototype.getSettings = function() {        var obj = nativeGetSettings.apply(this, arguments);        remap(obj, 'mozAutoGainControl', 'autoGainControl');        remap(obj, 'mozNoiseSuppression', 'noiseSuppression');        return obj;      };    }    if (MediaStreamTrack && MediaStreamTrack.prototype.applyConstraints) {      var nativeApplyConstraints = MediaStreamTrack.prototype.applyConstraints;      MediaStreamTrack.prototype.applyConstraints = function(c) {        if (this.kind === 'audio' && typeof c === 'object') {          c = JSON.parse(JSON.stringify(c));          remap(c, 'autoGainControl', 'mozAutoGainControl');          remap(c, 'noiseSuppression', 'mozNoiseSuppression');        }        return nativeApplyConstraints.apply(this, [c]);      };    }  }  navigator.getUserMedia = function(constraints, onSuccess, onError) {    if (browserDetails.version < 44) {      return getUserMedia_(constraints, onSuccess, onError);    }    // Replace Firefox 44+'s deprecation warning with unprefixed version.    utils.deprecated('navigator.getUserMedia',        'navigator.mediaDevices.getUserMedia');    navigator.mediaDevices.getUserMedia(constraints).then(onSuccess, onError);  };};},{"../utils":13}],12:[function(require,module,exports){/* *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * *  Use of this source code is governed by a BSD-style license *  that can be found in the LICENSE file in the root of the source *  tree. */'use strict';var utils = require('../utils');module.exports = {  shimLocalStreamsAPI: function(window) {    if (typeof window !== 'object' || !window.RTCPeerConnection) {      return;    }    if (!('getLocalStreams' in window.RTCPeerConnection.prototype)) {      window.RTCPeerConnection.prototype.getLocalStreams = function() {        if (!this._localStreams) {          this._localStreams = [];        }        return this._localStreams;      };    }    if (!('getStreamById' in window.RTCPeerConnection.prototype)) {      window.RTCPeerConnection.prototype.getStreamById = function(id) {        var result = null;        if (this._localStreams) {          this._localStreams.forEach(function(stream) {            if (stream.id === id) {              result = stream;            }          });        }        if (this._remoteStreams) {          this._remoteStreams.forEach(function(stream) {            if (stream.id === id) {              result = stream;            }          });        }        return result;      };    }    if (!('addStream' in window.RTCPeerConnection.prototype)) {      var _addTrack = window.RTCPeerConnection.prototype.addTrack;      window.RTCPeerConnection.prototype.addStream = function(stream) {        if (!this._localStreams) {          this._localStreams = [];        }        if (this._localStreams.indexOf(stream) === -1) {          this._localStreams.push(stream);        }        var pc = this;        stream.getTracks().forEach(function(track) {          _addTrack.call(pc, track, stream);        });      };      window.RTCPeerConnection.prototype.addTrack = function(track, stream) {        if (stream) {          if (!this._localStreams) {            this._localStreams = [stream];          } else if (this._localStreams.indexOf(stream) === -1) {            this._localStreams.push(stream);          }        }        return _addTrack.call(this, track, stream);      };    }    if (!('removeStream' in window.RTCPeerConnection.prototype)) {      window.RTCPeerConnection.prototype.removeStream = function(stream) {        if (!this._localStreams) {          this._localStreams = [];        }        var index = this._localStreams.indexOf(stream);        if (index === -1) {          return;        }        this._localStreams.splice(index, 1);        var pc = this;        var tracks = stream.getTracks();        this.getSenders().forEach(function(sender) {          if (tracks.indexOf(sender.track) !== -1) {            pc.removeTrack(sender);          }        });      };    }  },  shimRemoteStreamsAPI: function(window) {    if (typeof window !== 'object' || !window.RTCPeerConnection) {      return;    }    if (!('getRemoteStreams' in window.RTCPeerConnection.prototype)) {      window.RTCPeerConnection.prototype.getRemoteStreams = function() {        return this._remoteStreams ? this._remoteStreams : [];      };    }    if (!('onaddstream' in window.RTCPeerConnection.prototype)) {      Object.defineProperty(window.RTCPeerConnection.prototype, 'onaddstream', {        get: function() {          return this._onaddstream;        },        set: function(f) {          var pc = this;          if (this._onaddstream) {            this.removeEventListener('addstream', this._onaddstream);            this.removeEventListener('track', this._onaddstreampoly);          }          this.addEventListener('addstream', this._onaddstream = f);          this.addEventListener('track', this._onaddstreampoly = function(e) {            e.streams.forEach(function(stream) {              if (!pc._remoteStreams) {                pc._remoteStreams = [];              }              if (pc._remoteStreams.indexOf(stream) >= 0) {                return;              }              pc._remoteStreams.push(stream);              var event = new Event('addstream');              event.stream = stream;              pc.dispatchEvent(event);            });          });        }      });    }  },  shimCallbacksAPI: function(window) {    if (typeof window !== 'object' || !window.RTCPeerConnection) {      return;    }    var prototype = window.RTCPeerConnection.prototype;    var createOffer = prototype.createOffer;    var createAnswer = prototype.createAnswer;    var setLocalDescription = prototype.setLocalDescription;    var setRemoteDescription = prototype.setRemoteDescription;    var addIceCandidate = prototype.addIceCandidate;    prototype.createOffer = function(successCallback, failureCallback) {      var options = (arguments.length >= 2) ? arguments[2] : arguments[0];      var promise = createOffer.apply(this, [options]);      if (!failureCallback) {        return promise;      }      promise.then(successCallback, failureCallback);      return Promise.resolve();    };    prototype.createAnswer = function(successCallback, failureCallback) {      var options = (arguments.length >= 2) ? arguments[2] : arguments[0];      var promise = createAnswer.apply(this, [options]);      if (!failureCallback) {        return promise;      }      promise.then(successCallback, failureCallback);      return Promise.resolve();    };    var withCallback = function(description, successCallback, failureCallback) {      var promise = setLocalDescription.apply(this, [description]);      if (!failureCallback) {        return promise;      }      promise.then(successCallback, failureCallback);      return Promise.resolve();    };    prototype.setLocalDescription = withCallback;    withCallback = function(description, successCallback, failureCallback) {      var promise = setRemoteDescription.apply(this, [description]);      if (!failureCallback) {        return promise;      }      promise.then(successCallback, failureCallback);      return Promise.resolve();    };    prototype.setRemoteDescription = withCallback;    withCallback = function(candidate, successCallback, failureCallback) {      var promise = addIceCandidate.apply(this, [candidate]);      if (!failureCallback) {        return promise;      }      promise.then(successCallback, failureCallback);      return Promise.resolve();    };    prototype.addIceCandidate = withCallback;  },  shimGetUserMedia: function(window) {    var navigator = window && window.navigator;    if (!navigator.getUserMedia) {      if (navigator.webkitGetUserMedia) {        navigator.getUserMedia = navigator.webkitGetUserMedia.bind(navigator);      } else if (navigator.mediaDevices &&          navigator.mediaDevices.getUserMedia) {        navigator.getUserMedia = function(constraints, cb, errcb) {          navigator.mediaDevices.getUserMedia(constraints)          .then(cb, errcb);        }.bind(navigator);      }    }  },  shimRTCIceServerUrls: function(window) {    // migrate from non-spec RTCIceServer.url to RTCIceServer.urls    var OrigPeerConnection = window.RTCPeerConnection;    window.RTCPeerConnection = function(pcConfig, pcConstraints) {      if (pcConfig && pcConfig.iceServers) {        var newIceServers = [];        for (var i = 0; i < pcConfig.iceServers.length; i++) {          var server = pcConfig.iceServers[i];          if (!server.hasOwnProperty('urls') &&              server.hasOwnProperty('url')) {            utils.deprecated('RTCIceServer.url', 'RTCIceServer.urls');            server = JSON.parse(JSON.stringify(server));            server.urls = server.url;            delete server.url;            newIceServers.push(server);          } else {            newIceServers.push(pcConfig.iceServers[i]);          }        }        pcConfig.iceServers = newIceServers;      }      return new OrigPeerConnection(pcConfig, pcConstraints);    };    window.RTCPeerConnection.prototype = OrigPeerConnection.prototype;    // wrap static methods. Currently just generateCertificate.    if ('generateCertificate' in window.RTCPeerConnection) {      Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', {        get: function() {          return OrigPeerConnection.generateCertificate;        }      });    }  },  shimTrackEventTransceiver: function(window) {    // Add event.transceiver member over deprecated event.receiver    if (typeof window === 'object' && window.RTCPeerConnection &&        ('receiver' in window.RTCTrackEvent.prototype) &&        // can't check 'transceiver' in window.RTCTrackEvent.prototype, as it is        // defined for some reason even when window.RTCTransceiver is not.        !window.RTCTransceiver) {      Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', {        get: function() {          return {receiver: this.receiver};        }      });    }  },  shimCreateOfferLegacy: function(window) {    var origCreateOffer = window.RTCPeerConnection.prototype.createOffer;    window.RTCPeerConnection.prototype.createOffer = function(offerOptions) {      var pc = this;      if (offerOptions) {        var audioTransceiver = pc.getTransceivers().find(function(transceiver) {          return transceiver.sender.track &&              transceiver.sender.track.kind === 'audio';        });        if (offerOptions.offerToReceiveAudio === false && audioTransceiver) {          if (audioTransceiver.direction === 'sendrecv') {            if (audioTransceiver.setDirection) {              audioTransceiver.setDirection('sendonly');            } else {              audioTransceiver.direction = 'sendonly';            }          } else if (audioTransceiver.direction === 'recvonly') {            if (audioTransceiver.setDirection) {              audioTransceiver.setDirection('inactive');            } else {              audioTransceiver.direction = 'inactive';            }          }        } else if (offerOptions.offerToReceiveAudio === true &&            !audioTransceiver) {          pc.addTransceiver('audio');        }        var videoTransceiver = pc.getTransceivers().find(function(transceiver) {          return transceiver.sender.track &&              transceiver.sender.track.kind === 'video';        });        if (offerOptions.offerToReceiveVideo === false && videoTransceiver) {          if (videoTransceiver.direction === 'sendrecv') {            videoTransceiver.setDirection('sendonly');          } else if (videoTransceiver.direction === 'recvonly') {            videoTransceiver.setDirection('inactive');          }        } else if (offerOptions.offerToReceiveVideo === true &&            !videoTransceiver) {          pc.addTransceiver('video');        }      }      return origCreateOffer.apply(pc, arguments);    };  }};},{"../utils":13}],13:[function(require,module,exports){/* *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * *  Use of this source code is governed by a BSD-style license *  that can be found in the LICENSE file in the root of the source *  tree. */ /* eslint-env node */'use strict';var logDisabled_ = true;var deprecationWarnings_ = true;/** * Extract browser version out of the provided user agent string. * * @param {!string} uastring userAgent string. * @param {!string} expr Regular expression used as match criteria. * @param {!number} pos position in the version string to be returned. * @return {!number} browser version. */function extractVersion(uastring, expr, pos) {  var match = uastring.match(expr);  return match && match.length >= pos && parseInt(match[pos], 10);}// Wraps the peerconnection event eventNameToWrap in a function// which returns the modified event object.function wrapPeerConnectionEvent(window, eventNameToWrap, wrapper) {  if (!window.RTCPeerConnection) {    return;  }  var proto = window.RTCPeerConnection.prototype;  var nativeAddEventListener = proto.addEventListener;  proto.addEventListener = function(nativeEventName, cb) {    if (nativeEventName !== eventNameToWrap) {      return nativeAddEventListener.apply(this, arguments);    }    var wrappedCallback = function(e) {      cb(wrapper(e));    };    this._eventMap = this._eventMap || {};    this._eventMap[cb] = wrappedCallback;    return nativeAddEventListener.apply(this, [nativeEventName,      wrappedCallback]);  };  var nativeRemoveEventListener = proto.removeEventListener;  proto.removeEventListener = function(nativeEventName, cb) {    if (nativeEventName !== eventNameToWrap || !this._eventMap        || !this._eventMap[cb]) {      return nativeRemoveEventListener.apply(this, arguments);    }    var unwrappedCb = this._eventMap[cb];    delete this._eventMap[cb];    return nativeRemoveEventListener.apply(this, [nativeEventName,      unwrappedCb]);  };  Object.defineProperty(proto, 'on' + eventNameToWrap, {    get: function() {      return this['_on' + eventNameToWrap];    },    set: function(cb) {      if (this['_on' + eventNameToWrap]) {        this.removeEventListener(eventNameToWrap,            this['_on' + eventNameToWrap]);        delete this['_on' + eventNameToWrap];      }      if (cb) {        this.addEventListener(eventNameToWrap,            this['_on' + eventNameToWrap] = cb);      }    }  });}// Utility methods.module.exports = {  extractVersion: extractVersion,  wrapPeerConnectionEvent: wrapPeerConnectionEvent,  disableLog: function(bool) {    if (typeof bool !== 'boolean') {      return new Error('Argument type: ' + typeof bool +          '. Please use a boolean.');    }    logDisabled_ = bool;    return (bool) ? 'adapter.js logging disabled' :        'adapter.js logging enabled';  },  /**   * Disable or enable deprecation warnings   * @param {!boolean} bool set to true to disable warnings.   */  disableWarnings: function(bool) {    if (typeof bool !== 'boolean') {      return new Error('Argument type: ' + typeof bool +          '. Please use a boolean.');    }    deprecationWarnings_ = !bool;    return 'adapter.js deprecation warnings ' + (bool ? 'disabled' : 'enabled');  },  log: function() {    if (typeof window === 'object') {      if (logDisabled_) {        return;      }      if (typeof console !== 'undefined' && typeof console.log === 'function') {        console.log.apply(console, arguments);      }    }  },  /**   * Shows a deprecation warning suggesting the modern and spec-compatible API.   */  deprecated: function(oldMethod, newMethod) {    if (!deprecationWarnings_) {      return;    }    console.warn(oldMethod + ' is deprecated, please use ' + newMethod +        ' instead.');  },  /**   * Browser detector.   *   * @return {object} result containing browser and version   *     properties.   */  detectBrowser: function(window) {    var navigator = window && window.navigator;    // Returned result object.    var result = {};    result.browser = null;    result.version = null;    // Fail early if it's not a browser    if (typeof window === 'undefined' || !window.navigator) {      result.browser = 'Not a browser.';      return result;    }    // Firefox.    if (navigator.mozGetUserMedia) {      result.browser = 'firefox';      result.version = extractVersion(navigator.userAgent,          /Firefox\/(\d+)\./, 1);    } else if (navigator.webkitGetUserMedia) {      // Chrome, Chromium, Webview, Opera, all use the chrome shim for now      if (window.webkitRTCPeerConnection) {        result.browser = 'chrome';        result.version = extractVersion(navigator.userAgent,          /Chrom(e|ium)\/(\d+)\./, 2);      } else { // Safari (in an unpublished version) or unknown webkit-based.        if (navigator.userAgent.match(/Version\/(\d+).(\d+)/)) {          result.browser = 'safari';          result.version = extractVersion(navigator.userAgent,            /AppleWebKit\/(\d+)\./, 1);        } else { // unknown webkit-based browser.          result.browser = 'Unsupported webkit-based browser ' +              'with GUM support but no WebRTC support.';          return result;        }      }    } else if (navigator.mediaDevices &&        navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)) { // Edge.      result.browser = 'edge';      result.version = extractVersion(navigator.userAgent,          /Edge\/(\d+).(\d+)$/, 2);    } else if (navigator.mediaDevices &&        navigator.userAgent.match(/AppleWebKit\/(\d+)\./)) {        // Safari, with webkitGetUserMedia removed.      result.browser = 'safari';      result.version = extractVersion(navigator.userAgent,          /AppleWebKit\/(\d+)\./, 1);    } else { // Default fallthrough: not supported.      result.browser = 'Not a supported browser.';      return result;    }    return result;  }};},{}]},{},[3])(3)});
 |