ZLMRTCClient.js 268 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365
  1. let ZLMRTCClient = (function (exports) {
  2. 'use strict';
  3. const Events$1 = {
  4. WEBRTC_NOT_SUPPORT: 'WEBRTC_NOT_SUPPORT',
  5. WEBRTC_ICE_CANDIDATE_ERROR: 'WEBRTC_ICE_CANDIDATE_ERROR',
  6. WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED: 'WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED',
  7. WEBRTC_ON_REMOTE_STREAMS: 'WEBRTC_ON_REMOTE_STREAMS',
  8. WEBRTC_ON_LOCAL_STREAM: 'WEBRTC_ON_LOCAL_STREAM',
  9. WEBRTC_ON_CONNECTION_STATE_CHANGE: 'WEBRTC_ON_CONNECTION_STATE_CHANGE',
  10. WEBRTC_ON_DATA_CHANNEL_OPEN: 'WEBRTC_ON_DATA_CHANNEL_OPEN',
  11. WEBRTC_ON_DATA_CHANNEL_CLOSE: 'WEBRTC_ON_DATA_CHANNEL_CLOSE',
  12. WEBRTC_ON_DATA_CHANNEL_ERR: 'WEBRTC_ON_DATA_CHANNEL_ERR',
  13. WEBRTC_ON_DATA_CHANNEL_MSG: 'WEBRTC_ON_DATA_CHANNEL_MSG',
  14. CAPTURE_STREAM_FAILED: 'CAPTURE_STREAM_FAILED',
  15. CONNECT_FAIL: 'CONNECT_FAIL',// web端连接 zlm 失败
  16. };
  17. /// ^rtpmap:\d+ PCMU\/8000(\r\n|\n)?$/g
  18. // 替换replaceStr
  19. const audioEncoding = {
  20. 0: {
  21. name: "PCMU",
  22. replaceStr: /a=rtpmap:0 PCMU\/8000(\r\n|\r|\n)/
  23. },
  24. 8: {
  25. name: "PCMA",
  26. replaceStr: /a=rtpmap:8 PCMA\/8000(\r\n|\r|\n)/
  27. },
  28. 9: {
  29. name: "G722",
  30. replaceStr: /a=rtpmap:9 G722\/8000(\r\n|\r|\n)/
  31. },
  32. 13: {
  33. name: "CN",
  34. replaceStr: /a=rtpmap:13 CN\/8000(\r\n|\r|\n)/
  35. }
  36. };
  37. // const audioEncoding = {
  38. // 0:{ name: "PCMU", replaceStr:/a=rtpmap:0 PCMU/8000/ },
  39. // 8:{ name: "PCMA", replaceStr:/a=rtpmap:8 PCMA/8000/ },
  40. // 9:{ name: "G722", replaceStr:/a=rtpmap:9 G722/8000/ },
  41. // 13:{ name: "CN", replaceStr:/a=rtpmap:13 CN/8000/ } }
  42. const VERSION$1 = '1.0.1';
  43. const BUILD_DATE = 'Mon Jul 04 2022 19:50:55 GMT+0800 (China Standard Time)';
  44. // Copyright (C) <2018> Intel Corporation
  45. //
  46. // SPDX-License-Identifier: Apache-2.0
  47. // eslint-disable-next-line require-jsdoc
  48. function isFirefox() {
  49. return window.navigator.userAgent.match('Firefox') !== null;
  50. } // eslint-disable-next-line require-jsdoc
  51. function isChrome() {
  52. return window.navigator.userAgent.match('Chrome') !== null;
  53. } // eslint-disable-next-line require-jsdoc
  54. function isEdge() {
  55. return window.navigator.userAgent.match(/Edge\/(\d+).(\d+)$/) !== null;
  56. } // eslint-disable-next-line require-jsdoc
  57. // Copyright (C) <2018> Intel Corporation
  58. /**
  59. * @class AudioSourceInfo
  60. * @classDesc Source info about an audio track. Values: 'mic', 'screen-cast', 'file', 'mixed'.
  61. * @memberOf Owt.Base
  62. * @readonly
  63. * @enum {string}
  64. */
  65. const AudioSourceInfo = {
  66. MIC: 'mic',
  67. SCREENCAST: 'screen-cast',
  68. FILE: 'file',
  69. MIXED: 'mixed'
  70. };
  71. /**
  72. * @class VideoSourceInfo
  73. * @classDesc Source info about a video track. Values: 'camera', 'screen-cast', 'file', 'mixed'.
  74. * @memberOf Owt.Base
  75. * @readonly
  76. * @enum {string}
  77. */
  78. const VideoSourceInfo = {
  79. CAMERA: 'camera',
  80. SCREENCAST: 'screen-cast',
  81. FILE: 'file',
  82. MIXED: 'mixed'
  83. };
  84. /**
  85. * @class TrackKind
  86. * @classDesc Kind of a track. Values: 'audio' for audio track, 'video' for video track, 'av' for both audio and video tracks.
  87. * @memberOf Owt.Base
  88. * @readonly
  89. * @enum {string}
  90. */
  91. const TrackKind = {
  92. /**
  93. * Audio tracks.
  94. * @type string
  95. */
  96. AUDIO: 'audio',
  97. /**
  98. * Video tracks.
  99. * @type string
  100. */
  101. VIDEO: 'video',
  102. /**
  103. * Both audio and video tracks.
  104. * @type string
  105. */
  106. AUDIO_AND_VIDEO: 'av'
  107. };
  108. /**
  109. * @class Resolution
  110. * @memberOf Owt.Base
  111. * @classDesc The Resolution defines the size of a rectangle.
  112. * @constructor
  113. * @param {number} width
  114. * @param {number} height
  115. */
  116. class Resolution {
  117. // eslint-disable-next-line require-jsdoc
  118. constructor(width, height) {
  119. /**
  120. * @member {number} width
  121. * @instance
  122. * @memberof Owt.Base.Resolution
  123. */
  124. this.width = width;
  125. /**
  126. * @member {number} height
  127. * @instance
  128. * @memberof Owt.Base.Resolution
  129. */
  130. this.height = height;
  131. }
  132. }
  133. /*
  134. * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
  135. *
  136. * Use of this source code is governed by a BSD-style license
  137. * that can be found in the LICENSE file in the root of the source
  138. * tree.
  139. */
  140. let logDisabled_ = true;
  141. let deprecationWarnings_ = true;
  142. /**
  143. * Extract browser version out of the provided user agent string.
  144. *
  145. * @param {!string} uastring userAgent string.
  146. * @param {!string} expr Regular expression used as match criteria.
  147. * @param {!number} pos position in the version string to be returned.
  148. * @return {!number} browser version.
  149. */
  150. function extractVersion(uastring, expr, pos) {
  151. const match = uastring.match(expr);
  152. return match && match.length >= pos && parseInt(match[pos], 10);
  153. }
  154. // Wraps the peerconnection event eventNameToWrap in a function
  155. // which returns the modified event object (or false to prevent
  156. // the event).
  157. function wrapPeerConnectionEvent(window, eventNameToWrap, wrapper) {
  158. if (!window.RTCPeerConnection) {
  159. return;
  160. }
  161. const proto = window.RTCPeerConnection.prototype;
  162. const nativeAddEventListener = proto.addEventListener;
  163. proto.addEventListener = function(nativeEventName, cb) {
  164. if (nativeEventName !== eventNameToWrap) {
  165. return nativeAddEventListener.apply(this, arguments);
  166. }
  167. const wrappedCallback = (e) => {
  168. const modifiedEvent = wrapper(e);
  169. if (modifiedEvent) {
  170. if (cb.handleEvent) {
  171. cb.handleEvent(modifiedEvent);
  172. } else {
  173. cb(modifiedEvent);
  174. }
  175. }
  176. };
  177. this._eventMap = this._eventMap || {};
  178. if (!this._eventMap[eventNameToWrap]) {
  179. this._eventMap[eventNameToWrap] = new Map();
  180. }
  181. this._eventMap[eventNameToWrap].set(cb, wrappedCallback);
  182. return nativeAddEventListener.apply(this, [nativeEventName,
  183. wrappedCallback]);
  184. };
  185. const nativeRemoveEventListener = proto.removeEventListener;
  186. proto.removeEventListener = function(nativeEventName, cb) {
  187. if (nativeEventName !== eventNameToWrap || !this._eventMap
  188. || !this._eventMap[eventNameToWrap]) {
  189. return nativeRemoveEventListener.apply(this, arguments);
  190. }
  191. if (!this._eventMap[eventNameToWrap].has(cb)) {
  192. return nativeRemoveEventListener.apply(this, arguments);
  193. }
  194. const unwrappedCb = this._eventMap[eventNameToWrap].get(cb);
  195. this._eventMap[eventNameToWrap].delete(cb);
  196. if (this._eventMap[eventNameToWrap].size === 0) {
  197. delete this._eventMap[eventNameToWrap];
  198. }
  199. if (Object.keys(this._eventMap).length === 0) {
  200. delete this._eventMap;
  201. }
  202. return nativeRemoveEventListener.apply(this, [nativeEventName,
  203. unwrappedCb]);
  204. };
  205. Object.defineProperty(proto, 'on' + eventNameToWrap, {
  206. get() {
  207. return this['_on' + eventNameToWrap];
  208. },
  209. set(cb) {
  210. if (this['_on' + eventNameToWrap]) {
  211. this.removeEventListener(eventNameToWrap,
  212. this['_on' + eventNameToWrap]);
  213. delete this['_on' + eventNameToWrap];
  214. }
  215. if (cb) {
  216. this.addEventListener(eventNameToWrap,
  217. this['_on' + eventNameToWrap] = cb);
  218. }
  219. },
  220. enumerable: true,
  221. configurable: true
  222. });
  223. }
  224. function disableLog(bool) {
  225. if (typeof bool !== 'boolean') {
  226. return new Error('Argument type: ' + typeof bool +
  227. '. Please use a boolean.');
  228. }
  229. logDisabled_ = bool;
  230. return (bool) ? 'adapter.js logging disabled' :
  231. 'adapter.js logging enabled';
  232. }
  233. /**
  234. * Disable or enable deprecation warnings
  235. * @param {!boolean} bool set to true to disable warnings.
  236. */
  237. function disableWarnings(bool) {
  238. if (typeof bool !== 'boolean') {
  239. return new Error('Argument type: ' + typeof bool +
  240. '. Please use a boolean.');
  241. }
  242. deprecationWarnings_ = !bool;
  243. return 'adapter.js deprecation warnings ' + (bool ? 'disabled' : 'enabled');
  244. }
  245. function log$1() {
  246. if (typeof window === 'object') {
  247. if (logDisabled_) {
  248. return;
  249. }
  250. if (typeof console !== 'undefined' && typeof console.log === 'function') {
  251. console.log.apply(console, arguments);
  252. }
  253. }
  254. }
  255. /**
  256. * Shows a deprecation warning suggesting the modern and spec-compatible API.
  257. */
  258. function deprecated(oldMethod, newMethod) {
  259. if (!deprecationWarnings_) {
  260. return;
  261. }
  262. console.warn(oldMethod + ' is deprecated, please use ' + newMethod +
  263. ' instead.');
  264. }
  265. /**
  266. * Browser detector.
  267. *
  268. * @return {object} result containing browser and version
  269. * properties.
  270. */
  271. function detectBrowser(window) {
  272. // Returned result object.
  273. const result = {browser: null, version: null};
  274. // Fail early if it's not a browser
  275. if (typeof window === 'undefined' || !window.navigator) {
  276. result.browser = 'Not a browser.';
  277. return result;
  278. }
  279. const {navigator} = window;
  280. if (navigator.mozGetUserMedia) { // Firefox.
  281. result.browser = 'firefox';
  282. result.version = extractVersion(navigator.userAgent,
  283. /Firefox\/(\d+)\./, 1);
  284. } else if (navigator.webkitGetUserMedia ||
  285. (window.isSecureContext === false && window.webkitRTCPeerConnection &&
  286. !window.RTCIceGatherer)) {
  287. // Chrome, Chromium, Webview, Opera.
  288. // Version matches Chrome/WebRTC version.
  289. // Chrome 74 removed webkitGetUserMedia on http as well so we need the
  290. // more complicated fallback to webkitRTCPeerConnection.
  291. result.browser = 'chrome';
  292. result.version = extractVersion(navigator.userAgent,
  293. /Chrom(e|ium)\/(\d+)\./, 2);
  294. } else if (navigator.mediaDevices &&
  295. navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)) { // Edge.
  296. result.browser = 'edge';
  297. result.version = extractVersion(navigator.userAgent,
  298. /Edge\/(\d+).(\d+)$/, 2);
  299. } else if (window.RTCPeerConnection &&
  300. navigator.userAgent.match(/AppleWebKit\/(\d+)\./)) { // Safari.
  301. result.browser = 'safari';
  302. result.version = extractVersion(navigator.userAgent,
  303. /AppleWebKit\/(\d+)\./, 1);
  304. result.supportsUnifiedPlan = window.RTCRtpTransceiver &&
  305. 'currentDirection' in window.RTCRtpTransceiver.prototype;
  306. } else { // Default fallthrough: not supported.
  307. result.browser = 'Not a supported browser.';
  308. return result;
  309. }
  310. return result;
  311. }
  312. /**
  313. * Checks if something is an object.
  314. *
  315. * @param {*} val The something you want to check.
  316. * @return true if val is an object, false otherwise.
  317. */
  318. function isObject$1(val) {
  319. return Object.prototype.toString.call(val) === '[object Object]';
  320. }
  321. /**
  322. * Remove all empty objects and undefined values
  323. * from a nested object -- an enhanced and vanilla version
  324. * of Lodash's `compact`.
  325. */
  326. function compactObject(data) {
  327. if (!isObject$1(data)) {
  328. return data;
  329. }
  330. return Object.keys(data).reduce(function(accumulator, key) {
  331. const isObj = isObject$1(data[key]);
  332. const value = isObj ? compactObject(data[key]) : data[key];
  333. const isEmptyObject = isObj && !Object.keys(value).length;
  334. if (value === undefined || isEmptyObject) {
  335. return accumulator;
  336. }
  337. return Object.assign(accumulator, {[key]: value});
  338. }, {});
  339. }
  340. /* iterates the stats graph recursively. */
  341. function walkStats(stats, base, resultSet) {
  342. if (!base || resultSet.has(base.id)) {
  343. return;
  344. }
  345. resultSet.set(base.id, base);
  346. Object.keys(base).forEach(name => {
  347. if (name.endsWith('Id')) {
  348. walkStats(stats, stats.get(base[name]), resultSet);
  349. } else if (name.endsWith('Ids')) {
  350. base[name].forEach(id => {
  351. walkStats(stats, stats.get(id), resultSet);
  352. });
  353. }
  354. });
  355. }
  356. /* filter getStats for a sender/receiver track. */
  357. function filterStats(result, track, outbound) {
  358. const streamStatsType = outbound ? 'outbound-rtp' : 'inbound-rtp';
  359. const filteredResult = new Map();
  360. if (track === null) {
  361. return filteredResult;
  362. }
  363. const trackStats = [];
  364. result.forEach(value => {
  365. if (value.type === 'track' &&
  366. value.trackIdentifier === track.id) {
  367. trackStats.push(value);
  368. }
  369. });
  370. trackStats.forEach(trackStat => {
  371. result.forEach(stats => {
  372. if (stats.type === streamStatsType && stats.trackId === trackStat.id) {
  373. walkStats(result, stats, filteredResult);
  374. }
  375. });
  376. });
  377. return filteredResult;
  378. }
  379. /*
  380. * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
  381. *
  382. * Use of this source code is governed by a BSD-style license
  383. * that can be found in the LICENSE file in the root of the source
  384. * tree.
  385. */
  386. const logging = log$1;
  387. function shimGetUserMedia$3(window, browserDetails) {
  388. const navigator = window && window.navigator;
  389. if (!navigator.mediaDevices) {
  390. return;
  391. }
  392. const constraintsToChrome_ = function(c) {
  393. if (typeof c !== 'object' || c.mandatory || c.optional) {
  394. return c;
  395. }
  396. const cc = {};
  397. Object.keys(c).forEach(key => {
  398. if (key === 'require' || key === 'advanced' || key === 'mediaSource') {
  399. return;
  400. }
  401. const r = (typeof c[key] === 'object') ? c[key] : {ideal: c[key]};
  402. if (r.exact !== undefined && typeof r.exact === 'number') {
  403. r.min = r.max = r.exact;
  404. }
  405. const oldname_ = function(prefix, name) {
  406. if (prefix) {
  407. return prefix + name.charAt(0).toUpperCase() + name.slice(1);
  408. }
  409. return (name === 'deviceId') ? 'sourceId' : name;
  410. };
  411. if (r.ideal !== undefined) {
  412. cc.optional = cc.optional || [];
  413. let oc = {};
  414. if (typeof r.ideal === 'number') {
  415. oc[oldname_('min', key)] = r.ideal;
  416. cc.optional.push(oc);
  417. oc = {};
  418. oc[oldname_('max', key)] = r.ideal;
  419. cc.optional.push(oc);
  420. } else {
  421. oc[oldname_('', key)] = r.ideal;
  422. cc.optional.push(oc);
  423. }
  424. }
  425. if (r.exact !== undefined && typeof r.exact !== 'number') {
  426. cc.mandatory = cc.mandatory || {};
  427. cc.mandatory[oldname_('', key)] = r.exact;
  428. } else {
  429. ['min', 'max'].forEach(mix => {
  430. if (r[mix] !== undefined) {
  431. cc.mandatory = cc.mandatory || {};
  432. cc.mandatory[oldname_(mix, key)] = r[mix];
  433. }
  434. });
  435. }
  436. });
  437. if (c.advanced) {
  438. cc.optional = (cc.optional || []).concat(c.advanced);
  439. }
  440. return cc;
  441. };
  442. const shimConstraints_ = function(constraints, func) {
  443. if (browserDetails.version >= 61) {
  444. return func(constraints);
  445. }
  446. constraints = JSON.parse(JSON.stringify(constraints));
  447. if (constraints && typeof constraints.audio === 'object') {
  448. const remap = function(obj, a, b) {
  449. if (a in obj && !(b in obj)) {
  450. obj[b] = obj[a];
  451. delete obj[a];
  452. }
  453. };
  454. constraints = JSON.parse(JSON.stringify(constraints));
  455. remap(constraints.audio, 'autoGainControl', 'googAutoGainControl');
  456. remap(constraints.audio, 'noiseSuppression', 'googNoiseSuppression');
  457. constraints.audio = constraintsToChrome_(constraints.audio);
  458. }
  459. if (constraints && typeof constraints.video === 'object') {
  460. // Shim facingMode for mobile & surface pro.
  461. let face = constraints.video.facingMode;
  462. face = face && ((typeof face === 'object') ? face : {ideal: face});
  463. const getSupportedFacingModeLies = browserDetails.version < 66;
  464. if ((face && (face.exact === 'user' || face.exact === 'environment' ||
  465. face.ideal === 'user' || face.ideal === 'environment')) &&
  466. !(navigator.mediaDevices.getSupportedConstraints &&
  467. navigator.mediaDevices.getSupportedConstraints().facingMode &&
  468. !getSupportedFacingModeLies)) {
  469. delete constraints.video.facingMode;
  470. let matches;
  471. if (face.exact === 'environment' || face.ideal === 'environment') {
  472. matches = ['back', 'rear'];
  473. } else if (face.exact === 'user' || face.ideal === 'user') {
  474. matches = ['front'];
  475. }
  476. if (matches) {
  477. // Look for matches in label, or use last cam for back (typical).
  478. return navigator.mediaDevices.enumerateDevices()
  479. .then(devices => {
  480. devices = devices.filter(d => d.kind === 'videoinput');
  481. let dev = devices.find(d => matches.some(match =>
  482. d.label.toLowerCase().includes(match)));
  483. if (!dev && devices.length && matches.includes('back')) {
  484. dev = devices[devices.length - 1]; // more likely the back cam
  485. }
  486. if (dev) {
  487. constraints.video.deviceId = face.exact ? {exact: dev.deviceId} :
  488. {ideal: dev.deviceId};
  489. }
  490. constraints.video = constraintsToChrome_(constraints.video);
  491. logging('chrome: ' + JSON.stringify(constraints));
  492. return func(constraints);
  493. });
  494. }
  495. }
  496. constraints.video = constraintsToChrome_(constraints.video);
  497. }
  498. logging('chrome: ' + JSON.stringify(constraints));
  499. return func(constraints);
  500. };
  501. const shimError_ = function(e) {
  502. if (browserDetails.version >= 64) {
  503. return e;
  504. }
  505. return {
  506. name: {
  507. PermissionDeniedError: 'NotAllowedError',
  508. PermissionDismissedError: 'NotAllowedError',
  509. InvalidStateError: 'NotAllowedError',
  510. DevicesNotFoundError: 'NotFoundError',
  511. ConstraintNotSatisfiedError: 'OverconstrainedError',
  512. TrackStartError: 'NotReadableError',
  513. MediaDeviceFailedDueToShutdown: 'NotAllowedError',
  514. MediaDeviceKillSwitchOn: 'NotAllowedError',
  515. TabCaptureError: 'AbortError',
  516. ScreenCaptureError: 'AbortError',
  517. DeviceCaptureError: 'AbortError'
  518. }[e.name] || e.name,
  519. message: e.message,
  520. constraint: e.constraint || e.constraintName,
  521. toString() {
  522. return this.name + (this.message && ': ') + this.message;
  523. }
  524. };
  525. };
  526. const getUserMedia_ = function(constraints, onSuccess, onError) {
  527. shimConstraints_(constraints, c => {
  528. navigator.webkitGetUserMedia(c, onSuccess, e => {
  529. if (onError) {
  530. onError(shimError_(e));
  531. }
  532. });
  533. });
  534. };
  535. navigator.getUserMedia = getUserMedia_.bind(navigator);
  536. // Even though Chrome 45 has navigator.mediaDevices and a getUserMedia
  537. // function which returns a Promise, it does not accept spec-style
  538. // constraints.
  539. if (navigator.mediaDevices.getUserMedia) {
  540. const origGetUserMedia = navigator.mediaDevices.getUserMedia.
  541. bind(navigator.mediaDevices);
  542. navigator.mediaDevices.getUserMedia = function(cs) {
  543. return shimConstraints_(cs, c => origGetUserMedia(c).then(stream => {
  544. if (c.audio && !stream.getAudioTracks().length ||
  545. c.video && !stream.getVideoTracks().length) {
  546. stream.getTracks().forEach(track => {
  547. track.stop();
  548. });
  549. throw new DOMException('', 'NotFoundError');
  550. }
  551. return stream;
  552. }, e => Promise.reject(shimError_(e))));
  553. };
  554. }
  555. }
  556. /*
  557. * Copyright (c) 2018 The adapter.js project authors. All Rights Reserved.
  558. *
  559. * Use of this source code is governed by a BSD-style license
  560. * that can be found in the LICENSE file in the root of the source
  561. * tree.
  562. */
  563. function shimGetDisplayMedia$2(window, getSourceId) {
  564. if (window.navigator.mediaDevices &&
  565. 'getDisplayMedia' in window.navigator.mediaDevices) {
  566. return;
  567. }
  568. if (!(window.navigator.mediaDevices)) {
  569. return;
  570. }
  571. // getSourceId is a function that returns a promise resolving with
  572. // the sourceId of the screen/window/tab to be shared.
  573. if (typeof getSourceId !== 'function') {
  574. console.error('shimGetDisplayMedia: getSourceId argument is not ' +
  575. 'a function');
  576. return;
  577. }
  578. window.navigator.mediaDevices.getDisplayMedia =
  579. function getDisplayMedia(constraints) {
  580. return getSourceId(constraints)
  581. .then(sourceId => {
  582. const widthSpecified = constraints.video && constraints.video.width;
  583. const heightSpecified = constraints.video &&
  584. constraints.video.height;
  585. const frameRateSpecified = constraints.video &&
  586. constraints.video.frameRate;
  587. constraints.video = {
  588. mandatory: {
  589. chromeMediaSource: 'desktop',
  590. chromeMediaSourceId: sourceId,
  591. maxFrameRate: frameRateSpecified || 3
  592. }
  593. };
  594. if (widthSpecified) {
  595. constraints.video.mandatory.maxWidth = widthSpecified;
  596. }
  597. if (heightSpecified) {
  598. constraints.video.mandatory.maxHeight = heightSpecified;
  599. }
  600. return window.navigator.mediaDevices.getUserMedia(constraints);
  601. });
  602. };
  603. }
  604. /*
  605. * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
  606. *
  607. * Use of this source code is governed by a BSD-style license
  608. * that can be found in the LICENSE file in the root of the source
  609. * tree.
  610. */
  611. function shimMediaStream(window) {
  612. window.MediaStream = window.MediaStream || window.webkitMediaStream;
  613. }
  614. function shimOnTrack$1(window) {
  615. if (typeof window === 'object' && window.RTCPeerConnection && !('ontrack' in
  616. window.RTCPeerConnection.prototype)) {
  617. Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', {
  618. get() {
  619. return this._ontrack;
  620. },
  621. set(f) {
  622. if (this._ontrack) {
  623. this.removeEventListener('track', this._ontrack);
  624. }
  625. this.addEventListener('track', this._ontrack = f);
  626. },
  627. enumerable: true,
  628. configurable: true
  629. });
  630. const origSetRemoteDescription =
  631. window.RTCPeerConnection.prototype.setRemoteDescription;
  632. window.RTCPeerConnection.prototype.setRemoteDescription =
  633. function setRemoteDescription() {
  634. if (!this._ontrackpoly) {
  635. this._ontrackpoly = (e) => {
  636. // onaddstream does not fire when a track is added to an existing
  637. // stream. But stream.onaddtrack is implemented so we use that.
  638. e.stream.addEventListener('addtrack', te => {
  639. let receiver;
  640. if (window.RTCPeerConnection.prototype.getReceivers) {
  641. receiver = this.getReceivers()
  642. .find(r => r.track && r.track.id === te.track.id);
  643. } else {
  644. receiver = {track: te.track};
  645. }
  646. const event = new Event('track');
  647. event.track = te.track;
  648. event.receiver = receiver;
  649. event.transceiver = {receiver};
  650. event.streams = [e.stream];
  651. this.dispatchEvent(event);
  652. });
  653. e.stream.getTracks().forEach(track => {
  654. let receiver;
  655. if (window.RTCPeerConnection.prototype.getReceivers) {
  656. receiver = this.getReceivers()
  657. .find(r => r.track && r.track.id === track.id);
  658. } else {
  659. receiver = {track};
  660. }
  661. const event = new Event('track');
  662. event.track = track;
  663. event.receiver = receiver;
  664. event.transceiver = {receiver};
  665. event.streams = [e.stream];
  666. this.dispatchEvent(event);
  667. });
  668. };
  669. this.addEventListener('addstream', this._ontrackpoly);
  670. }
  671. return origSetRemoteDescription.apply(this, arguments);
  672. };
  673. } else {
  674. // even if RTCRtpTransceiver is in window, it is only used and
  675. // emitted in unified-plan. Unfortunately this means we need
  676. // to unconditionally wrap the event.
  677. wrapPeerConnectionEvent(window, 'track', e => {
  678. if (!e.transceiver) {
  679. Object.defineProperty(e, 'transceiver',
  680. {value: {receiver: e.receiver}});
  681. }
  682. return e;
  683. });
  684. }
  685. }
  686. function shimGetSendersWithDtmf(window) {
  687. // Overrides addTrack/removeTrack, depends on shimAddTrackRemoveTrack.
  688. if (typeof window === 'object' && window.RTCPeerConnection &&
  689. !('getSenders' in window.RTCPeerConnection.prototype) &&
  690. 'createDTMFSender' in window.RTCPeerConnection.prototype) {
  691. const shimSenderWithDtmf = function(pc, track) {
  692. return {
  693. track,
  694. get dtmf() {
  695. if (this._dtmf === undefined) {
  696. if (track.kind === 'audio') {
  697. this._dtmf = pc.createDTMFSender(track);
  698. } else {
  699. this._dtmf = null;
  700. }
  701. }
  702. return this._dtmf;
  703. },
  704. _pc: pc
  705. };
  706. };
  707. // augment addTrack when getSenders is not available.
  708. if (!window.RTCPeerConnection.prototype.getSenders) {
  709. window.RTCPeerConnection.prototype.getSenders = function getSenders() {
  710. this._senders = this._senders || [];
  711. return this._senders.slice(); // return a copy of the internal state.
  712. };
  713. const origAddTrack = window.RTCPeerConnection.prototype.addTrack;
  714. window.RTCPeerConnection.prototype.addTrack =
  715. function addTrack(track, stream) {
  716. let sender = origAddTrack.apply(this, arguments);
  717. if (!sender) {
  718. sender = shimSenderWithDtmf(this, track);
  719. this._senders.push(sender);
  720. }
  721. return sender;
  722. };
  723. const origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack;
  724. window.RTCPeerConnection.prototype.removeTrack =
  725. function removeTrack(sender) {
  726. origRemoveTrack.apply(this, arguments);
  727. const idx = this._senders.indexOf(sender);
  728. if (idx !== -1) {
  729. this._senders.splice(idx, 1);
  730. }
  731. };
  732. }
  733. const origAddStream = window.RTCPeerConnection.prototype.addStream;
  734. window.RTCPeerConnection.prototype.addStream = function addStream(stream) {
  735. this._senders = this._senders || [];
  736. origAddStream.apply(this, [stream]);
  737. stream.getTracks().forEach(track => {
  738. this._senders.push(shimSenderWithDtmf(this, track));
  739. });
  740. };
  741. const origRemoveStream = window.RTCPeerConnection.prototype.removeStream;
  742. window.RTCPeerConnection.prototype.removeStream =
  743. function removeStream(stream) {
  744. this._senders = this._senders || [];
  745. origRemoveStream.apply(this, [stream]);
  746. stream.getTracks().forEach(track => {
  747. const sender = this._senders.find(s => s.track === track);
  748. if (sender) { // remove sender
  749. this._senders.splice(this._senders.indexOf(sender), 1);
  750. }
  751. });
  752. };
  753. } else if (typeof window === 'object' && window.RTCPeerConnection &&
  754. 'getSenders' in window.RTCPeerConnection.prototype &&
  755. 'createDTMFSender' in window.RTCPeerConnection.prototype &&
  756. window.RTCRtpSender &&
  757. !('dtmf' in window.RTCRtpSender.prototype)) {
  758. const origGetSenders = window.RTCPeerConnection.prototype.getSenders;
  759. window.RTCPeerConnection.prototype.getSenders = function getSenders() {
  760. const senders = origGetSenders.apply(this, []);
  761. senders.forEach(sender => sender._pc = this);
  762. return senders;
  763. };
  764. Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', {
  765. get() {
  766. if (this._dtmf === undefined) {
  767. if (this.track.kind === 'audio') {
  768. this._dtmf = this._pc.createDTMFSender(this.track);
  769. } else {
  770. this._dtmf = null;
  771. }
  772. }
  773. return this._dtmf;
  774. }
  775. });
  776. }
  777. }
  778. function shimGetStats(window) {
  779. if (!window.RTCPeerConnection) {
  780. return;
  781. }
  782. const origGetStats = window.RTCPeerConnection.prototype.getStats;
  783. window.RTCPeerConnection.prototype.getStats = function getStats() {
  784. const [selector, onSucc, onErr] = arguments;
  785. // If selector is a function then we are in the old style stats so just
  786. // pass back the original getStats format to avoid breaking old users.
  787. if (arguments.length > 0 && typeof selector === 'function') {
  788. return origGetStats.apply(this, arguments);
  789. }
  790. // When spec-style getStats is supported, return those when called with
  791. // either no arguments or the selector argument is null.
  792. if (origGetStats.length === 0 && (arguments.length === 0 ||
  793. typeof selector !== 'function')) {
  794. return origGetStats.apply(this, []);
  795. }
  796. const fixChromeStats_ = function(response) {
  797. const standardReport = {};
  798. const reports = response.result();
  799. reports.forEach(report => {
  800. const standardStats = {
  801. id: report.id,
  802. timestamp: report.timestamp,
  803. type: {
  804. localcandidate: 'local-candidate',
  805. remotecandidate: 'remote-candidate'
  806. }[report.type] || report.type
  807. };
  808. report.names().forEach(name => {
  809. standardStats[name] = report.stat(name);
  810. });
  811. standardReport[standardStats.id] = standardStats;
  812. });
  813. return standardReport;
  814. };
  815. // shim getStats with maplike support
  816. const makeMapStats = function(stats) {
  817. return new Map(Object.keys(stats).map(key => [key, stats[key]]));
  818. };
  819. if (arguments.length >= 2) {
  820. const successCallbackWrapper_ = function(response) {
  821. onSucc(makeMapStats(fixChromeStats_(response)));
  822. };
  823. return origGetStats.apply(this, [successCallbackWrapper_,
  824. selector]);
  825. }
  826. // promise-support
  827. return new Promise((resolve, reject) => {
  828. origGetStats.apply(this, [
  829. function(response) {
  830. resolve(makeMapStats(fixChromeStats_(response)));
  831. }, reject]);
  832. }).then(onSucc, onErr);
  833. };
  834. }
  835. function shimSenderReceiverGetStats(window) {
  836. if (!(typeof window === 'object' && window.RTCPeerConnection &&
  837. window.RTCRtpSender && window.RTCRtpReceiver)) {
  838. return;
  839. }
  840. // shim sender stats.
  841. if (!('getStats' in window.RTCRtpSender.prototype)) {
  842. const origGetSenders = window.RTCPeerConnection.prototype.getSenders;
  843. if (origGetSenders) {
  844. window.RTCPeerConnection.prototype.getSenders = function getSenders() {
  845. const senders = origGetSenders.apply(this, []);
  846. senders.forEach(sender => sender._pc = this);
  847. return senders;
  848. };
  849. }
  850. const origAddTrack = window.RTCPeerConnection.prototype.addTrack;
  851. if (origAddTrack) {
  852. window.RTCPeerConnection.prototype.addTrack = function addTrack() {
  853. const sender = origAddTrack.apply(this, arguments);
  854. sender._pc = this;
  855. return sender;
  856. };
  857. }
  858. window.RTCRtpSender.prototype.getStats = function getStats() {
  859. const sender = this;
  860. return this._pc.getStats().then(result =>
  861. /* Note: this will include stats of all senders that
  862. * send a track with the same id as sender.track as
  863. * it is not possible to identify the RTCRtpSender.
  864. */
  865. filterStats(result, sender.track, true));
  866. };
  867. }
  868. // shim receiver stats.
  869. if (!('getStats' in window.RTCRtpReceiver.prototype)) {
  870. const origGetReceivers = window.RTCPeerConnection.prototype.getReceivers;
  871. if (origGetReceivers) {
  872. window.RTCPeerConnection.prototype.getReceivers =
  873. function getReceivers() {
  874. const receivers = origGetReceivers.apply(this, []);
  875. receivers.forEach(receiver => receiver._pc = this);
  876. return receivers;
  877. };
  878. }
  879. wrapPeerConnectionEvent(window, 'track', e => {
  880. e.receiver._pc = e.srcElement;
  881. return e;
  882. });
  883. window.RTCRtpReceiver.prototype.getStats = function getStats() {
  884. const receiver = this;
  885. return this._pc.getStats().then(result =>
  886. filterStats(result, receiver.track, false));
  887. };
  888. }
  889. if (!('getStats' in window.RTCRtpSender.prototype &&
  890. 'getStats' in window.RTCRtpReceiver.prototype)) {
  891. return;
  892. }
  893. // shim RTCPeerConnection.getStats(track).
  894. const origGetStats = window.RTCPeerConnection.prototype.getStats;
  895. window.RTCPeerConnection.prototype.getStats = function getStats() {
  896. if (arguments.length > 0 &&
  897. arguments[0] instanceof window.MediaStreamTrack) {
  898. const track = arguments[0];
  899. let sender;
  900. let receiver;
  901. let err;
  902. this.getSenders().forEach(s => {
  903. if (s.track === track) {
  904. if (sender) {
  905. err = true;
  906. } else {
  907. sender = s;
  908. }
  909. }
  910. });
  911. this.getReceivers().forEach(r => {
  912. if (r.track === track) {
  913. if (receiver) {
  914. err = true;
  915. } else {
  916. receiver = r;
  917. }
  918. }
  919. return r.track === track;
  920. });
  921. if (err || (sender && receiver)) {
  922. return Promise.reject(new DOMException(
  923. 'There are more than one sender or receiver for the track.',
  924. 'InvalidAccessError'));
  925. } else if (sender) {
  926. return sender.getStats();
  927. } else if (receiver) {
  928. return receiver.getStats();
  929. }
  930. return Promise.reject(new DOMException(
  931. 'There is no sender or receiver for the track.',
  932. 'InvalidAccessError'));
  933. }
  934. return origGetStats.apply(this, arguments);
  935. };
  936. }
  937. function shimAddTrackRemoveTrackWithNative(window) {
  938. // shim addTrack/removeTrack with native variants in order to make
  939. // the interactions with legacy getLocalStreams behave as in other browsers.
  940. // Keeps a mapping stream.id => [stream, rtpsenders...]
  941. window.RTCPeerConnection.prototype.getLocalStreams =
  942. function getLocalStreams() {
  943. this._shimmedLocalStreams = this._shimmedLocalStreams || {};
  944. return Object.keys(this._shimmedLocalStreams)
  945. .map(streamId => this._shimmedLocalStreams[streamId][0]);
  946. };
  947. const origAddTrack = window.RTCPeerConnection.prototype.addTrack;
  948. window.RTCPeerConnection.prototype.addTrack =
  949. function addTrack(track, stream) {
  950. if (!stream) {
  951. return origAddTrack.apply(this, arguments);
  952. }
  953. this._shimmedLocalStreams = this._shimmedLocalStreams || {};
  954. const sender = origAddTrack.apply(this, arguments);
  955. if (!this._shimmedLocalStreams[stream.id]) {
  956. this._shimmedLocalStreams[stream.id] = [stream, sender];
  957. } else if (this._shimmedLocalStreams[stream.id].indexOf(sender) === -1) {
  958. this._shimmedLocalStreams[stream.id].push(sender);
  959. }
  960. return sender;
  961. };
  962. const origAddStream = window.RTCPeerConnection.prototype.addStream;
  963. window.RTCPeerConnection.prototype.addStream = function addStream(stream) {
  964. this._shimmedLocalStreams = this._shimmedLocalStreams || {};
  965. stream.getTracks().forEach(track => {
  966. const alreadyExists = this.getSenders().find(s => s.track === track);
  967. if (alreadyExists) {
  968. throw new DOMException('Track already exists.',
  969. 'InvalidAccessError');
  970. }
  971. });
  972. const existingSenders = this.getSenders();
  973. origAddStream.apply(this, arguments);
  974. const newSenders = this.getSenders()
  975. .filter(newSender => existingSenders.indexOf(newSender) === -1);
  976. this._shimmedLocalStreams[stream.id] = [stream].concat(newSenders);
  977. };
  978. const origRemoveStream = window.RTCPeerConnection.prototype.removeStream;
  979. window.RTCPeerConnection.prototype.removeStream =
  980. function removeStream(stream) {
  981. this._shimmedLocalStreams = this._shimmedLocalStreams || {};
  982. delete this._shimmedLocalStreams[stream.id];
  983. return origRemoveStream.apply(this, arguments);
  984. };
  985. const origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack;
  986. window.RTCPeerConnection.prototype.removeTrack =
  987. function removeTrack(sender) {
  988. this._shimmedLocalStreams = this._shimmedLocalStreams || {};
  989. if (sender) {
  990. Object.keys(this._shimmedLocalStreams).forEach(streamId => {
  991. const idx = this._shimmedLocalStreams[streamId].indexOf(sender);
  992. if (idx !== -1) {
  993. this._shimmedLocalStreams[streamId].splice(idx, 1);
  994. }
  995. if (this._shimmedLocalStreams[streamId].length === 1) {
  996. delete this._shimmedLocalStreams[streamId];
  997. }
  998. });
  999. }
  1000. return origRemoveTrack.apply(this, arguments);
  1001. };
  1002. }
  1003. function shimAddTrackRemoveTrack(window, browserDetails) {
  1004. if (!window.RTCPeerConnection) {
  1005. return;
  1006. }
  1007. // shim addTrack and removeTrack.
  1008. if (window.RTCPeerConnection.prototype.addTrack &&
  1009. browserDetails.version >= 65) {
  1010. return shimAddTrackRemoveTrackWithNative(window);
  1011. }
  1012. // also shim pc.getLocalStreams when addTrack is shimmed
  1013. // to return the original streams.
  1014. const origGetLocalStreams = window.RTCPeerConnection.prototype
  1015. .getLocalStreams;
  1016. window.RTCPeerConnection.prototype.getLocalStreams =
  1017. function getLocalStreams() {
  1018. const nativeStreams = origGetLocalStreams.apply(this);
  1019. this._reverseStreams = this._reverseStreams || {};
  1020. return nativeStreams.map(stream => this._reverseStreams[stream.id]);
  1021. };
  1022. const origAddStream = window.RTCPeerConnection.prototype.addStream;
  1023. window.RTCPeerConnection.prototype.addStream = function addStream(stream) {
  1024. this._streams = this._streams || {};
  1025. this._reverseStreams = this._reverseStreams || {};
  1026. stream.getTracks().forEach(track => {
  1027. const alreadyExists = this.getSenders().find(s => s.track === track);
  1028. if (alreadyExists) {
  1029. throw new DOMException('Track already exists.',
  1030. 'InvalidAccessError');
  1031. }
  1032. });
  1033. // Add identity mapping for consistency with addTrack.
  1034. // Unless this is being used with a stream from addTrack.
  1035. if (!this._reverseStreams[stream.id]) {
  1036. const newStream = new window.MediaStream(stream.getTracks());
  1037. this._streams[stream.id] = newStream;
  1038. this._reverseStreams[newStream.id] = stream;
  1039. stream = newStream;
  1040. }
  1041. origAddStream.apply(this, [stream]);
  1042. };
  1043. const origRemoveStream = window.RTCPeerConnection.prototype.removeStream;
  1044. window.RTCPeerConnection.prototype.removeStream =
  1045. function removeStream(stream) {
  1046. this._streams = this._streams || {};
  1047. this._reverseStreams = this._reverseStreams || {};
  1048. origRemoveStream.apply(this, [(this._streams[stream.id] || stream)]);
  1049. delete this._reverseStreams[(this._streams[stream.id] ?
  1050. this._streams[stream.id].id : stream.id)];
  1051. delete this._streams[stream.id];
  1052. };
  1053. window.RTCPeerConnection.prototype.addTrack =
  1054. function addTrack(track, stream) {
  1055. if (this.signalingState === 'closed') {
  1056. throw new DOMException(
  1057. 'The RTCPeerConnection\'s signalingState is \'closed\'.',
  1058. 'InvalidStateError');
  1059. }
  1060. const streams = [].slice.call(arguments, 1);
  1061. if (streams.length !== 1 ||
  1062. !streams[0].getTracks().find(t => t === track)) {
  1063. // this is not fully correct but all we can manage without
  1064. // [[associated MediaStreams]] internal slot.
  1065. throw new DOMException(
  1066. 'The adapter.js addTrack polyfill only supports a single ' +
  1067. ' stream which is associated with the specified track.',
  1068. 'NotSupportedError');
  1069. }
  1070. const alreadyExists = this.getSenders().find(s => s.track === track);
  1071. if (alreadyExists) {
  1072. throw new DOMException('Track already exists.',
  1073. 'InvalidAccessError');
  1074. }
  1075. this._streams = this._streams || {};
  1076. this._reverseStreams = this._reverseStreams || {};
  1077. const oldStream = this._streams[stream.id];
  1078. if (oldStream) {
  1079. // this is using odd Chrome behaviour, use with caution:
  1080. // https://bugs.chromium.org/p/webrtc/issues/detail?id=7815
  1081. // Note: we rely on the high-level addTrack/dtmf shim to
  1082. // create the sender with a dtmf sender.
  1083. oldStream.addTrack(track);
  1084. // Trigger ONN async.
  1085. Promise.resolve().then(() => {
  1086. this.dispatchEvent(new Event('negotiationneeded'));
  1087. });
  1088. } else {
  1089. const newStream = new window.MediaStream([track]);
  1090. this._streams[stream.id] = newStream;
  1091. this._reverseStreams[newStream.id] = stream;
  1092. this.addStream(newStream);
  1093. }
  1094. return this.getSenders().find(s => s.track === track);
  1095. };
  1096. // replace the internal stream id with the external one and
  1097. // vice versa.
  1098. function replaceInternalStreamId(pc, description) {
  1099. let sdp = description.sdp;
  1100. Object.keys(pc._reverseStreams || []).forEach(internalId => {
  1101. const externalStream = pc._reverseStreams[internalId];
  1102. const internalStream = pc._streams[externalStream.id];
  1103. sdp = sdp.replace(new RegExp(internalStream.id, 'g'),
  1104. externalStream.id);
  1105. });
  1106. return new RTCSessionDescription({
  1107. type: description.type,
  1108. sdp
  1109. });
  1110. }
  1111. function replaceExternalStreamId(pc, description) {
  1112. let sdp = description.sdp;
  1113. Object.keys(pc._reverseStreams || []).forEach(internalId => {
  1114. const externalStream = pc._reverseStreams[internalId];
  1115. const internalStream = pc._streams[externalStream.id];
  1116. sdp = sdp.replace(new RegExp(externalStream.id, 'g'),
  1117. internalStream.id);
  1118. });
  1119. return new RTCSessionDescription({
  1120. type: description.type,
  1121. sdp
  1122. });
  1123. }
  1124. ['createOffer', 'createAnswer'].forEach(function(method) {
  1125. const nativeMethod = window.RTCPeerConnection.prototype[method];
  1126. const methodObj = {[method]() {
  1127. const args = arguments;
  1128. const isLegacyCall = arguments.length &&
  1129. typeof arguments[0] === 'function';
  1130. if (isLegacyCall) {
  1131. return nativeMethod.apply(this, [
  1132. (description) => {
  1133. const desc = replaceInternalStreamId(this, description);
  1134. args[0].apply(null, [desc]);
  1135. },
  1136. (err) => {
  1137. if (args[1]) {
  1138. args[1].apply(null, err);
  1139. }
  1140. }, arguments[2]
  1141. ]);
  1142. }
  1143. return nativeMethod.apply(this, arguments)
  1144. .then(description => replaceInternalStreamId(this, description));
  1145. }};
  1146. window.RTCPeerConnection.prototype[method] = methodObj[method];
  1147. });
  1148. const origSetLocalDescription =
  1149. window.RTCPeerConnection.prototype.setLocalDescription;
  1150. window.RTCPeerConnection.prototype.setLocalDescription =
  1151. function setLocalDescription() {
  1152. if (!arguments.length || !arguments[0].type) {
  1153. return origSetLocalDescription.apply(this, arguments);
  1154. }
  1155. arguments[0] = replaceExternalStreamId(this, arguments[0]);
  1156. return origSetLocalDescription.apply(this, arguments);
  1157. };
  1158. // TODO: mangle getStats: https://w3c.github.io/webrtc-stats/#dom-rtcmediastreamstats-streamidentifier
  1159. const origLocalDescription = Object.getOwnPropertyDescriptor(
  1160. window.RTCPeerConnection.prototype, 'localDescription');
  1161. Object.defineProperty(window.RTCPeerConnection.prototype,
  1162. 'localDescription', {
  1163. get() {
  1164. const description = origLocalDescription.get.apply(this);
  1165. if (description.type === '') {
  1166. return description;
  1167. }
  1168. return replaceInternalStreamId(this, description);
  1169. }
  1170. });
  1171. window.RTCPeerConnection.prototype.removeTrack =
  1172. function removeTrack(sender) {
  1173. if (this.signalingState === 'closed') {
  1174. throw new DOMException(
  1175. 'The RTCPeerConnection\'s signalingState is \'closed\'.',
  1176. 'InvalidStateError');
  1177. }
  1178. // We can not yet check for sender instanceof RTCRtpSender
  1179. // since we shim RTPSender. So we check if sender._pc is set.
  1180. if (!sender._pc) {
  1181. throw new DOMException('Argument 1 of RTCPeerConnection.removeTrack ' +
  1182. 'does not implement interface RTCRtpSender.', 'TypeError');
  1183. }
  1184. const isLocal = sender._pc === this;
  1185. if (!isLocal) {
  1186. throw new DOMException('Sender was not created by this connection.',
  1187. 'InvalidAccessError');
  1188. }
  1189. // Search for the native stream the senders track belongs to.
  1190. this._streams = this._streams || {};
  1191. let stream;
  1192. Object.keys(this._streams).forEach(streamid => {
  1193. const hasTrack = this._streams[streamid].getTracks()
  1194. .find(track => sender.track === track);
  1195. if (hasTrack) {
  1196. stream = this._streams[streamid];
  1197. }
  1198. });
  1199. if (stream) {
  1200. if (stream.getTracks().length === 1) {
  1201. // if this is the last track of the stream, remove the stream. This
  1202. // takes care of any shimmed _senders.
  1203. this.removeStream(this._reverseStreams[stream.id]);
  1204. } else {
  1205. // relying on the same odd chrome behaviour as above.
  1206. stream.removeTrack(sender.track);
  1207. }
  1208. this.dispatchEvent(new Event('negotiationneeded'));
  1209. }
  1210. };
  1211. }
  1212. function shimPeerConnection$2(window, browserDetails) {
  1213. if (!window.RTCPeerConnection && window.webkitRTCPeerConnection) {
  1214. // very basic support for old versions.
  1215. window.RTCPeerConnection = window.webkitRTCPeerConnection;
  1216. }
  1217. if (!window.RTCPeerConnection) {
  1218. return;
  1219. }
  1220. // shim implicit creation of RTCSessionDescription/RTCIceCandidate
  1221. if (browserDetails.version < 53) {
  1222. ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate']
  1223. .forEach(function(method) {
  1224. const nativeMethod = window.RTCPeerConnection.prototype[method];
  1225. const methodObj = {[method]() {
  1226. arguments[0] = new ((method === 'addIceCandidate') ?
  1227. window.RTCIceCandidate :
  1228. window.RTCSessionDescription)(arguments[0]);
  1229. return nativeMethod.apply(this, arguments);
  1230. }};
  1231. window.RTCPeerConnection.prototype[method] = methodObj[method];
  1232. });
  1233. }
  1234. }
  1235. // Attempt to fix ONN in plan-b mode.
  1236. function fixNegotiationNeeded(window, browserDetails) {
  1237. wrapPeerConnectionEvent(window, 'negotiationneeded', e => {
  1238. const pc = e.target;
  1239. if (browserDetails.version < 72 || (pc.getConfiguration &&
  1240. pc.getConfiguration().sdpSemantics === 'plan-b')) {
  1241. if (pc.signalingState !== 'stable') {
  1242. return;
  1243. }
  1244. }
  1245. return e;
  1246. });
  1247. }
  1248. var chromeShim = /*#__PURE__*/Object.freeze({
  1249. __proto__: null,
  1250. shimMediaStream: shimMediaStream,
  1251. shimOnTrack: shimOnTrack$1,
  1252. shimGetSendersWithDtmf: shimGetSendersWithDtmf,
  1253. shimGetStats: shimGetStats,
  1254. shimSenderReceiverGetStats: shimSenderReceiverGetStats,
  1255. shimAddTrackRemoveTrackWithNative: shimAddTrackRemoveTrackWithNative,
  1256. shimAddTrackRemoveTrack: shimAddTrackRemoveTrack,
  1257. shimPeerConnection: shimPeerConnection$2,
  1258. fixNegotiationNeeded: fixNegotiationNeeded,
  1259. shimGetUserMedia: shimGetUserMedia$3,
  1260. shimGetDisplayMedia: shimGetDisplayMedia$2
  1261. });
  1262. /*
  1263. * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
  1264. *
  1265. * Use of this source code is governed by a BSD-style license
  1266. * that can be found in the LICENSE file in the root of the source
  1267. * tree.
  1268. */
  1269. // Edge does not like
  1270. // 1) stun: filtered after 14393 unless ?transport=udp is present
  1271. // 2) turn: that does not have all of turn:host:port?transport=udp
  1272. // 3) turn: with ipv6 addresses
  1273. // 4) turn: occurring muliple times
  1274. function filterIceServers$1(iceServers, edgeVersion) {
  1275. let hasTurn = false;
  1276. iceServers = JSON.parse(JSON.stringify(iceServers));
  1277. return iceServers.filter(server => {
  1278. if (server && (server.urls || server.url)) {
  1279. let urls = server.urls || server.url;
  1280. if (server.url && !server.urls) {
  1281. deprecated('RTCIceServer.url', 'RTCIceServer.urls');
  1282. }
  1283. const isString = typeof urls === 'string';
  1284. if (isString) {
  1285. urls = [urls];
  1286. }
  1287. urls = urls.filter(url => {
  1288. // filter STUN unconditionally.
  1289. if (url.indexOf('stun:') === 0) {
  1290. return false;
  1291. }
  1292. const validTurn = url.startsWith('turn') &&
  1293. !url.startsWith('turn:[') &&
  1294. url.includes('transport=udp');
  1295. if (validTurn && !hasTurn) {
  1296. hasTurn = true;
  1297. return true;
  1298. }
  1299. return validTurn && !hasTurn;
  1300. });
  1301. delete server.url;
  1302. server.urls = isString ? urls[0] : urls;
  1303. return !!urls.length;
  1304. }
  1305. });
  1306. }
  1307. function createCommonjsModule(fn) {
  1308. var module = { exports: {} };
  1309. return fn(module, module.exports), module.exports;
  1310. }
  1311. /* eslint-env node */
  1312. var sdp = createCommonjsModule(function (module) {
  1313. // SDP helpers.
  1314. var SDPUtils = {};
  1315. // Generate an alphanumeric identifier for cname or mids.
  1316. // TODO: use UUIDs instead? https://gist.github.com/jed/982883
  1317. SDPUtils.generateIdentifier = function() {
  1318. return Math.random().toString(36).substr(2, 10);
  1319. };
  1320. // The RTCP CNAME used by all peerconnections from the same JS.
  1321. SDPUtils.localCName = SDPUtils.generateIdentifier();
  1322. // Splits SDP into lines, dealing with both CRLF and LF.
  1323. SDPUtils.splitLines = function(blob) {
  1324. return blob.trim().split('\n').map(function(line) {
  1325. return line.trim();
  1326. });
  1327. };
  1328. // Splits SDP into sessionpart and mediasections. Ensures CRLF.
  1329. SDPUtils.splitSections = function(blob) {
  1330. var parts = blob.split('\nm=');
  1331. return parts.map(function(part, index) {
  1332. return (index > 0 ? 'm=' + part : part).trim() + '\r\n';
  1333. });
  1334. };
  1335. // returns the session description.
  1336. SDPUtils.getDescription = function(blob) {
  1337. var sections = SDPUtils.splitSections(blob);
  1338. return sections && sections[0];
  1339. };
  1340. // returns the individual media sections.
  1341. SDPUtils.getMediaSections = function(blob) {
  1342. var sections = SDPUtils.splitSections(blob);
  1343. sections.shift();
  1344. return sections;
  1345. };
  1346. // Returns lines that start with a certain prefix.
  1347. SDPUtils.matchPrefix = function(blob, prefix) {
  1348. return SDPUtils.splitLines(blob).filter(function(line) {
  1349. return line.indexOf(prefix) === 0;
  1350. });
  1351. };
  1352. // Parses an ICE candidate line. Sample input:
  1353. // candidate:702786350 2 udp 41819902 8.8.8.8 60769 typ relay raddr 8.8.8.8
  1354. // rport 55996"
  1355. SDPUtils.parseCandidate = function(line) {
  1356. var parts;
  1357. // Parse both variants.
  1358. if (line.indexOf('a=candidate:') === 0) {
  1359. parts = line.substring(12).split(' ');
  1360. } else {
  1361. parts = line.substring(10).split(' ');
  1362. }
  1363. var candidate = {
  1364. foundation: parts[0],
  1365. component: parseInt(parts[1], 10),
  1366. protocol: parts[2].toLowerCase(),
  1367. priority: parseInt(parts[3], 10),
  1368. ip: parts[4],
  1369. address: parts[4], // address is an alias for ip.
  1370. port: parseInt(parts[5], 10),
  1371. // skip parts[6] == 'typ'
  1372. type: parts[7]
  1373. };
  1374. for (var i = 8; i < parts.length; i += 2) {
  1375. switch (parts[i]) {
  1376. case 'raddr':
  1377. candidate.relatedAddress = parts[i + 1];
  1378. break;
  1379. case 'rport':
  1380. candidate.relatedPort = parseInt(parts[i + 1], 10);
  1381. break;
  1382. case 'tcptype':
  1383. candidate.tcpType = parts[i + 1];
  1384. break;
  1385. case 'ufrag':
  1386. candidate.ufrag = parts[i + 1]; // for backward compability.
  1387. candidate.usernameFragment = parts[i + 1];
  1388. break;
  1389. default: // extension handling, in particular ufrag
  1390. candidate[parts[i]] = parts[i + 1];
  1391. break;
  1392. }
  1393. }
  1394. return candidate;
  1395. };
  1396. // Translates a candidate object into SDP candidate attribute.
  1397. SDPUtils.writeCandidate = function(candidate) {
  1398. var sdp = [];
  1399. sdp.push(candidate.foundation);
  1400. sdp.push(candidate.component);
  1401. sdp.push(candidate.protocol.toUpperCase());
  1402. sdp.push(candidate.priority);
  1403. sdp.push(candidate.address || candidate.ip);
  1404. sdp.push(candidate.port);
  1405. var type = candidate.type;
  1406. sdp.push('typ');
  1407. sdp.push(type);
  1408. if (type !== 'host' && candidate.relatedAddress &&
  1409. candidate.relatedPort) {
  1410. sdp.push('raddr');
  1411. sdp.push(candidate.relatedAddress);
  1412. sdp.push('rport');
  1413. sdp.push(candidate.relatedPort);
  1414. }
  1415. if (candidate.tcpType && candidate.protocol.toLowerCase() === 'tcp') {
  1416. sdp.push('tcptype');
  1417. sdp.push(candidate.tcpType);
  1418. }
  1419. if (candidate.usernameFragment || candidate.ufrag) {
  1420. sdp.push('ufrag');
  1421. sdp.push(candidate.usernameFragment || candidate.ufrag);
  1422. }
  1423. return 'candidate:' + sdp.join(' ');
  1424. };
  1425. // Parses an ice-options line, returns an array of option tags.
  1426. // a=ice-options:foo bar
  1427. SDPUtils.parseIceOptions = function(line) {
  1428. return line.substr(14).split(' ');
  1429. };
  1430. // Parses an rtpmap line, returns RTCRtpCoddecParameters. Sample input:
  1431. // a=rtpmap:111 opus/48000/2
  1432. SDPUtils.parseRtpMap = function(line) {
  1433. var parts = line.substr(9).split(' ');
  1434. var parsed = {
  1435. payloadType: parseInt(parts.shift(), 10) // was: id
  1436. };
  1437. parts = parts[0].split('/');
  1438. parsed.name = parts[0];
  1439. parsed.clockRate = parseInt(parts[1], 10); // was: clockrate
  1440. parsed.channels = parts.length === 3 ? parseInt(parts[2], 10) : 1;
  1441. // legacy alias, got renamed back to channels in ORTC.
  1442. parsed.numChannels = parsed.channels;
  1443. return parsed;
  1444. };
  1445. // Generate an a=rtpmap line from RTCRtpCodecCapability or
  1446. // RTCRtpCodecParameters.
  1447. SDPUtils.writeRtpMap = function(codec) {
  1448. var pt = codec.payloadType;
  1449. if (codec.preferredPayloadType !== undefined) {
  1450. pt = codec.preferredPayloadType;
  1451. }
  1452. var channels = codec.channels || codec.numChannels || 1;
  1453. return 'a=rtpmap:' + pt + ' ' + codec.name + '/' + codec.clockRate +
  1454. (channels !== 1 ? '/' + channels : '') + '\r\n';
  1455. };
  1456. // Parses an a=extmap line (headerextension from RFC 5285). Sample input:
  1457. // a=extmap:2 urn:ietf:params:rtp-hdrext:toffset
  1458. // a=extmap:2/sendonly urn:ietf:params:rtp-hdrext:toffset
  1459. SDPUtils.parseExtmap = function(line) {
  1460. var parts = line.substr(9).split(' ');
  1461. return {
  1462. id: parseInt(parts[0], 10),
  1463. direction: parts[0].indexOf('/') > 0 ? parts[0].split('/')[1] : 'sendrecv',
  1464. uri: parts[1]
  1465. };
  1466. };
  1467. // Generates a=extmap line from RTCRtpHeaderExtensionParameters or
  1468. // RTCRtpHeaderExtension.
  1469. SDPUtils.writeExtmap = function(headerExtension) {
  1470. return 'a=extmap:' + (headerExtension.id || headerExtension.preferredId) +
  1471. (headerExtension.direction && headerExtension.direction !== 'sendrecv'
  1472. ? '/' + headerExtension.direction
  1473. : '') +
  1474. ' ' + headerExtension.uri + '\r\n';
  1475. };
  1476. // Parses an ftmp line, returns dictionary. Sample input:
  1477. // a=fmtp:96 vbr=on;cng=on
  1478. // Also deals with vbr=on; cng=on
  1479. SDPUtils.parseFmtp = function(line) {
  1480. var parsed = {};
  1481. var kv;
  1482. var parts = line.substr(line.indexOf(' ') + 1).split(';');
  1483. for (var j = 0; j < parts.length; j++) {
  1484. kv = parts[j].trim().split('=');
  1485. parsed[kv[0].trim()] = kv[1];
  1486. }
  1487. return parsed;
  1488. };
  1489. // Generates an a=ftmp line from RTCRtpCodecCapability or RTCRtpCodecParameters.
  1490. SDPUtils.writeFmtp = function(codec) {
  1491. var line = '';
  1492. var pt = codec.payloadType;
  1493. if (codec.preferredPayloadType !== undefined) {
  1494. pt = codec.preferredPayloadType;
  1495. }
  1496. if (codec.parameters && Object.keys(codec.parameters).length) {
  1497. var params = [];
  1498. Object.keys(codec.parameters).forEach(function(param) {
  1499. if (codec.parameters[param]) {
  1500. params.push(param + '=' + codec.parameters[param]);
  1501. } else {
  1502. params.push(param);
  1503. }
  1504. });
  1505. line += 'a=fmtp:' + pt + ' ' + params.join(';') + '\r\n';
  1506. }
  1507. return line;
  1508. };
  1509. // Parses an rtcp-fb line, returns RTCPRtcpFeedback object. Sample input:
  1510. // a=rtcp-fb:98 nack rpsi
  1511. SDPUtils.parseRtcpFb = function(line) {
  1512. var parts = line.substr(line.indexOf(' ') + 1).split(' ');
  1513. return {
  1514. type: parts.shift(),
  1515. parameter: parts.join(' ')
  1516. };
  1517. };
  1518. // Generate a=rtcp-fb lines from RTCRtpCodecCapability or RTCRtpCodecParameters.
  1519. SDPUtils.writeRtcpFb = function(codec) {
  1520. var lines = '';
  1521. var pt = codec.payloadType;
  1522. if (codec.preferredPayloadType !== undefined) {
  1523. pt = codec.preferredPayloadType;
  1524. }
  1525. if (codec.rtcpFeedback && codec.rtcpFeedback.length) {
  1526. // FIXME: special handling for trr-int?
  1527. codec.rtcpFeedback.forEach(function(fb) {
  1528. lines += 'a=rtcp-fb:' + pt + ' ' + fb.type +
  1529. (fb.parameter && fb.parameter.length ? ' ' + fb.parameter : '') +
  1530. '\r\n';
  1531. });
  1532. }
  1533. return lines;
  1534. };
  1535. // Parses an RFC 5576 ssrc media attribute. Sample input:
  1536. // a=ssrc:3735928559 cname:something
  1537. SDPUtils.parseSsrcMedia = function(line) {
  1538. var sp = line.indexOf(' ');
  1539. var parts = {
  1540. ssrc: parseInt(line.substr(7, sp - 7), 10)
  1541. };
  1542. var colon = line.indexOf(':', sp);
  1543. if (colon > -1) {
  1544. parts.attribute = line.substr(sp + 1, colon - sp - 1);
  1545. parts.value = line.substr(colon + 1);
  1546. } else {
  1547. parts.attribute = line.substr(sp + 1);
  1548. }
  1549. return parts;
  1550. };
  1551. SDPUtils.parseSsrcGroup = function(line) {
  1552. var parts = line.substr(13).split(' ');
  1553. return {
  1554. semantics: parts.shift(),
  1555. ssrcs: parts.map(function(ssrc) {
  1556. return parseInt(ssrc, 10);
  1557. })
  1558. };
  1559. };
  1560. // Extracts the MID (RFC 5888) from a media section.
  1561. // returns the MID or undefined if no mid line was found.
  1562. SDPUtils.getMid = function(mediaSection) {
  1563. var mid = SDPUtils.matchPrefix(mediaSection, 'a=mid:')[0];
  1564. if (mid) {
  1565. return mid.substr(6);
  1566. }
  1567. };
  1568. SDPUtils.parseFingerprint = function(line) {
  1569. var parts = line.substr(14).split(' ');
  1570. return {
  1571. algorithm: parts[0].toLowerCase(), // algorithm is case-sensitive in Edge.
  1572. value: parts[1]
  1573. };
  1574. };
  1575. // Extracts DTLS parameters from SDP media section or sessionpart.
  1576. // FIXME: for consistency with other functions this should only
  1577. // get the fingerprint line as input. See also getIceParameters.
  1578. SDPUtils.getDtlsParameters = function(mediaSection, sessionpart) {
  1579. var lines = SDPUtils.matchPrefix(mediaSection + sessionpart,
  1580. 'a=fingerprint:');
  1581. // Note: a=setup line is ignored since we use the 'auto' role.
  1582. // Note2: 'algorithm' is not case sensitive except in Edge.
  1583. return {
  1584. role: 'auto',
  1585. fingerprints: lines.map(SDPUtils.parseFingerprint)
  1586. };
  1587. };
  1588. // Serializes DTLS parameters to SDP.
  1589. SDPUtils.writeDtlsParameters = function(params, setupType) {
  1590. var sdp = 'a=setup:' + setupType + '\r\n';
  1591. params.fingerprints.forEach(function(fp) {
  1592. sdp += 'a=fingerprint:' + fp.algorithm + ' ' + fp.value + '\r\n';
  1593. });
  1594. return sdp;
  1595. };
  1596. // Parses a=crypto lines into
  1597. // https://rawgit.com/aboba/edgertc/master/msortc-rs4.html#dictionary-rtcsrtpsdesparameters-members
  1598. SDPUtils.parseCryptoLine = function(line) {
  1599. var parts = line.substr(9).split(' ');
  1600. return {
  1601. tag: parseInt(parts[0], 10),
  1602. cryptoSuite: parts[1],
  1603. keyParams: parts[2],
  1604. sessionParams: parts.slice(3),
  1605. };
  1606. };
  1607. SDPUtils.writeCryptoLine = function(parameters) {
  1608. return 'a=crypto:' + parameters.tag + ' ' +
  1609. parameters.cryptoSuite + ' ' +
  1610. (typeof parameters.keyParams === 'object'
  1611. ? SDPUtils.writeCryptoKeyParams(parameters.keyParams)
  1612. : parameters.keyParams) +
  1613. (parameters.sessionParams ? ' ' + parameters.sessionParams.join(' ') : '') +
  1614. '\r\n';
  1615. };
  1616. // Parses the crypto key parameters into
  1617. // https://rawgit.com/aboba/edgertc/master/msortc-rs4.html#rtcsrtpkeyparam*
  1618. SDPUtils.parseCryptoKeyParams = function(keyParams) {
  1619. if (keyParams.indexOf('inline:') !== 0) {
  1620. return null;
  1621. }
  1622. var parts = keyParams.substr(7).split('|');
  1623. return {
  1624. keyMethod: 'inline',
  1625. keySalt: parts[0],
  1626. lifeTime: parts[1],
  1627. mkiValue: parts[2] ? parts[2].split(':')[0] : undefined,
  1628. mkiLength: parts[2] ? parts[2].split(':')[1] : undefined,
  1629. };
  1630. };
  1631. SDPUtils.writeCryptoKeyParams = function(keyParams) {
  1632. return keyParams.keyMethod + ':'
  1633. + keyParams.keySalt +
  1634. (keyParams.lifeTime ? '|' + keyParams.lifeTime : '') +
  1635. (keyParams.mkiValue && keyParams.mkiLength
  1636. ? '|' + keyParams.mkiValue + ':' + keyParams.mkiLength
  1637. : '');
  1638. };
  1639. // Extracts all SDES paramters.
  1640. SDPUtils.getCryptoParameters = function(mediaSection, sessionpart) {
  1641. var lines = SDPUtils.matchPrefix(mediaSection + sessionpart,
  1642. 'a=crypto:');
  1643. return lines.map(SDPUtils.parseCryptoLine);
  1644. };
  1645. // Parses ICE information from SDP media section or sessionpart.
  1646. // FIXME: for consistency with other functions this should only
  1647. // get the ice-ufrag and ice-pwd lines as input.
  1648. SDPUtils.getIceParameters = function(mediaSection, sessionpart) {
  1649. var ufrag = SDPUtils.matchPrefix(mediaSection + sessionpart,
  1650. 'a=ice-ufrag:')[0];
  1651. var pwd = SDPUtils.matchPrefix(mediaSection + sessionpart,
  1652. 'a=ice-pwd:')[0];
  1653. if (!(ufrag && pwd)) {
  1654. return null;
  1655. }
  1656. return {
  1657. usernameFragment: ufrag.substr(12),
  1658. password: pwd.substr(10),
  1659. };
  1660. };
  1661. // Serializes ICE parameters to SDP.
  1662. SDPUtils.writeIceParameters = function(params) {
  1663. return 'a=ice-ufrag:' + params.usernameFragment + '\r\n' +
  1664. 'a=ice-pwd:' + params.password + '\r\n';
  1665. };
  1666. // Parses the SDP media section and returns RTCRtpParameters.
  1667. SDPUtils.parseRtpParameters = function(mediaSection) {
  1668. var description = {
  1669. codecs: [],
  1670. headerExtensions: [],
  1671. fecMechanisms: [],
  1672. rtcp: []
  1673. };
  1674. var lines = SDPUtils.splitLines(mediaSection);
  1675. var mline = lines[0].split(' ');
  1676. for (var i = 3; i < mline.length; i++) { // find all codecs from mline[3..]
  1677. var pt = mline[i];
  1678. var rtpmapline = SDPUtils.matchPrefix(
  1679. mediaSection, 'a=rtpmap:' + pt + ' ')[0];
  1680. if (rtpmapline) {
  1681. var codec = SDPUtils.parseRtpMap(rtpmapline);
  1682. var fmtps = SDPUtils.matchPrefix(
  1683. mediaSection, 'a=fmtp:' + pt + ' ');
  1684. // Only the first a=fmtp:<pt> is considered.
  1685. codec.parameters = fmtps.length ? SDPUtils.parseFmtp(fmtps[0]) : {};
  1686. codec.rtcpFeedback = SDPUtils.matchPrefix(
  1687. mediaSection, 'a=rtcp-fb:' + pt + ' ')
  1688. .map(SDPUtils.parseRtcpFb);
  1689. description.codecs.push(codec);
  1690. // parse FEC mechanisms from rtpmap lines.
  1691. switch (codec.name.toUpperCase()) {
  1692. case 'RED':
  1693. case 'ULPFEC':
  1694. description.fecMechanisms.push(codec.name.toUpperCase());
  1695. break;
  1696. }
  1697. }
  1698. }
  1699. SDPUtils.matchPrefix(mediaSection, 'a=extmap:').forEach(function(line) {
  1700. description.headerExtensions.push(SDPUtils.parseExtmap(line));
  1701. });
  1702. // FIXME: parse rtcp.
  1703. return description;
  1704. };
  1705. // Generates parts of the SDP media section describing the capabilities /
  1706. // parameters.
  1707. SDPUtils.writeRtpDescription = function(kind, caps) {
  1708. var sdp = '';
  1709. // Build the mline.
  1710. sdp += 'm=' + kind + ' ';
  1711. sdp += caps.codecs.length > 0 ? '9' : '0'; // reject if no codecs.
  1712. sdp += ' UDP/TLS/RTP/SAVPF ';
  1713. sdp += caps.codecs.map(function(codec) {
  1714. if (codec.preferredPayloadType !== undefined) {
  1715. return codec.preferredPayloadType;
  1716. }
  1717. return codec.payloadType;
  1718. }).join(' ') + '\r\n';
  1719. sdp += 'c=IN IP4 0.0.0.0\r\n';
  1720. sdp += 'a=rtcp:9 IN IP4 0.0.0.0\r\n';
  1721. // Add a=rtpmap lines for each codec. Also fmtp and rtcp-fb.
  1722. caps.codecs.forEach(function(codec) {
  1723. sdp += SDPUtils.writeRtpMap(codec);
  1724. sdp += SDPUtils.writeFmtp(codec);
  1725. sdp += SDPUtils.writeRtcpFb(codec);
  1726. });
  1727. var maxptime = 0;
  1728. caps.codecs.forEach(function(codec) {
  1729. if (codec.maxptime > maxptime) {
  1730. maxptime = codec.maxptime;
  1731. }
  1732. });
  1733. if (maxptime > 0) {
  1734. sdp += 'a=maxptime:' + maxptime + '\r\n';
  1735. }
  1736. sdp += 'a=rtcp-mux\r\n';
  1737. if (caps.headerExtensions) {
  1738. caps.headerExtensions.forEach(function(extension) {
  1739. sdp += SDPUtils.writeExtmap(extension);
  1740. });
  1741. }
  1742. // FIXME: write fecMechanisms.
  1743. return sdp;
  1744. };
  1745. // Parses the SDP media section and returns an array of
  1746. // RTCRtpEncodingParameters.
  1747. SDPUtils.parseRtpEncodingParameters = function(mediaSection) {
  1748. var encodingParameters = [];
  1749. var description = SDPUtils.parseRtpParameters(mediaSection);
  1750. var hasRed = description.fecMechanisms.indexOf('RED') !== -1;
  1751. var hasUlpfec = description.fecMechanisms.indexOf('ULPFEC') !== -1;
  1752. // filter a=ssrc:... cname:, ignore PlanB-msid
  1753. var ssrcs = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:')
  1754. .map(function(line) {
  1755. return SDPUtils.parseSsrcMedia(line);
  1756. })
  1757. .filter(function(parts) {
  1758. return parts.attribute === 'cname';
  1759. });
  1760. var primarySsrc = ssrcs.length > 0 && ssrcs[0].ssrc;
  1761. var secondarySsrc;
  1762. var flows = SDPUtils.matchPrefix(mediaSection, 'a=ssrc-group:FID')
  1763. .map(function(line) {
  1764. var parts = line.substr(17).split(' ');
  1765. return parts.map(function(part) {
  1766. return parseInt(part, 10);
  1767. });
  1768. });
  1769. if (flows.length > 0 && flows[0].length > 1 && flows[0][0] === primarySsrc) {
  1770. secondarySsrc = flows[0][1];
  1771. }
  1772. description.codecs.forEach(function(codec) {
  1773. if (codec.name.toUpperCase() === 'RTX' && codec.parameters.apt) {
  1774. var encParam = {
  1775. ssrc: primarySsrc,
  1776. codecPayloadType: parseInt(codec.parameters.apt, 10)
  1777. };
  1778. if (primarySsrc && secondarySsrc) {
  1779. encParam.rtx = {ssrc: secondarySsrc};
  1780. }
  1781. encodingParameters.push(encParam);
  1782. if (hasRed) {
  1783. encParam = JSON.parse(JSON.stringify(encParam));
  1784. encParam.fec = {
  1785. ssrc: primarySsrc,
  1786. mechanism: hasUlpfec ? 'red+ulpfec' : 'red'
  1787. };
  1788. encodingParameters.push(encParam);
  1789. }
  1790. }
  1791. });
  1792. if (encodingParameters.length === 0 && primarySsrc) {
  1793. encodingParameters.push({
  1794. ssrc: primarySsrc
  1795. });
  1796. }
  1797. // we support both b=AS and b=TIAS but interpret AS as TIAS.
  1798. var bandwidth = SDPUtils.matchPrefix(mediaSection, 'b=');
  1799. if (bandwidth.length) {
  1800. if (bandwidth[0].indexOf('b=TIAS:') === 0) {
  1801. bandwidth = parseInt(bandwidth[0].substr(7), 10);
  1802. } else if (bandwidth[0].indexOf('b=AS:') === 0) {
  1803. // use formula from JSEP to convert b=AS to TIAS value.
  1804. bandwidth = parseInt(bandwidth[0].substr(5), 10) * 1000 * 0.95
  1805. - (50 * 40 * 8);
  1806. } else {
  1807. bandwidth = undefined;
  1808. }
  1809. encodingParameters.forEach(function(params) {
  1810. params.maxBitrate = bandwidth;
  1811. });
  1812. }
  1813. return encodingParameters;
  1814. };
  1815. // parses http://draft.ortc.org/#rtcrtcpparameters*
  1816. SDPUtils.parseRtcpParameters = function(mediaSection) {
  1817. var rtcpParameters = {};
  1818. // Gets the first SSRC. Note tha with RTX there might be multiple
  1819. // SSRCs.
  1820. var remoteSsrc = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:')
  1821. .map(function(line) {
  1822. return SDPUtils.parseSsrcMedia(line);
  1823. })
  1824. .filter(function(obj) {
  1825. return obj.attribute === 'cname';
  1826. })[0];
  1827. if (remoteSsrc) {
  1828. rtcpParameters.cname = remoteSsrc.value;
  1829. rtcpParameters.ssrc = remoteSsrc.ssrc;
  1830. }
  1831. // Edge uses the compound attribute instead of reducedSize
  1832. // compound is !reducedSize
  1833. var rsize = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-rsize');
  1834. rtcpParameters.reducedSize = rsize.length > 0;
  1835. rtcpParameters.compound = rsize.length === 0;
  1836. // parses the rtcp-mux attrіbute.
  1837. // Note that Edge does not support unmuxed RTCP.
  1838. var mux = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-mux');
  1839. rtcpParameters.mux = mux.length > 0;
  1840. return rtcpParameters;
  1841. };
  1842. // parses either a=msid: or a=ssrc:... msid lines and returns
  1843. // the id of the MediaStream and MediaStreamTrack.
  1844. SDPUtils.parseMsid = function(mediaSection) {
  1845. var parts;
  1846. var spec = SDPUtils.matchPrefix(mediaSection, 'a=msid:');
  1847. if (spec.length === 1) {
  1848. parts = spec[0].substr(7).split(' ');
  1849. return {stream: parts[0], track: parts[1]};
  1850. }
  1851. var planB = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:')
  1852. .map(function(line) {
  1853. return SDPUtils.parseSsrcMedia(line);
  1854. })
  1855. .filter(function(msidParts) {
  1856. return msidParts.attribute === 'msid';
  1857. });
  1858. if (planB.length > 0) {
  1859. parts = planB[0].value.split(' ');
  1860. return {stream: parts[0], track: parts[1]};
  1861. }
  1862. };
  1863. // SCTP
  1864. // parses draft-ietf-mmusic-sctp-sdp-26 first and falls back
  1865. // to draft-ietf-mmusic-sctp-sdp-05
  1866. SDPUtils.parseSctpDescription = function(mediaSection) {
  1867. var mline = SDPUtils.parseMLine(mediaSection);
  1868. var maxSizeLine = SDPUtils.matchPrefix(mediaSection, 'a=max-message-size:');
  1869. var maxMessageSize;
  1870. if (maxSizeLine.length > 0) {
  1871. maxMessageSize = parseInt(maxSizeLine[0].substr(19), 10);
  1872. }
  1873. if (isNaN(maxMessageSize)) {
  1874. maxMessageSize = 65536;
  1875. }
  1876. var sctpPort = SDPUtils.matchPrefix(mediaSection, 'a=sctp-port:');
  1877. if (sctpPort.length > 0) {
  1878. return {
  1879. port: parseInt(sctpPort[0].substr(12), 10),
  1880. protocol: mline.fmt,
  1881. maxMessageSize: maxMessageSize
  1882. };
  1883. }
  1884. var sctpMapLines = SDPUtils.matchPrefix(mediaSection, 'a=sctpmap:');
  1885. if (sctpMapLines.length > 0) {
  1886. var parts = SDPUtils.matchPrefix(mediaSection, 'a=sctpmap:')[0]
  1887. .substr(10)
  1888. .split(' ');
  1889. return {
  1890. port: parseInt(parts[0], 10),
  1891. protocol: parts[1],
  1892. maxMessageSize: maxMessageSize
  1893. };
  1894. }
  1895. };
  1896. // SCTP
  1897. // outputs the draft-ietf-mmusic-sctp-sdp-26 version that all browsers
  1898. // support by now receiving in this format, unless we originally parsed
  1899. // as the draft-ietf-mmusic-sctp-sdp-05 format (indicated by the m-line
  1900. // protocol of DTLS/SCTP -- without UDP/ or TCP/)
  1901. SDPUtils.writeSctpDescription = function(media, sctp) {
  1902. var output = [];
  1903. if (media.protocol !== 'DTLS/SCTP') {
  1904. output = [
  1905. 'm=' + media.kind + ' 9 ' + media.protocol + ' ' + sctp.protocol + '\r\n',
  1906. 'c=IN IP4 0.0.0.0\r\n',
  1907. 'a=sctp-port:' + sctp.port + '\r\n'
  1908. ];
  1909. } else {
  1910. output = [
  1911. 'm=' + media.kind + ' 9 ' + media.protocol + ' ' + sctp.port + '\r\n',
  1912. 'c=IN IP4 0.0.0.0\r\n',
  1913. 'a=sctpmap:' + sctp.port + ' ' + sctp.protocol + ' 65535\r\n'
  1914. ];
  1915. }
  1916. if (sctp.maxMessageSize !== undefined) {
  1917. output.push('a=max-message-size:' + sctp.maxMessageSize + '\r\n');
  1918. }
  1919. return output.join('');
  1920. };
  1921. // Generate a session ID for SDP.
  1922. // https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-20#section-5.2.1
  1923. // recommends using a cryptographically random +ve 64-bit value
  1924. // but right now this should be acceptable and within the right range
  1925. SDPUtils.generateSessionId = function() {
  1926. return Math.random().toString().substr(2, 21);
  1927. };
  1928. // Write boilder plate for start of SDP
  1929. // sessId argument is optional - if not supplied it will
  1930. // be generated randomly
  1931. // sessVersion is optional and defaults to 2
  1932. // sessUser is optional and defaults to 'thisisadapterortc'
  1933. SDPUtils.writeSessionBoilerplate = function(sessId, sessVer, sessUser) {
  1934. var sessionId;
  1935. var version = sessVer !== undefined ? sessVer : 2;
  1936. if (sessId) {
  1937. sessionId = sessId;
  1938. } else {
  1939. sessionId = SDPUtils.generateSessionId();
  1940. }
  1941. var user = sessUser || 'thisisadapterortc';
  1942. // FIXME: sess-id should be an NTP timestamp.
  1943. return 'v=0\r\n' +
  1944. 'o=' + user + ' ' + sessionId + ' ' + version +
  1945. ' IN IP4 127.0.0.1\r\n' +
  1946. 's=-\r\n' +
  1947. 't=0 0\r\n';
  1948. };
  1949. SDPUtils.writeMediaSection = function(transceiver, caps, type, stream) {
  1950. var sdp = SDPUtils.writeRtpDescription(transceiver.kind, caps);
  1951. // Map ICE parameters (ufrag, pwd) to SDP.
  1952. sdp += SDPUtils.writeIceParameters(
  1953. transceiver.iceGatherer.getLocalParameters());
  1954. // Map DTLS parameters to SDP.
  1955. sdp += SDPUtils.writeDtlsParameters(
  1956. transceiver.dtlsTransport.getLocalParameters(),
  1957. type === 'offer' ? 'actpass' : 'active');
  1958. sdp += 'a=mid:' + transceiver.mid + '\r\n';
  1959. if (transceiver.direction) {
  1960. sdp += 'a=' + transceiver.direction + '\r\n';
  1961. } else if (transceiver.rtpSender && transceiver.rtpReceiver) {
  1962. sdp += 'a=sendrecv\r\n';
  1963. } else if (transceiver.rtpSender) {
  1964. sdp += 'a=sendonly\r\n';
  1965. } else if (transceiver.rtpReceiver) {
  1966. sdp += 'a=recvonly\r\n';
  1967. } else {
  1968. sdp += 'a=inactive\r\n';
  1969. }
  1970. if (transceiver.rtpSender) {
  1971. // spec.
  1972. var msid = 'msid:' + stream.id + ' ' +
  1973. transceiver.rtpSender.track.id + '\r\n';
  1974. sdp += 'a=' + msid;
  1975. // for Chrome.
  1976. sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc +
  1977. ' ' + msid;
  1978. if (transceiver.sendEncodingParameters[0].rtx) {
  1979. sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc +
  1980. ' ' + msid;
  1981. sdp += 'a=ssrc-group:FID ' +
  1982. transceiver.sendEncodingParameters[0].ssrc + ' ' +
  1983. transceiver.sendEncodingParameters[0].rtx.ssrc +
  1984. '\r\n';
  1985. }
  1986. }
  1987. // FIXME: this should be written by writeRtpDescription.
  1988. sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc +
  1989. ' cname:' + SDPUtils.localCName + '\r\n';
  1990. if (transceiver.rtpSender && transceiver.sendEncodingParameters[0].rtx) {
  1991. sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc +
  1992. ' cname:' + SDPUtils.localCName + '\r\n';
  1993. }
  1994. return sdp;
  1995. };
  1996. // Gets the direction from the mediaSection or the sessionpart.
  1997. SDPUtils.getDirection = function(mediaSection, sessionpart) {
  1998. // Look for sendrecv, sendonly, recvonly, inactive, default to sendrecv.
  1999. var lines = SDPUtils.splitLines(mediaSection);
  2000. for (var i = 0; i < lines.length; i++) {
  2001. switch (lines[i]) {
  2002. case 'a=sendrecv':
  2003. case 'a=sendonly':
  2004. case 'a=recvonly':
  2005. case 'a=inactive':
  2006. return lines[i].substr(2);
  2007. // FIXME: What should happen here?
  2008. }
  2009. }
  2010. if (sessionpart) {
  2011. return SDPUtils.getDirection(sessionpart);
  2012. }
  2013. return 'sendrecv';
  2014. };
  2015. SDPUtils.getKind = function(mediaSection) {
  2016. var lines = SDPUtils.splitLines(mediaSection);
  2017. var mline = lines[0].split(' ');
  2018. return mline[0].substr(2);
  2019. };
  2020. SDPUtils.isRejected = function(mediaSection) {
  2021. return mediaSection.split(' ', 2)[1] === '0';
  2022. };
  2023. SDPUtils.parseMLine = function(mediaSection) {
  2024. var lines = SDPUtils.splitLines(mediaSection);
  2025. var parts = lines[0].substr(2).split(' ');
  2026. return {
  2027. kind: parts[0],
  2028. port: parseInt(parts[1], 10),
  2029. protocol: parts[2],
  2030. fmt: parts.slice(3).join(' ')
  2031. };
  2032. };
  2033. SDPUtils.parseOLine = function(mediaSection) {
  2034. var line = SDPUtils.matchPrefix(mediaSection, 'o=')[0];
  2035. var parts = line.substr(2).split(' ');
  2036. return {
  2037. username: parts[0],
  2038. sessionId: parts[1],
  2039. sessionVersion: parseInt(parts[2], 10),
  2040. netType: parts[3],
  2041. addressType: parts[4],
  2042. address: parts[5]
  2043. };
  2044. };
  2045. // a very naive interpretation of a valid SDP.
  2046. SDPUtils.isValidSDP = function(blob) {
  2047. if (typeof blob !== 'string' || blob.length === 0) {
  2048. return false;
  2049. }
  2050. var lines = SDPUtils.splitLines(blob);
  2051. for (var i = 0; i < lines.length; i++) {
  2052. if (lines[i].length < 2 || lines[i].charAt(1) !== '=') {
  2053. return false;
  2054. }
  2055. // TODO: check the modifier a bit more.
  2056. }
  2057. return true;
  2058. };
  2059. // Expose public methods.
  2060. {
  2061. module.exports = SDPUtils;
  2062. }
  2063. });
  2064. /*
  2065. * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
  2066. *
  2067. * Use of this source code is governed by a BSD-style license
  2068. * that can be found in the LICENSE file in the root of the source
  2069. * tree.
  2070. */
  2071. function fixStatsType(stat) {
  2072. return {
  2073. inboundrtp: 'inbound-rtp',
  2074. outboundrtp: 'outbound-rtp',
  2075. candidatepair: 'candidate-pair',
  2076. localcandidate: 'local-candidate',
  2077. remotecandidate: 'remote-candidate'
  2078. }[stat.type] || stat.type;
  2079. }
  2080. function writeMediaSection(transceiver, caps, type, stream, dtlsRole) {
  2081. var sdp$1 = sdp.writeRtpDescription(transceiver.kind, caps);
  2082. // Map ICE parameters (ufrag, pwd) to SDP.
  2083. sdp$1 += sdp.writeIceParameters(
  2084. transceiver.iceGatherer.getLocalParameters());
  2085. // Map DTLS parameters to SDP.
  2086. sdp$1 += sdp.writeDtlsParameters(
  2087. transceiver.dtlsTransport.getLocalParameters(),
  2088. type === 'offer' ? 'actpass' : dtlsRole || 'active');
  2089. sdp$1 += 'a=mid:' + transceiver.mid + '\r\n';
  2090. if (transceiver.rtpSender && transceiver.rtpReceiver) {
  2091. sdp$1 += 'a=sendrecv\r\n';
  2092. } else if (transceiver.rtpSender) {
  2093. sdp$1 += 'a=sendonly\r\n';
  2094. } else if (transceiver.rtpReceiver) {
  2095. sdp$1 += 'a=recvonly\r\n';
  2096. } else {
  2097. sdp$1 += 'a=inactive\r\n';
  2098. }
  2099. if (transceiver.rtpSender) {
  2100. var trackId = transceiver.rtpSender._initialTrackId ||
  2101. transceiver.rtpSender.track.id;
  2102. transceiver.rtpSender._initialTrackId = trackId;
  2103. // spec.
  2104. var msid = 'msid:' + (stream ? stream.id : '-') + ' ' +
  2105. trackId + '\r\n';
  2106. sdp$1 += 'a=' + msid;
  2107. // for Chrome. Legacy should no longer be required.
  2108. sdp$1 += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc +
  2109. ' ' + msid;
  2110. // RTX
  2111. if (transceiver.sendEncodingParameters[0].rtx) {
  2112. sdp$1 += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc +
  2113. ' ' + msid;
  2114. sdp$1 += 'a=ssrc-group:FID ' +
  2115. transceiver.sendEncodingParameters[0].ssrc + ' ' +
  2116. transceiver.sendEncodingParameters[0].rtx.ssrc +
  2117. '\r\n';
  2118. }
  2119. }
  2120. // FIXME: this should be written by writeRtpDescription.
  2121. sdp$1 += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc +
  2122. ' cname:' + sdp.localCName + '\r\n';
  2123. if (transceiver.rtpSender && transceiver.sendEncodingParameters[0].rtx) {
  2124. sdp$1 += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc +
  2125. ' cname:' + sdp.localCName + '\r\n';
  2126. }
  2127. return sdp$1;
  2128. }
  2129. // Edge does not like
  2130. // 1) stun: filtered after 14393 unless ?transport=udp is present
  2131. // 2) turn: that does not have all of turn:host:port?transport=udp
  2132. // 3) turn: with ipv6 addresses
  2133. // 4) turn: occurring muliple times
  2134. function filterIceServers(iceServers, edgeVersion) {
  2135. var hasTurn = false;
  2136. iceServers = JSON.parse(JSON.stringify(iceServers));
  2137. return iceServers.filter(function(server) {
  2138. if (server && (server.urls || server.url)) {
  2139. var urls = server.urls || server.url;
  2140. if (server.url && !server.urls) {
  2141. console.warn('RTCIceServer.url is deprecated! Use urls instead.');
  2142. }
  2143. var isString = typeof urls === 'string';
  2144. if (isString) {
  2145. urls = [urls];
  2146. }
  2147. urls = urls.filter(function(url) {
  2148. var validTurn = url.indexOf('turn:') === 0 &&
  2149. url.indexOf('transport=udp') !== -1 &&
  2150. url.indexOf('turn:[') === -1 &&
  2151. !hasTurn;
  2152. if (validTurn) {
  2153. hasTurn = true;
  2154. return true;
  2155. }
  2156. return url.indexOf('stun:') === 0 && edgeVersion >= 14393 &&
  2157. url.indexOf('?transport=udp') === -1;
  2158. });
  2159. delete server.url;
  2160. server.urls = isString ? urls[0] : urls;
  2161. return !!urls.length;
  2162. }
  2163. });
  2164. }
  2165. // Determines the intersection of local and remote capabilities.
  2166. function getCommonCapabilities(localCapabilities, remoteCapabilities) {
  2167. var commonCapabilities = {
  2168. codecs: [],
  2169. headerExtensions: [],
  2170. fecMechanisms: []
  2171. };
  2172. var findCodecByPayloadType = function(pt, codecs) {
  2173. pt = parseInt(pt, 10);
  2174. for (var i = 0; i < codecs.length; i++) {
  2175. if (codecs[i].payloadType === pt ||
  2176. codecs[i].preferredPayloadType === pt) {
  2177. return codecs[i];
  2178. }
  2179. }
  2180. };
  2181. var rtxCapabilityMatches = function(lRtx, rRtx, lCodecs, rCodecs) {
  2182. var lCodec = findCodecByPayloadType(lRtx.parameters.apt, lCodecs);
  2183. var rCodec = findCodecByPayloadType(rRtx.parameters.apt, rCodecs);
  2184. return lCodec && rCodec &&
  2185. lCodec.name.toLowerCase() === rCodec.name.toLowerCase();
  2186. };
  2187. localCapabilities.codecs.forEach(function(lCodec) {
  2188. for (var i = 0; i < remoteCapabilities.codecs.length; i++) {
  2189. var rCodec = remoteCapabilities.codecs[i];
  2190. if (lCodec.name.toLowerCase() === rCodec.name.toLowerCase() &&
  2191. lCodec.clockRate === rCodec.clockRate) {
  2192. if (lCodec.name.toLowerCase() === 'rtx' &&
  2193. lCodec.parameters && rCodec.parameters.apt) {
  2194. // for RTX we need to find the local rtx that has a apt
  2195. // which points to the same local codec as the remote one.
  2196. if (!rtxCapabilityMatches(lCodec, rCodec,
  2197. localCapabilities.codecs, remoteCapabilities.codecs)) {
  2198. continue;
  2199. }
  2200. }
  2201. rCodec = JSON.parse(JSON.stringify(rCodec)); // deepcopy
  2202. // number of channels is the highest common number of channels
  2203. rCodec.numChannels = Math.min(lCodec.numChannels,
  2204. rCodec.numChannels);
  2205. // push rCodec so we reply with offerer payload type
  2206. commonCapabilities.codecs.push(rCodec);
  2207. // determine common feedback mechanisms
  2208. rCodec.rtcpFeedback = rCodec.rtcpFeedback.filter(function(fb) {
  2209. for (var j = 0; j < lCodec.rtcpFeedback.length; j++) {
  2210. if (lCodec.rtcpFeedback[j].type === fb.type &&
  2211. lCodec.rtcpFeedback[j].parameter === fb.parameter) {
  2212. return true;
  2213. }
  2214. }
  2215. return false;
  2216. });
  2217. // FIXME: also need to determine .parameters
  2218. // see https://github.com/openpeer/ortc/issues/569
  2219. break;
  2220. }
  2221. }
  2222. });
  2223. localCapabilities.headerExtensions.forEach(function(lHeaderExtension) {
  2224. for (var i = 0; i < remoteCapabilities.headerExtensions.length;
  2225. i++) {
  2226. var rHeaderExtension = remoteCapabilities.headerExtensions[i];
  2227. if (lHeaderExtension.uri === rHeaderExtension.uri) {
  2228. commonCapabilities.headerExtensions.push(rHeaderExtension);
  2229. break;
  2230. }
  2231. }
  2232. });
  2233. // FIXME: fecMechanisms
  2234. return commonCapabilities;
  2235. }
  2236. // is action=setLocalDescription with type allowed in signalingState
  2237. function isActionAllowedInSignalingState(action, type, signalingState) {
  2238. return {
  2239. offer: {
  2240. setLocalDescription: ['stable', 'have-local-offer'],
  2241. setRemoteDescription: ['stable', 'have-remote-offer']
  2242. },
  2243. answer: {
  2244. setLocalDescription: ['have-remote-offer', 'have-local-pranswer'],
  2245. setRemoteDescription: ['have-local-offer', 'have-remote-pranswer']
  2246. }
  2247. }[type][action].indexOf(signalingState) !== -1;
  2248. }
  2249. function maybeAddCandidate(iceTransport, candidate) {
  2250. // Edge's internal representation adds some fields therefore
  2251. // not all fieldѕ are taken into account.
  2252. var alreadyAdded = iceTransport.getRemoteCandidates()
  2253. .find(function(remoteCandidate) {
  2254. return candidate.foundation === remoteCandidate.foundation &&
  2255. candidate.ip === remoteCandidate.ip &&
  2256. candidate.port === remoteCandidate.port &&
  2257. candidate.priority === remoteCandidate.priority &&
  2258. candidate.protocol === remoteCandidate.protocol &&
  2259. candidate.type === remoteCandidate.type;
  2260. });
  2261. if (!alreadyAdded) {
  2262. iceTransport.addRemoteCandidate(candidate);
  2263. }
  2264. return !alreadyAdded;
  2265. }
  2266. function makeError(name, description) {
  2267. var e = new Error(description);
  2268. e.name = name;
  2269. // legacy error codes from https://heycam.github.io/webidl/#idl-DOMException-error-names
  2270. e.code = {
  2271. NotSupportedError: 9,
  2272. InvalidStateError: 11,
  2273. InvalidAccessError: 15,
  2274. TypeError: undefined,
  2275. OperationError: undefined
  2276. }[name];
  2277. return e;
  2278. }
  2279. var rtcpeerconnection = function(window, edgeVersion) {
  2280. // https://w3c.github.io/mediacapture-main/#mediastream
  2281. // Helper function to add the track to the stream and
  2282. // dispatch the event ourselves.
  2283. function addTrackToStreamAndFireEvent(track, stream) {
  2284. stream.addTrack(track);
  2285. stream.dispatchEvent(new window.MediaStreamTrackEvent('addtrack',
  2286. {track: track}));
  2287. }
  2288. function removeTrackFromStreamAndFireEvent(track, stream) {
  2289. stream.removeTrack(track);
  2290. stream.dispatchEvent(new window.MediaStreamTrackEvent('removetrack',
  2291. {track: track}));
  2292. }
  2293. function fireAddTrack(pc, track, receiver, streams) {
  2294. var trackEvent = new Event('track');
  2295. trackEvent.track = track;
  2296. trackEvent.receiver = receiver;
  2297. trackEvent.transceiver = {receiver: receiver};
  2298. trackEvent.streams = streams;
  2299. window.setTimeout(function() {
  2300. pc._dispatchEvent('track', trackEvent);
  2301. });
  2302. }
  2303. var RTCPeerConnection = function(config) {
  2304. var pc = this;
  2305. var _eventTarget = document.createDocumentFragment();
  2306. ['addEventListener', 'removeEventListener', 'dispatchEvent']
  2307. .forEach(function(method) {
  2308. pc[method] = _eventTarget[method].bind(_eventTarget);
  2309. });
  2310. this.canTrickleIceCandidates = null;
  2311. this.needNegotiation = false;
  2312. this.localStreams = [];
  2313. this.remoteStreams = [];
  2314. this._localDescription = null;
  2315. this._remoteDescription = null;
  2316. this.signalingState = 'stable';
  2317. this.iceConnectionState = 'new';
  2318. this.connectionState = 'new';
  2319. this.iceGatheringState = 'new';
  2320. config = JSON.parse(JSON.stringify(config || {}));
  2321. this.usingBundle = config.bundlePolicy === 'max-bundle';
  2322. if (config.rtcpMuxPolicy === 'negotiate') {
  2323. throw(makeError('NotSupportedError',
  2324. 'rtcpMuxPolicy \'negotiate\' is not supported'));
  2325. } else if (!config.rtcpMuxPolicy) {
  2326. config.rtcpMuxPolicy = 'require';
  2327. }
  2328. switch (config.iceTransportPolicy) {
  2329. case 'all':
  2330. case 'relay':
  2331. break;
  2332. default:
  2333. config.iceTransportPolicy = 'all';
  2334. break;
  2335. }
  2336. switch (config.bundlePolicy) {
  2337. case 'balanced':
  2338. case 'max-compat':
  2339. case 'max-bundle':
  2340. break;
  2341. default:
  2342. config.bundlePolicy = 'balanced';
  2343. break;
  2344. }
  2345. config.iceServers = filterIceServers(config.iceServers || [], edgeVersion);
  2346. this._iceGatherers = [];
  2347. if (config.iceCandidatePoolSize) {
  2348. for (var i = config.iceCandidatePoolSize; i > 0; i--) {
  2349. this._iceGatherers.push(new window.RTCIceGatherer({
  2350. iceServers: config.iceServers,
  2351. gatherPolicy: config.iceTransportPolicy
  2352. }));
  2353. }
  2354. } else {
  2355. config.iceCandidatePoolSize = 0;
  2356. }
  2357. this._config = config;
  2358. // per-track iceGathers, iceTransports, dtlsTransports, rtpSenders, ...
  2359. // everything that is needed to describe a SDP m-line.
  2360. this.transceivers = [];
  2361. this._sdpSessionId = sdp.generateSessionId();
  2362. this._sdpSessionVersion = 0;
  2363. this._dtlsRole = undefined; // role for a=setup to use in answers.
  2364. this._isClosed = false;
  2365. };
  2366. Object.defineProperty(RTCPeerConnection.prototype, 'localDescription', {
  2367. configurable: true,
  2368. get: function() {
  2369. return this._localDescription;
  2370. }
  2371. });
  2372. Object.defineProperty(RTCPeerConnection.prototype, 'remoteDescription', {
  2373. configurable: true,
  2374. get: function() {
  2375. return this._remoteDescription;
  2376. }
  2377. });
  2378. // set up event handlers on prototype
  2379. RTCPeerConnection.prototype.onicecandidate = null;
  2380. RTCPeerConnection.prototype.onaddstream = null;
  2381. RTCPeerConnection.prototype.ontrack = null;
  2382. RTCPeerConnection.prototype.onremovestream = null;
  2383. RTCPeerConnection.prototype.onsignalingstatechange = null;
  2384. RTCPeerConnection.prototype.oniceconnectionstatechange = null;
  2385. RTCPeerConnection.prototype.onconnectionstatechange = null;
  2386. RTCPeerConnection.prototype.onicegatheringstatechange = null;
  2387. RTCPeerConnection.prototype.onnegotiationneeded = null;
  2388. RTCPeerConnection.prototype.ondatachannel = null;
  2389. RTCPeerConnection.prototype._dispatchEvent = function(name, event) {
  2390. if (this._isClosed) {
  2391. return;
  2392. }
  2393. this.dispatchEvent(event);
  2394. if (typeof this['on' + name] === 'function') {
  2395. this['on' + name](event);
  2396. }
  2397. };
  2398. RTCPeerConnection.prototype._emitGatheringStateChange = function() {
  2399. var event = new Event('icegatheringstatechange');
  2400. this._dispatchEvent('icegatheringstatechange', event);
  2401. };
  2402. RTCPeerConnection.prototype.getConfiguration = function() {
  2403. return this._config;
  2404. };
  2405. RTCPeerConnection.prototype.getLocalStreams = function() {
  2406. return this.localStreams;
  2407. };
  2408. RTCPeerConnection.prototype.getRemoteStreams = function() {
  2409. return this.remoteStreams;
  2410. };
  2411. // internal helper to create a transceiver object.
  2412. // (which is not yet the same as the WebRTC 1.0 transceiver)
  2413. RTCPeerConnection.prototype._createTransceiver = function(kind, doNotAdd) {
  2414. var hasBundleTransport = this.transceivers.length > 0;
  2415. var transceiver = {
  2416. track: null,
  2417. iceGatherer: null,
  2418. iceTransport: null,
  2419. dtlsTransport: null,
  2420. localCapabilities: null,
  2421. remoteCapabilities: null,
  2422. rtpSender: null,
  2423. rtpReceiver: null,
  2424. kind: kind,
  2425. mid: null,
  2426. sendEncodingParameters: null,
  2427. recvEncodingParameters: null,
  2428. stream: null,
  2429. associatedRemoteMediaStreams: [],
  2430. wantReceive: true
  2431. };
  2432. if (this.usingBundle && hasBundleTransport) {
  2433. transceiver.iceTransport = this.transceivers[0].iceTransport;
  2434. transceiver.dtlsTransport = this.transceivers[0].dtlsTransport;
  2435. } else {
  2436. var transports = this._createIceAndDtlsTransports();
  2437. transceiver.iceTransport = transports.iceTransport;
  2438. transceiver.dtlsTransport = transports.dtlsTransport;
  2439. }
  2440. if (!doNotAdd) {
  2441. this.transceivers.push(transceiver);
  2442. }
  2443. return transceiver;
  2444. };
  2445. RTCPeerConnection.prototype.addTrack = function(track, stream) {
  2446. if (this._isClosed) {
  2447. throw makeError('InvalidStateError',
  2448. 'Attempted to call addTrack on a closed peerconnection.');
  2449. }
  2450. var alreadyExists = this.transceivers.find(function(s) {
  2451. return s.track === track;
  2452. });
  2453. if (alreadyExists) {
  2454. throw makeError('InvalidAccessError', 'Track already exists.');
  2455. }
  2456. var transceiver;
  2457. for (var i = 0; i < this.transceivers.length; i++) {
  2458. if (!this.transceivers[i].track &&
  2459. this.transceivers[i].kind === track.kind) {
  2460. transceiver = this.transceivers[i];
  2461. }
  2462. }
  2463. if (!transceiver) {
  2464. transceiver = this._createTransceiver(track.kind);
  2465. }
  2466. this._maybeFireNegotiationNeeded();
  2467. if (this.localStreams.indexOf(stream) === -1) {
  2468. this.localStreams.push(stream);
  2469. }
  2470. transceiver.track = track;
  2471. transceiver.stream = stream;
  2472. transceiver.rtpSender = new window.RTCRtpSender(track,
  2473. transceiver.dtlsTransport);
  2474. return transceiver.rtpSender;
  2475. };
  2476. RTCPeerConnection.prototype.addStream = function(stream) {
  2477. var pc = this;
  2478. if (edgeVersion >= 15025) {
  2479. stream.getTracks().forEach(function(track) {
  2480. pc.addTrack(track, stream);
  2481. });
  2482. } else {
  2483. // Clone is necessary for local demos mostly, attaching directly
  2484. // to two different senders does not work (build 10547).
  2485. // Fixed in 15025 (or earlier)
  2486. var clonedStream = stream.clone();
  2487. stream.getTracks().forEach(function(track, idx) {
  2488. var clonedTrack = clonedStream.getTracks()[idx];
  2489. track.addEventListener('enabled', function(event) {
  2490. clonedTrack.enabled = event.enabled;
  2491. });
  2492. });
  2493. clonedStream.getTracks().forEach(function(track) {
  2494. pc.addTrack(track, clonedStream);
  2495. });
  2496. }
  2497. };
  2498. RTCPeerConnection.prototype.removeTrack = function(sender) {
  2499. if (this._isClosed) {
  2500. throw makeError('InvalidStateError',
  2501. 'Attempted to call removeTrack on a closed peerconnection.');
  2502. }
  2503. if (!(sender instanceof window.RTCRtpSender)) {
  2504. throw new TypeError('Argument 1 of RTCPeerConnection.removeTrack ' +
  2505. 'does not implement interface RTCRtpSender.');
  2506. }
  2507. var transceiver = this.transceivers.find(function(t) {
  2508. return t.rtpSender === sender;
  2509. });
  2510. if (!transceiver) {
  2511. throw makeError('InvalidAccessError',
  2512. 'Sender was not created by this connection.');
  2513. }
  2514. var stream = transceiver.stream;
  2515. transceiver.rtpSender.stop();
  2516. transceiver.rtpSender = null;
  2517. transceiver.track = null;
  2518. transceiver.stream = null;
  2519. // remove the stream from the set of local streams
  2520. var localStreams = this.transceivers.map(function(t) {
  2521. return t.stream;
  2522. });
  2523. if (localStreams.indexOf(stream) === -1 &&
  2524. this.localStreams.indexOf(stream) > -1) {
  2525. this.localStreams.splice(this.localStreams.indexOf(stream), 1);
  2526. }
  2527. this._maybeFireNegotiationNeeded();
  2528. };
  2529. RTCPeerConnection.prototype.removeStream = function(stream) {
  2530. var pc = this;
  2531. stream.getTracks().forEach(function(track) {
  2532. var sender = pc.getSenders().find(function(s) {
  2533. return s.track === track;
  2534. });
  2535. if (sender) {
  2536. pc.removeTrack(sender);
  2537. }
  2538. });
  2539. };
  2540. RTCPeerConnection.prototype.getSenders = function() {
  2541. return this.transceivers.filter(function(transceiver) {
  2542. return !!transceiver.rtpSender;
  2543. })
  2544. .map(function(transceiver) {
  2545. return transceiver.rtpSender;
  2546. });
  2547. };
  2548. RTCPeerConnection.prototype.getReceivers = function() {
  2549. return this.transceivers.filter(function(transceiver) {
  2550. return !!transceiver.rtpReceiver;
  2551. })
  2552. .map(function(transceiver) {
  2553. return transceiver.rtpReceiver;
  2554. });
  2555. };
  2556. RTCPeerConnection.prototype._createIceGatherer = function(sdpMLineIndex,
  2557. usingBundle) {
  2558. var pc = this;
  2559. if (usingBundle && sdpMLineIndex > 0) {
  2560. return this.transceivers[0].iceGatherer;
  2561. } else if (this._iceGatherers.length) {
  2562. return this._iceGatherers.shift();
  2563. }
  2564. var iceGatherer = new window.RTCIceGatherer({
  2565. iceServers: this._config.iceServers,
  2566. gatherPolicy: this._config.iceTransportPolicy
  2567. });
  2568. Object.defineProperty(iceGatherer, 'state',
  2569. {value: 'new', writable: true}
  2570. );
  2571. this.transceivers[sdpMLineIndex].bufferedCandidateEvents = [];
  2572. this.transceivers[sdpMLineIndex].bufferCandidates = function(event) {
  2573. var end = !event.candidate || Object.keys(event.candidate).length === 0;
  2574. // polyfill since RTCIceGatherer.state is not implemented in
  2575. // Edge 10547 yet.
  2576. iceGatherer.state = end ? 'completed' : 'gathering';
  2577. if (pc.transceivers[sdpMLineIndex].bufferedCandidateEvents !== null) {
  2578. pc.transceivers[sdpMLineIndex].bufferedCandidateEvents.push(event);
  2579. }
  2580. };
  2581. iceGatherer.addEventListener('localcandidate',
  2582. this.transceivers[sdpMLineIndex].bufferCandidates);
  2583. return iceGatherer;
  2584. };
  2585. // start gathering from an RTCIceGatherer.
  2586. RTCPeerConnection.prototype._gather = function(mid, sdpMLineIndex) {
  2587. var pc = this;
  2588. var iceGatherer = this.transceivers[sdpMLineIndex].iceGatherer;
  2589. if (iceGatherer.onlocalcandidate) {
  2590. return;
  2591. }
  2592. var bufferedCandidateEvents =
  2593. this.transceivers[sdpMLineIndex].bufferedCandidateEvents;
  2594. this.transceivers[sdpMLineIndex].bufferedCandidateEvents = null;
  2595. iceGatherer.removeEventListener('localcandidate',
  2596. this.transceivers[sdpMLineIndex].bufferCandidates);
  2597. iceGatherer.onlocalcandidate = function(evt) {
  2598. if (pc.usingBundle && sdpMLineIndex > 0) {
  2599. // if we know that we use bundle we can drop candidates with
  2600. // ѕdpMLineIndex > 0. If we don't do this then our state gets
  2601. // confused since we dispose the extra ice gatherer.
  2602. return;
  2603. }
  2604. var event = new Event('icecandidate');
  2605. event.candidate = {sdpMid: mid, sdpMLineIndex: sdpMLineIndex};
  2606. var cand = evt.candidate;
  2607. // Edge emits an empty object for RTCIceCandidateComplete‥
  2608. var end = !cand || Object.keys(cand).length === 0;
  2609. if (end) {
  2610. // polyfill since RTCIceGatherer.state is not implemented in
  2611. // Edge 10547 yet.
  2612. if (iceGatherer.state === 'new' || iceGatherer.state === 'gathering') {
  2613. iceGatherer.state = 'completed';
  2614. }
  2615. } else {
  2616. if (iceGatherer.state === 'new') {
  2617. iceGatherer.state = 'gathering';
  2618. }
  2619. // RTCIceCandidate doesn't have a component, needs to be added
  2620. cand.component = 1;
  2621. // also the usernameFragment. TODO: update SDP to take both variants.
  2622. cand.ufrag = iceGatherer.getLocalParameters().usernameFragment;
  2623. var serializedCandidate = sdp.writeCandidate(cand);
  2624. event.candidate = Object.assign(event.candidate,
  2625. sdp.parseCandidate(serializedCandidate));
  2626. event.candidate.candidate = serializedCandidate;
  2627. event.candidate.toJSON = function() {
  2628. return {
  2629. candidate: event.candidate.candidate,
  2630. sdpMid: event.candidate.sdpMid,
  2631. sdpMLineIndex: event.candidate.sdpMLineIndex,
  2632. usernameFragment: event.candidate.usernameFragment
  2633. };
  2634. };
  2635. }
  2636. // update local description.
  2637. var sections = sdp.getMediaSections(pc._localDescription.sdp);
  2638. if (!end) {
  2639. sections[event.candidate.sdpMLineIndex] +=
  2640. 'a=' + event.candidate.candidate + '\r\n';
  2641. } else {
  2642. sections[event.candidate.sdpMLineIndex] +=
  2643. 'a=end-of-candidates\r\n';
  2644. }
  2645. pc._localDescription.sdp =
  2646. sdp.getDescription(pc._localDescription.sdp) +
  2647. sections.join('');
  2648. var complete = pc.transceivers.every(function(transceiver) {
  2649. return transceiver.iceGatherer &&
  2650. transceiver.iceGatherer.state === 'completed';
  2651. });
  2652. if (pc.iceGatheringState !== 'gathering') {
  2653. pc.iceGatheringState = 'gathering';
  2654. pc._emitGatheringStateChange();
  2655. }
  2656. // Emit candidate. Also emit null candidate when all gatherers are
  2657. // complete.
  2658. if (!end) {
  2659. pc._dispatchEvent('icecandidate', event);
  2660. }
  2661. if (complete) {
  2662. pc._dispatchEvent('icecandidate', new Event('icecandidate'));
  2663. pc.iceGatheringState = 'complete';
  2664. pc._emitGatheringStateChange();
  2665. }
  2666. };
  2667. // emit already gathered candidates.
  2668. window.setTimeout(function() {
  2669. bufferedCandidateEvents.forEach(function(e) {
  2670. iceGatherer.onlocalcandidate(e);
  2671. });
  2672. }, 0);
  2673. };
  2674. // Create ICE transport and DTLS transport.
  2675. RTCPeerConnection.prototype._createIceAndDtlsTransports = function() {
  2676. var pc = this;
  2677. var iceTransport = new window.RTCIceTransport(null);
  2678. iceTransport.onicestatechange = function() {
  2679. pc._updateIceConnectionState();
  2680. pc._updateConnectionState();
  2681. };
  2682. var dtlsTransport = new window.RTCDtlsTransport(iceTransport);
  2683. dtlsTransport.ondtlsstatechange = function() {
  2684. pc._updateConnectionState();
  2685. };
  2686. dtlsTransport.onerror = function() {
  2687. // onerror does not set state to failed by itself.
  2688. Object.defineProperty(dtlsTransport, 'state',
  2689. {value: 'failed', writable: true});
  2690. pc._updateConnectionState();
  2691. };
  2692. return {
  2693. iceTransport: iceTransport,
  2694. dtlsTransport: dtlsTransport
  2695. };
  2696. };
  2697. // Destroy ICE gatherer, ICE transport and DTLS transport.
  2698. // Without triggering the callbacks.
  2699. RTCPeerConnection.prototype._disposeIceAndDtlsTransports = function(
  2700. sdpMLineIndex) {
  2701. var iceGatherer = this.transceivers[sdpMLineIndex].iceGatherer;
  2702. if (iceGatherer) {
  2703. delete iceGatherer.onlocalcandidate;
  2704. delete this.transceivers[sdpMLineIndex].iceGatherer;
  2705. }
  2706. var iceTransport = this.transceivers[sdpMLineIndex].iceTransport;
  2707. if (iceTransport) {
  2708. delete iceTransport.onicestatechange;
  2709. delete this.transceivers[sdpMLineIndex].iceTransport;
  2710. }
  2711. var dtlsTransport = this.transceivers[sdpMLineIndex].dtlsTransport;
  2712. if (dtlsTransport) {
  2713. delete dtlsTransport.ondtlsstatechange;
  2714. delete dtlsTransport.onerror;
  2715. delete this.transceivers[sdpMLineIndex].dtlsTransport;
  2716. }
  2717. };
  2718. // Start the RTP Sender and Receiver for a transceiver.
  2719. RTCPeerConnection.prototype._transceive = function(transceiver,
  2720. send, recv) {
  2721. var params = getCommonCapabilities(transceiver.localCapabilities,
  2722. transceiver.remoteCapabilities);
  2723. if (send && transceiver.rtpSender) {
  2724. params.encodings = transceiver.sendEncodingParameters;
  2725. params.rtcp = {
  2726. cname: sdp.localCName,
  2727. compound: transceiver.rtcpParameters.compound
  2728. };
  2729. if (transceiver.recvEncodingParameters.length) {
  2730. params.rtcp.ssrc = transceiver.recvEncodingParameters[0].ssrc;
  2731. }
  2732. transceiver.rtpSender.send(params);
  2733. }
  2734. if (recv && transceiver.rtpReceiver && params.codecs.length > 0) {
  2735. // remove RTX field in Edge 14942
  2736. if (transceiver.kind === 'video'
  2737. && transceiver.recvEncodingParameters
  2738. && edgeVersion < 15019) {
  2739. transceiver.recvEncodingParameters.forEach(function(p) {
  2740. delete p.rtx;
  2741. });
  2742. }
  2743. if (transceiver.recvEncodingParameters.length) {
  2744. params.encodings = transceiver.recvEncodingParameters;
  2745. } else {
  2746. params.encodings = [{}];
  2747. }
  2748. params.rtcp = {
  2749. compound: transceiver.rtcpParameters.compound
  2750. };
  2751. if (transceiver.rtcpParameters.cname) {
  2752. params.rtcp.cname = transceiver.rtcpParameters.cname;
  2753. }
  2754. if (transceiver.sendEncodingParameters.length) {
  2755. params.rtcp.ssrc = transceiver.sendEncodingParameters[0].ssrc;
  2756. }
  2757. transceiver.rtpReceiver.receive(params);
  2758. }
  2759. };
  2760. RTCPeerConnection.prototype.setLocalDescription = function(description) {
  2761. var pc = this;
  2762. // Note: pranswer is not supported.
  2763. if (['offer', 'answer'].indexOf(description.type) === -1) {
  2764. return Promise.reject(makeError('TypeError',
  2765. 'Unsupported type "' + description.type + '"'));
  2766. }
  2767. if (!isActionAllowedInSignalingState('setLocalDescription',
  2768. description.type, pc.signalingState) || pc._isClosed) {
  2769. return Promise.reject(makeError('InvalidStateError',
  2770. 'Can not set local ' + description.type +
  2771. ' in state ' + pc.signalingState));
  2772. }
  2773. var sections;
  2774. var sessionpart;
  2775. if (description.type === 'offer') {
  2776. // VERY limited support for SDP munging. Limited to:
  2777. // * changing the order of codecs
  2778. sections = sdp.splitSections(description.sdp);
  2779. sessionpart = sections.shift();
  2780. sections.forEach(function(mediaSection, sdpMLineIndex) {
  2781. var caps = sdp.parseRtpParameters(mediaSection);
  2782. pc.transceivers[sdpMLineIndex].localCapabilities = caps;
  2783. });
  2784. pc.transceivers.forEach(function(transceiver, sdpMLineIndex) {
  2785. pc._gather(transceiver.mid, sdpMLineIndex);
  2786. });
  2787. } else if (description.type === 'answer') {
  2788. sections = sdp.splitSections(pc._remoteDescription.sdp);
  2789. sessionpart = sections.shift();
  2790. var isIceLite = sdp.matchPrefix(sessionpart,
  2791. 'a=ice-lite').length > 0;
  2792. sections.forEach(function(mediaSection, sdpMLineIndex) {
  2793. var transceiver = pc.transceivers[sdpMLineIndex];
  2794. var iceGatherer = transceiver.iceGatherer;
  2795. var iceTransport = transceiver.iceTransport;
  2796. var dtlsTransport = transceiver.dtlsTransport;
  2797. var localCapabilities = transceiver.localCapabilities;
  2798. var remoteCapabilities = transceiver.remoteCapabilities;
  2799. // treat bundle-only as not-rejected.
  2800. var rejected = sdp.isRejected(mediaSection) &&
  2801. sdp.matchPrefix(mediaSection, 'a=bundle-only').length === 0;
  2802. if (!rejected && !transceiver.rejected) {
  2803. var remoteIceParameters = sdp.getIceParameters(
  2804. mediaSection, sessionpart);
  2805. var remoteDtlsParameters = sdp.getDtlsParameters(
  2806. mediaSection, sessionpart);
  2807. if (isIceLite) {
  2808. remoteDtlsParameters.role = 'server';
  2809. }
  2810. if (!pc.usingBundle || sdpMLineIndex === 0) {
  2811. pc._gather(transceiver.mid, sdpMLineIndex);
  2812. if (iceTransport.state === 'new') {
  2813. iceTransport.start(iceGatherer, remoteIceParameters,
  2814. isIceLite ? 'controlling' : 'controlled');
  2815. }
  2816. if (dtlsTransport.state === 'new') {
  2817. dtlsTransport.start(remoteDtlsParameters);
  2818. }
  2819. }
  2820. // Calculate intersection of capabilities.
  2821. var params = getCommonCapabilities(localCapabilities,
  2822. remoteCapabilities);
  2823. // Start the RTCRtpSender. The RTCRtpReceiver for this
  2824. // transceiver has already been started in setRemoteDescription.
  2825. pc._transceive(transceiver,
  2826. params.codecs.length > 0,
  2827. false);
  2828. }
  2829. });
  2830. }
  2831. pc._localDescription = {
  2832. type: description.type,
  2833. sdp: description.sdp
  2834. };
  2835. if (description.type === 'offer') {
  2836. pc._updateSignalingState('have-local-offer');
  2837. } else {
  2838. pc._updateSignalingState('stable');
  2839. }
  2840. return Promise.resolve();
  2841. };
  2842. RTCPeerConnection.prototype.setRemoteDescription = function(description) {
  2843. var pc = this;
  2844. // Note: pranswer is not supported.
  2845. if (['offer', 'answer'].indexOf(description.type) === -1) {
  2846. return Promise.reject(makeError('TypeError',
  2847. 'Unsupported type "' + description.type + '"'));
  2848. }
  2849. if (!isActionAllowedInSignalingState('setRemoteDescription',
  2850. description.type, pc.signalingState) || pc._isClosed) {
  2851. return Promise.reject(makeError('InvalidStateError',
  2852. 'Can not set remote ' + description.type +
  2853. ' in state ' + pc.signalingState));
  2854. }
  2855. var streams = {};
  2856. pc.remoteStreams.forEach(function(stream) {
  2857. streams[stream.id] = stream;
  2858. });
  2859. var receiverList = [];
  2860. var sections = sdp.splitSections(description.sdp);
  2861. var sessionpart = sections.shift();
  2862. var isIceLite = sdp.matchPrefix(sessionpart,
  2863. 'a=ice-lite').length > 0;
  2864. var usingBundle = sdp.matchPrefix(sessionpart,
  2865. 'a=group:BUNDLE ').length > 0;
  2866. pc.usingBundle = usingBundle;
  2867. var iceOptions = sdp.matchPrefix(sessionpart,
  2868. 'a=ice-options:')[0];
  2869. if (iceOptions) {
  2870. pc.canTrickleIceCandidates = iceOptions.substr(14).split(' ')
  2871. .indexOf('trickle') >= 0;
  2872. } else {
  2873. pc.canTrickleIceCandidates = false;
  2874. }
  2875. sections.forEach(function(mediaSection, sdpMLineIndex) {
  2876. var lines = sdp.splitLines(mediaSection);
  2877. var kind = sdp.getKind(mediaSection);
  2878. // treat bundle-only as not-rejected.
  2879. var rejected = sdp.isRejected(mediaSection) &&
  2880. sdp.matchPrefix(mediaSection, 'a=bundle-only').length === 0;
  2881. var protocol = lines[0].substr(2).split(' ')[2];
  2882. var direction = sdp.getDirection(mediaSection, sessionpart);
  2883. var remoteMsid = sdp.parseMsid(mediaSection);
  2884. var mid = sdp.getMid(mediaSection) || sdp.generateIdentifier();
  2885. // Reject datachannels which are not implemented yet.
  2886. if (rejected || (kind === 'application' && (protocol === 'DTLS/SCTP' ||
  2887. protocol === 'UDP/DTLS/SCTP'))) {
  2888. // TODO: this is dangerous in the case where a non-rejected m-line
  2889. // becomes rejected.
  2890. pc.transceivers[sdpMLineIndex] = {
  2891. mid: mid,
  2892. kind: kind,
  2893. protocol: protocol,
  2894. rejected: true
  2895. };
  2896. return;
  2897. }
  2898. if (!rejected && pc.transceivers[sdpMLineIndex] &&
  2899. pc.transceivers[sdpMLineIndex].rejected) {
  2900. // recycle a rejected transceiver.
  2901. pc.transceivers[sdpMLineIndex] = pc._createTransceiver(kind, true);
  2902. }
  2903. var transceiver;
  2904. var iceGatherer;
  2905. var iceTransport;
  2906. var dtlsTransport;
  2907. var rtpReceiver;
  2908. var sendEncodingParameters;
  2909. var recvEncodingParameters;
  2910. var localCapabilities;
  2911. var track;
  2912. // FIXME: ensure the mediaSection has rtcp-mux set.
  2913. var remoteCapabilities = sdp.parseRtpParameters(mediaSection);
  2914. var remoteIceParameters;
  2915. var remoteDtlsParameters;
  2916. if (!rejected) {
  2917. remoteIceParameters = sdp.getIceParameters(mediaSection,
  2918. sessionpart);
  2919. remoteDtlsParameters = sdp.getDtlsParameters(mediaSection,
  2920. sessionpart);
  2921. remoteDtlsParameters.role = 'client';
  2922. }
  2923. recvEncodingParameters =
  2924. sdp.parseRtpEncodingParameters(mediaSection);
  2925. var rtcpParameters = sdp.parseRtcpParameters(mediaSection);
  2926. var isComplete = sdp.matchPrefix(mediaSection,
  2927. 'a=end-of-candidates', sessionpart).length > 0;
  2928. var cands = sdp.matchPrefix(mediaSection, 'a=candidate:')
  2929. .map(function(cand) {
  2930. return sdp.parseCandidate(cand);
  2931. })
  2932. .filter(function(cand) {
  2933. return cand.component === 1;
  2934. });
  2935. // Check if we can use BUNDLE and dispose transports.
  2936. if ((description.type === 'offer' || description.type === 'answer') &&
  2937. !rejected && usingBundle && sdpMLineIndex > 0 &&
  2938. pc.transceivers[sdpMLineIndex]) {
  2939. pc._disposeIceAndDtlsTransports(sdpMLineIndex);
  2940. pc.transceivers[sdpMLineIndex].iceGatherer =
  2941. pc.transceivers[0].iceGatherer;
  2942. pc.transceivers[sdpMLineIndex].iceTransport =
  2943. pc.transceivers[0].iceTransport;
  2944. pc.transceivers[sdpMLineIndex].dtlsTransport =
  2945. pc.transceivers[0].dtlsTransport;
  2946. if (pc.transceivers[sdpMLineIndex].rtpSender) {
  2947. pc.transceivers[sdpMLineIndex].rtpSender.setTransport(
  2948. pc.transceivers[0].dtlsTransport);
  2949. }
  2950. if (pc.transceivers[sdpMLineIndex].rtpReceiver) {
  2951. pc.transceivers[sdpMLineIndex].rtpReceiver.setTransport(
  2952. pc.transceivers[0].dtlsTransport);
  2953. }
  2954. }
  2955. if (description.type === 'offer' && !rejected) {
  2956. transceiver = pc.transceivers[sdpMLineIndex] ||
  2957. pc._createTransceiver(kind);
  2958. transceiver.mid = mid;
  2959. if (!transceiver.iceGatherer) {
  2960. transceiver.iceGatherer = pc._createIceGatherer(sdpMLineIndex,
  2961. usingBundle);
  2962. }
  2963. if (cands.length && transceiver.iceTransport.state === 'new') {
  2964. if (isComplete && (!usingBundle || sdpMLineIndex === 0)) {
  2965. transceiver.iceTransport.setRemoteCandidates(cands);
  2966. } else {
  2967. cands.forEach(function(candidate) {
  2968. maybeAddCandidate(transceiver.iceTransport, candidate);
  2969. });
  2970. }
  2971. }
  2972. localCapabilities = window.RTCRtpReceiver.getCapabilities(kind);
  2973. // filter RTX until additional stuff needed for RTX is implemented
  2974. // in adapter.js
  2975. if (edgeVersion < 15019) {
  2976. localCapabilities.codecs = localCapabilities.codecs.filter(
  2977. function(codec) {
  2978. return codec.name !== 'rtx';
  2979. });
  2980. }
  2981. sendEncodingParameters = transceiver.sendEncodingParameters || [{
  2982. ssrc: (2 * sdpMLineIndex + 2) * 1001
  2983. }];
  2984. // TODO: rewrite to use http://w3c.github.io/webrtc-pc/#set-associated-remote-streams
  2985. var isNewTrack = false;
  2986. if (direction === 'sendrecv' || direction === 'sendonly') {
  2987. isNewTrack = !transceiver.rtpReceiver;
  2988. rtpReceiver = transceiver.rtpReceiver ||
  2989. new window.RTCRtpReceiver(transceiver.dtlsTransport, kind);
  2990. if (isNewTrack) {
  2991. var stream;
  2992. track = rtpReceiver.track;
  2993. // FIXME: does not work with Plan B.
  2994. if (remoteMsid && remoteMsid.stream === '-') ; else if (remoteMsid) {
  2995. if (!streams[remoteMsid.stream]) {
  2996. streams[remoteMsid.stream] = new window.MediaStream();
  2997. Object.defineProperty(streams[remoteMsid.stream], 'id', {
  2998. get: function() {
  2999. return remoteMsid.stream;
  3000. }
  3001. });
  3002. }
  3003. Object.defineProperty(track, 'id', {
  3004. get: function() {
  3005. return remoteMsid.track;
  3006. }
  3007. });
  3008. stream = streams[remoteMsid.stream];
  3009. } else {
  3010. if (!streams.default) {
  3011. streams.default = new window.MediaStream();
  3012. }
  3013. stream = streams.default;
  3014. }
  3015. if (stream) {
  3016. addTrackToStreamAndFireEvent(track, stream);
  3017. transceiver.associatedRemoteMediaStreams.push(stream);
  3018. }
  3019. receiverList.push([track, rtpReceiver, stream]);
  3020. }
  3021. } else if (transceiver.rtpReceiver && transceiver.rtpReceiver.track) {
  3022. transceiver.associatedRemoteMediaStreams.forEach(function(s) {
  3023. var nativeTrack = s.getTracks().find(function(t) {
  3024. return t.id === transceiver.rtpReceiver.track.id;
  3025. });
  3026. if (nativeTrack) {
  3027. removeTrackFromStreamAndFireEvent(nativeTrack, s);
  3028. }
  3029. });
  3030. transceiver.associatedRemoteMediaStreams = [];
  3031. }
  3032. transceiver.localCapabilities = localCapabilities;
  3033. transceiver.remoteCapabilities = remoteCapabilities;
  3034. transceiver.rtpReceiver = rtpReceiver;
  3035. transceiver.rtcpParameters = rtcpParameters;
  3036. transceiver.sendEncodingParameters = sendEncodingParameters;
  3037. transceiver.recvEncodingParameters = recvEncodingParameters;
  3038. // Start the RTCRtpReceiver now. The RTPSender is started in
  3039. // setLocalDescription.
  3040. pc._transceive(pc.transceivers[sdpMLineIndex],
  3041. false,
  3042. isNewTrack);
  3043. } else if (description.type === 'answer' && !rejected) {
  3044. transceiver = pc.transceivers[sdpMLineIndex];
  3045. iceGatherer = transceiver.iceGatherer;
  3046. iceTransport = transceiver.iceTransport;
  3047. dtlsTransport = transceiver.dtlsTransport;
  3048. rtpReceiver = transceiver.rtpReceiver;
  3049. sendEncodingParameters = transceiver.sendEncodingParameters;
  3050. localCapabilities = transceiver.localCapabilities;
  3051. pc.transceivers[sdpMLineIndex].recvEncodingParameters =
  3052. recvEncodingParameters;
  3053. pc.transceivers[sdpMLineIndex].remoteCapabilities =
  3054. remoteCapabilities;
  3055. pc.transceivers[sdpMLineIndex].rtcpParameters = rtcpParameters;
  3056. if (cands.length && iceTransport.state === 'new') {
  3057. if ((isIceLite || isComplete) &&
  3058. (!usingBundle || sdpMLineIndex === 0)) {
  3059. iceTransport.setRemoteCandidates(cands);
  3060. } else {
  3061. cands.forEach(function(candidate) {
  3062. maybeAddCandidate(transceiver.iceTransport, candidate);
  3063. });
  3064. }
  3065. }
  3066. if (!usingBundle || sdpMLineIndex === 0) {
  3067. if (iceTransport.state === 'new') {
  3068. iceTransport.start(iceGatherer, remoteIceParameters,
  3069. 'controlling');
  3070. }
  3071. if (dtlsTransport.state === 'new') {
  3072. dtlsTransport.start(remoteDtlsParameters);
  3073. }
  3074. }
  3075. // If the offer contained RTX but the answer did not,
  3076. // remove RTX from sendEncodingParameters.
  3077. var commonCapabilities = getCommonCapabilities(
  3078. transceiver.localCapabilities,
  3079. transceiver.remoteCapabilities);
  3080. var hasRtx = commonCapabilities.codecs.filter(function(c) {
  3081. return c.name.toLowerCase() === 'rtx';
  3082. }).length;
  3083. if (!hasRtx && transceiver.sendEncodingParameters[0].rtx) {
  3084. delete transceiver.sendEncodingParameters[0].rtx;
  3085. }
  3086. pc._transceive(transceiver,
  3087. direction === 'sendrecv' || direction === 'recvonly',
  3088. direction === 'sendrecv' || direction === 'sendonly');
  3089. // TODO: rewrite to use http://w3c.github.io/webrtc-pc/#set-associated-remote-streams
  3090. if (rtpReceiver &&
  3091. (direction === 'sendrecv' || direction === 'sendonly')) {
  3092. track = rtpReceiver.track;
  3093. if (remoteMsid) {
  3094. if (!streams[remoteMsid.stream]) {
  3095. streams[remoteMsid.stream] = new window.MediaStream();
  3096. }
  3097. addTrackToStreamAndFireEvent(track, streams[remoteMsid.stream]);
  3098. receiverList.push([track, rtpReceiver, streams[remoteMsid.stream]]);
  3099. } else {
  3100. if (!streams.default) {
  3101. streams.default = new window.MediaStream();
  3102. }
  3103. addTrackToStreamAndFireEvent(track, streams.default);
  3104. receiverList.push([track, rtpReceiver, streams.default]);
  3105. }
  3106. } else {
  3107. // FIXME: actually the receiver should be created later.
  3108. delete transceiver.rtpReceiver;
  3109. }
  3110. }
  3111. });
  3112. if (pc._dtlsRole === undefined) {
  3113. pc._dtlsRole = description.type === 'offer' ? 'active' : 'passive';
  3114. }
  3115. pc._remoteDescription = {
  3116. type: description.type,
  3117. sdp: description.sdp
  3118. };
  3119. if (description.type === 'offer') {
  3120. pc._updateSignalingState('have-remote-offer');
  3121. } else {
  3122. pc._updateSignalingState('stable');
  3123. }
  3124. Object.keys(streams).forEach(function(sid) {
  3125. var stream = streams[sid];
  3126. if (stream.getTracks().length) {
  3127. if (pc.remoteStreams.indexOf(stream) === -1) {
  3128. pc.remoteStreams.push(stream);
  3129. var event = new Event('addstream');
  3130. event.stream = stream;
  3131. window.setTimeout(function() {
  3132. pc._dispatchEvent('addstream', event);
  3133. });
  3134. }
  3135. receiverList.forEach(function(item) {
  3136. var track = item[0];
  3137. var receiver = item[1];
  3138. if (stream.id !== item[2].id) {
  3139. return;
  3140. }
  3141. fireAddTrack(pc, track, receiver, [stream]);
  3142. });
  3143. }
  3144. });
  3145. receiverList.forEach(function(item) {
  3146. if (item[2]) {
  3147. return;
  3148. }
  3149. fireAddTrack(pc, item[0], item[1], []);
  3150. });
  3151. // check whether addIceCandidate({}) was called within four seconds after
  3152. // setRemoteDescription.
  3153. window.setTimeout(function() {
  3154. if (!(pc && pc.transceivers)) {
  3155. return;
  3156. }
  3157. pc.transceivers.forEach(function(transceiver) {
  3158. if (transceiver.iceTransport &&
  3159. transceiver.iceTransport.state === 'new' &&
  3160. transceiver.iceTransport.getRemoteCandidates().length > 0) {
  3161. console.warn('Timeout for addRemoteCandidate. Consider sending ' +
  3162. 'an end-of-candidates notification');
  3163. transceiver.iceTransport.addRemoteCandidate({});
  3164. }
  3165. });
  3166. }, 4000);
  3167. return Promise.resolve();
  3168. };
  3169. RTCPeerConnection.prototype.close = function() {
  3170. this.transceivers.forEach(function(transceiver) {
  3171. /* not yet
  3172. if (transceiver.iceGatherer) {
  3173. transceiver.iceGatherer.close();
  3174. }
  3175. */
  3176. if (transceiver.iceTransport) {
  3177. transceiver.iceTransport.stop();
  3178. }
  3179. if (transceiver.dtlsTransport) {
  3180. transceiver.dtlsTransport.stop();
  3181. }
  3182. if (transceiver.rtpSender) {
  3183. transceiver.rtpSender.stop();
  3184. }
  3185. if (transceiver.rtpReceiver) {
  3186. transceiver.rtpReceiver.stop();
  3187. }
  3188. });
  3189. // FIXME: clean up tracks, local streams, remote streams, etc
  3190. this._isClosed = true;
  3191. this._updateSignalingState('closed');
  3192. };
  3193. // Update the signaling state.
  3194. RTCPeerConnection.prototype._updateSignalingState = function(newState) {
  3195. this.signalingState = newState;
  3196. var event = new Event('signalingstatechange');
  3197. this._dispatchEvent('signalingstatechange', event);
  3198. };
  3199. // Determine whether to fire the negotiationneeded event.
  3200. RTCPeerConnection.prototype._maybeFireNegotiationNeeded = function() {
  3201. var pc = this;
  3202. if (this.signalingState !== 'stable' || this.needNegotiation === true) {
  3203. return;
  3204. }
  3205. this.needNegotiation = true;
  3206. window.setTimeout(function() {
  3207. if (pc.needNegotiation) {
  3208. pc.needNegotiation = false;
  3209. var event = new Event('negotiationneeded');
  3210. pc._dispatchEvent('negotiationneeded', event);
  3211. }
  3212. }, 0);
  3213. };
  3214. // Update the ice connection state.
  3215. RTCPeerConnection.prototype._updateIceConnectionState = function() {
  3216. var newState;
  3217. var states = {
  3218. 'new': 0,
  3219. closed: 0,
  3220. checking: 0,
  3221. connected: 0,
  3222. completed: 0,
  3223. disconnected: 0,
  3224. failed: 0
  3225. };
  3226. this.transceivers.forEach(function(transceiver) {
  3227. if (transceiver.iceTransport && !transceiver.rejected) {
  3228. states[transceiver.iceTransport.state]++;
  3229. }
  3230. });
  3231. newState = 'new';
  3232. if (states.failed > 0) {
  3233. newState = 'failed';
  3234. } else if (states.checking > 0) {
  3235. newState = 'checking';
  3236. } else if (states.disconnected > 0) {
  3237. newState = 'disconnected';
  3238. } else if (states.new > 0) {
  3239. newState = 'new';
  3240. } else if (states.connected > 0) {
  3241. newState = 'connected';
  3242. } else if (states.completed > 0) {
  3243. newState = 'completed';
  3244. }
  3245. if (newState !== this.iceConnectionState) {
  3246. this.iceConnectionState = newState;
  3247. var event = new Event('iceconnectionstatechange');
  3248. this._dispatchEvent('iceconnectionstatechange', event);
  3249. }
  3250. };
  3251. // Update the connection state.
  3252. RTCPeerConnection.prototype._updateConnectionState = function() {
  3253. var newState;
  3254. var states = {
  3255. 'new': 0,
  3256. closed: 0,
  3257. connecting: 0,
  3258. connected: 0,
  3259. completed: 0,
  3260. disconnected: 0,
  3261. failed: 0
  3262. };
  3263. this.transceivers.forEach(function(transceiver) {
  3264. if (transceiver.iceTransport && transceiver.dtlsTransport &&
  3265. !transceiver.rejected) {
  3266. states[transceiver.iceTransport.state]++;
  3267. states[transceiver.dtlsTransport.state]++;
  3268. }
  3269. });
  3270. // ICETransport.completed and connected are the same for this purpose.
  3271. states.connected += states.completed;
  3272. newState = 'new';
  3273. if (states.failed > 0) {
  3274. newState = 'failed';
  3275. } else if (states.connecting > 0) {
  3276. newState = 'connecting';
  3277. } else if (states.disconnected > 0) {
  3278. newState = 'disconnected';
  3279. } else if (states.new > 0) {
  3280. newState = 'new';
  3281. } else if (states.connected > 0) {
  3282. newState = 'connected';
  3283. }
  3284. if (newState !== this.connectionState) {
  3285. this.connectionState = newState;
  3286. var event = new Event('connectionstatechange');
  3287. this._dispatchEvent('connectionstatechange', event);
  3288. }
  3289. };
  3290. RTCPeerConnection.prototype.createOffer = function() {
  3291. var pc = this;
  3292. if (pc._isClosed) {
  3293. return Promise.reject(makeError('InvalidStateError',
  3294. 'Can not call createOffer after close'));
  3295. }
  3296. var numAudioTracks = pc.transceivers.filter(function(t) {
  3297. return t.kind === 'audio';
  3298. }).length;
  3299. var numVideoTracks = pc.transceivers.filter(function(t) {
  3300. return t.kind === 'video';
  3301. }).length;
  3302. // Determine number of audio and video tracks we need to send/recv.
  3303. var offerOptions = arguments[0];
  3304. if (offerOptions) {
  3305. // Reject Chrome legacy constraints.
  3306. if (offerOptions.mandatory || offerOptions.optional) {
  3307. throw new TypeError(
  3308. 'Legacy mandatory/optional constraints not supported.');
  3309. }
  3310. if (offerOptions.offerToReceiveAudio !== undefined) {
  3311. if (offerOptions.offerToReceiveAudio === true) {
  3312. numAudioTracks = 1;
  3313. } else if (offerOptions.offerToReceiveAudio === false) {
  3314. numAudioTracks = 0;
  3315. } else {
  3316. numAudioTracks = offerOptions.offerToReceiveAudio;
  3317. }
  3318. }
  3319. if (offerOptions.offerToReceiveVideo !== undefined) {
  3320. if (offerOptions.offerToReceiveVideo === true) {
  3321. numVideoTracks = 1;
  3322. } else if (offerOptions.offerToReceiveVideo === false) {
  3323. numVideoTracks = 0;
  3324. } else {
  3325. numVideoTracks = offerOptions.offerToReceiveVideo;
  3326. }
  3327. }
  3328. }
  3329. pc.transceivers.forEach(function(transceiver) {
  3330. if (transceiver.kind === 'audio') {
  3331. numAudioTracks--;
  3332. if (numAudioTracks < 0) {
  3333. transceiver.wantReceive = false;
  3334. }
  3335. } else if (transceiver.kind === 'video') {
  3336. numVideoTracks--;
  3337. if (numVideoTracks < 0) {
  3338. transceiver.wantReceive = false;
  3339. }
  3340. }
  3341. });
  3342. // Create M-lines for recvonly streams.
  3343. while (numAudioTracks > 0 || numVideoTracks > 0) {
  3344. if (numAudioTracks > 0) {
  3345. pc._createTransceiver('audio');
  3346. numAudioTracks--;
  3347. }
  3348. if (numVideoTracks > 0) {
  3349. pc._createTransceiver('video');
  3350. numVideoTracks--;
  3351. }
  3352. }
  3353. var sdp$1 = sdp.writeSessionBoilerplate(pc._sdpSessionId,
  3354. pc._sdpSessionVersion++);
  3355. pc.transceivers.forEach(function(transceiver, sdpMLineIndex) {
  3356. // For each track, create an ice gatherer, ice transport,
  3357. // dtls transport, potentially rtpsender and rtpreceiver.
  3358. var track = transceiver.track;
  3359. var kind = transceiver.kind;
  3360. var mid = transceiver.mid || sdp.generateIdentifier();
  3361. transceiver.mid = mid;
  3362. if (!transceiver.iceGatherer) {
  3363. transceiver.iceGatherer = pc._createIceGatherer(sdpMLineIndex,
  3364. pc.usingBundle);
  3365. }
  3366. var localCapabilities = window.RTCRtpSender.getCapabilities(kind);
  3367. // filter RTX until additional stuff needed for RTX is implemented
  3368. // in adapter.js
  3369. if (edgeVersion < 15019) {
  3370. localCapabilities.codecs = localCapabilities.codecs.filter(
  3371. function(codec) {
  3372. return codec.name !== 'rtx';
  3373. });
  3374. }
  3375. localCapabilities.codecs.forEach(function(codec) {
  3376. // work around https://bugs.chromium.org/p/webrtc/issues/detail?id=6552
  3377. // by adding level-asymmetry-allowed=1
  3378. if (codec.name === 'H264' &&
  3379. codec.parameters['level-asymmetry-allowed'] === undefined) {
  3380. codec.parameters['level-asymmetry-allowed'] = '1';
  3381. }
  3382. // for subsequent offers, we might have to re-use the payload
  3383. // type of the last offer.
  3384. if (transceiver.remoteCapabilities &&
  3385. transceiver.remoteCapabilities.codecs) {
  3386. transceiver.remoteCapabilities.codecs.forEach(function(remoteCodec) {
  3387. if (codec.name.toLowerCase() === remoteCodec.name.toLowerCase() &&
  3388. codec.clockRate === remoteCodec.clockRate) {
  3389. codec.preferredPayloadType = remoteCodec.payloadType;
  3390. }
  3391. });
  3392. }
  3393. });
  3394. localCapabilities.headerExtensions.forEach(function(hdrExt) {
  3395. var remoteExtensions = transceiver.remoteCapabilities &&
  3396. transceiver.remoteCapabilities.headerExtensions || [];
  3397. remoteExtensions.forEach(function(rHdrExt) {
  3398. if (hdrExt.uri === rHdrExt.uri) {
  3399. hdrExt.id = rHdrExt.id;
  3400. }
  3401. });
  3402. });
  3403. // generate an ssrc now, to be used later in rtpSender.send
  3404. var sendEncodingParameters = transceiver.sendEncodingParameters || [{
  3405. ssrc: (2 * sdpMLineIndex + 1) * 1001
  3406. }];
  3407. if (track) {
  3408. // add RTX
  3409. if (edgeVersion >= 15019 && kind === 'video' &&
  3410. !sendEncodingParameters[0].rtx) {
  3411. sendEncodingParameters[0].rtx = {
  3412. ssrc: sendEncodingParameters[0].ssrc + 1
  3413. };
  3414. }
  3415. }
  3416. if (transceiver.wantReceive) {
  3417. transceiver.rtpReceiver = new window.RTCRtpReceiver(
  3418. transceiver.dtlsTransport, kind);
  3419. }
  3420. transceiver.localCapabilities = localCapabilities;
  3421. transceiver.sendEncodingParameters = sendEncodingParameters;
  3422. });
  3423. // always offer BUNDLE and dispose on return if not supported.
  3424. if (pc._config.bundlePolicy !== 'max-compat') {
  3425. sdp$1 += 'a=group:BUNDLE ' + pc.transceivers.map(function(t) {
  3426. return t.mid;
  3427. }).join(' ') + '\r\n';
  3428. }
  3429. sdp$1 += 'a=ice-options:trickle\r\n';
  3430. pc.transceivers.forEach(function(transceiver, sdpMLineIndex) {
  3431. sdp$1 += writeMediaSection(transceiver, transceiver.localCapabilities,
  3432. 'offer', transceiver.stream, pc._dtlsRole);
  3433. sdp$1 += 'a=rtcp-rsize\r\n';
  3434. if (transceiver.iceGatherer && pc.iceGatheringState !== 'new' &&
  3435. (sdpMLineIndex === 0 || !pc.usingBundle)) {
  3436. transceiver.iceGatherer.getLocalCandidates().forEach(function(cand) {
  3437. cand.component = 1;
  3438. sdp$1 += 'a=' + sdp.writeCandidate(cand) + '\r\n';
  3439. });
  3440. if (transceiver.iceGatherer.state === 'completed') {
  3441. sdp$1 += 'a=end-of-candidates\r\n';
  3442. }
  3443. }
  3444. });
  3445. var desc = new window.RTCSessionDescription({
  3446. type: 'offer',
  3447. sdp: sdp$1
  3448. });
  3449. return Promise.resolve(desc);
  3450. };
  3451. RTCPeerConnection.prototype.createAnswer = function() {
  3452. var pc = this;
  3453. if (pc._isClosed) {
  3454. return Promise.reject(makeError('InvalidStateError',
  3455. 'Can not call createAnswer after close'));
  3456. }
  3457. if (!(pc.signalingState === 'have-remote-offer' ||
  3458. pc.signalingState === 'have-local-pranswer')) {
  3459. return Promise.reject(makeError('InvalidStateError',
  3460. 'Can not call createAnswer in signalingState ' + pc.signalingState));
  3461. }
  3462. var sdp$1 = sdp.writeSessionBoilerplate(pc._sdpSessionId,
  3463. pc._sdpSessionVersion++);
  3464. if (pc.usingBundle) {
  3465. sdp$1 += 'a=group:BUNDLE ' + pc.transceivers.map(function(t) {
  3466. return t.mid;
  3467. }).join(' ') + '\r\n';
  3468. }
  3469. sdp$1 += 'a=ice-options:trickle\r\n';
  3470. var mediaSectionsInOffer = sdp.getMediaSections(
  3471. pc._remoteDescription.sdp).length;
  3472. pc.transceivers.forEach(function(transceiver, sdpMLineIndex) {
  3473. if (sdpMLineIndex + 1 > mediaSectionsInOffer) {
  3474. return;
  3475. }
  3476. if (transceiver.rejected) {
  3477. if (transceiver.kind === 'application') {
  3478. if (transceiver.protocol === 'DTLS/SCTP') { // legacy fmt
  3479. sdp$1 += 'm=application 0 DTLS/SCTP 5000\r\n';
  3480. } else {
  3481. sdp$1 += 'm=application 0 ' + transceiver.protocol +
  3482. ' webrtc-datachannel\r\n';
  3483. }
  3484. } else if (transceiver.kind === 'audio') {
  3485. sdp$1 += 'm=audio 0 UDP/TLS/RTP/SAVPF 0\r\n' +
  3486. 'a=rtpmap:0 PCMU/8000\r\n';
  3487. } else if (transceiver.kind === 'video') {
  3488. sdp$1 += 'm=video 0 UDP/TLS/RTP/SAVPF 120\r\n' +
  3489. 'a=rtpmap:120 VP8/90000\r\n';
  3490. }
  3491. sdp$1 += 'c=IN IP4 0.0.0.0\r\n' +
  3492. 'a=inactive\r\n' +
  3493. 'a=mid:' + transceiver.mid + '\r\n';
  3494. return;
  3495. }
  3496. // FIXME: look at direction.
  3497. if (transceiver.stream) {
  3498. var localTrack;
  3499. if (transceiver.kind === 'audio') {
  3500. localTrack = transceiver.stream.getAudioTracks()[0];
  3501. } else if (transceiver.kind === 'video') {
  3502. localTrack = transceiver.stream.getVideoTracks()[0];
  3503. }
  3504. if (localTrack) {
  3505. // add RTX
  3506. if (edgeVersion >= 15019 && transceiver.kind === 'video' &&
  3507. !transceiver.sendEncodingParameters[0].rtx) {
  3508. transceiver.sendEncodingParameters[0].rtx = {
  3509. ssrc: transceiver.sendEncodingParameters[0].ssrc + 1
  3510. };
  3511. }
  3512. }
  3513. }
  3514. // Calculate intersection of capabilities.
  3515. var commonCapabilities = getCommonCapabilities(
  3516. transceiver.localCapabilities,
  3517. transceiver.remoteCapabilities);
  3518. var hasRtx = commonCapabilities.codecs.filter(function(c) {
  3519. return c.name.toLowerCase() === 'rtx';
  3520. }).length;
  3521. if (!hasRtx && transceiver.sendEncodingParameters[0].rtx) {
  3522. delete transceiver.sendEncodingParameters[0].rtx;
  3523. }
  3524. sdp$1 += writeMediaSection(transceiver, commonCapabilities,
  3525. 'answer', transceiver.stream, pc._dtlsRole);
  3526. if (transceiver.rtcpParameters &&
  3527. transceiver.rtcpParameters.reducedSize) {
  3528. sdp$1 += 'a=rtcp-rsize\r\n';
  3529. }
  3530. });
  3531. var desc = new window.RTCSessionDescription({
  3532. type: 'answer',
  3533. sdp: sdp$1
  3534. });
  3535. return Promise.resolve(desc);
  3536. };
  3537. RTCPeerConnection.prototype.addIceCandidate = function(candidate) {
  3538. var pc = this;
  3539. var sections;
  3540. if (candidate && !(candidate.sdpMLineIndex !== undefined ||
  3541. candidate.sdpMid)) {
  3542. return Promise.reject(new TypeError('sdpMLineIndex or sdpMid required'));
  3543. }
  3544. // TODO: needs to go into ops queue.
  3545. return new Promise(function(resolve, reject) {
  3546. if (!pc._remoteDescription) {
  3547. return reject(makeError('InvalidStateError',
  3548. 'Can not add ICE candidate without a remote description'));
  3549. } else if (!candidate || candidate.candidate === '') {
  3550. for (var j = 0; j < pc.transceivers.length; j++) {
  3551. if (pc.transceivers[j].rejected) {
  3552. continue;
  3553. }
  3554. pc.transceivers[j].iceTransport.addRemoteCandidate({});
  3555. sections = sdp.getMediaSections(pc._remoteDescription.sdp);
  3556. sections[j] += 'a=end-of-candidates\r\n';
  3557. pc._remoteDescription.sdp =
  3558. sdp.getDescription(pc._remoteDescription.sdp) +
  3559. sections.join('');
  3560. if (pc.usingBundle) {
  3561. break;
  3562. }
  3563. }
  3564. } else {
  3565. var sdpMLineIndex = candidate.sdpMLineIndex;
  3566. if (candidate.sdpMid) {
  3567. for (var i = 0; i < pc.transceivers.length; i++) {
  3568. if (pc.transceivers[i].mid === candidate.sdpMid) {
  3569. sdpMLineIndex = i;
  3570. break;
  3571. }
  3572. }
  3573. }
  3574. var transceiver = pc.transceivers[sdpMLineIndex];
  3575. if (transceiver) {
  3576. if (transceiver.rejected) {
  3577. return resolve();
  3578. }
  3579. var cand = Object.keys(candidate.candidate).length > 0 ?
  3580. sdp.parseCandidate(candidate.candidate) : {};
  3581. // Ignore Chrome's invalid candidates since Edge does not like them.
  3582. if (cand.protocol === 'tcp' && (cand.port === 0 || cand.port === 9)) {
  3583. return resolve();
  3584. }
  3585. // Ignore RTCP candidates, we assume RTCP-MUX.
  3586. if (cand.component && cand.component !== 1) {
  3587. return resolve();
  3588. }
  3589. // when using bundle, avoid adding candidates to the wrong
  3590. // ice transport. And avoid adding candidates added in the SDP.
  3591. if (sdpMLineIndex === 0 || (sdpMLineIndex > 0 &&
  3592. transceiver.iceTransport !== pc.transceivers[0].iceTransport)) {
  3593. if (!maybeAddCandidate(transceiver.iceTransport, cand)) {
  3594. return reject(makeError('OperationError',
  3595. 'Can not add ICE candidate'));
  3596. }
  3597. }
  3598. // update the remoteDescription.
  3599. var candidateString = candidate.candidate.trim();
  3600. if (candidateString.indexOf('a=') === 0) {
  3601. candidateString = candidateString.substr(2);
  3602. }
  3603. sections = sdp.getMediaSections(pc._remoteDescription.sdp);
  3604. sections[sdpMLineIndex] += 'a=' +
  3605. (cand.type ? candidateString : 'end-of-candidates')
  3606. + '\r\n';
  3607. pc._remoteDescription.sdp =
  3608. sdp.getDescription(pc._remoteDescription.sdp) +
  3609. sections.join('');
  3610. } else {
  3611. return reject(makeError('OperationError',
  3612. 'Can not add ICE candidate'));
  3613. }
  3614. }
  3615. resolve();
  3616. });
  3617. };
  3618. RTCPeerConnection.prototype.getStats = function(selector) {
  3619. if (selector && selector instanceof window.MediaStreamTrack) {
  3620. var senderOrReceiver = null;
  3621. this.transceivers.forEach(function(transceiver) {
  3622. if (transceiver.rtpSender &&
  3623. transceiver.rtpSender.track === selector) {
  3624. senderOrReceiver = transceiver.rtpSender;
  3625. } else if (transceiver.rtpReceiver &&
  3626. transceiver.rtpReceiver.track === selector) {
  3627. senderOrReceiver = transceiver.rtpReceiver;
  3628. }
  3629. });
  3630. if (!senderOrReceiver) {
  3631. throw makeError('InvalidAccessError', 'Invalid selector.');
  3632. }
  3633. return senderOrReceiver.getStats();
  3634. }
  3635. var promises = [];
  3636. this.transceivers.forEach(function(transceiver) {
  3637. ['rtpSender', 'rtpReceiver', 'iceGatherer', 'iceTransport',
  3638. 'dtlsTransport'].forEach(function(method) {
  3639. if (transceiver[method]) {
  3640. promises.push(transceiver[method].getStats());
  3641. }
  3642. });
  3643. });
  3644. return Promise.all(promises).then(function(allStats) {
  3645. var results = new Map();
  3646. allStats.forEach(function(stats) {
  3647. stats.forEach(function(stat) {
  3648. results.set(stat.id, stat);
  3649. });
  3650. });
  3651. return results;
  3652. });
  3653. };
  3654. // fix low-level stat names and return Map instead of object.
  3655. var ortcObjects = ['RTCRtpSender', 'RTCRtpReceiver', 'RTCIceGatherer',
  3656. 'RTCIceTransport', 'RTCDtlsTransport'];
  3657. ortcObjects.forEach(function(ortcObjectName) {
  3658. var obj = window[ortcObjectName];
  3659. if (obj && obj.prototype && obj.prototype.getStats) {
  3660. var nativeGetstats = obj.prototype.getStats;
  3661. obj.prototype.getStats = function() {
  3662. return nativeGetstats.apply(this)
  3663. .then(function(nativeStats) {
  3664. var mapStats = new Map();
  3665. Object.keys(nativeStats).forEach(function(id) {
  3666. nativeStats[id].type = fixStatsType(nativeStats[id]);
  3667. mapStats.set(id, nativeStats[id]);
  3668. });
  3669. return mapStats;
  3670. });
  3671. };
  3672. }
  3673. });
  3674. // legacy callback shims. Should be moved to adapter.js some days.
  3675. var methods = ['createOffer', 'createAnswer'];
  3676. methods.forEach(function(method) {
  3677. var nativeMethod = RTCPeerConnection.prototype[method];
  3678. RTCPeerConnection.prototype[method] = function() {
  3679. var args = arguments;
  3680. if (typeof args[0] === 'function' ||
  3681. typeof args[1] === 'function') { // legacy
  3682. return nativeMethod.apply(this, [arguments[2]])
  3683. .then(function(description) {
  3684. if (typeof args[0] === 'function') {
  3685. args[0].apply(null, [description]);
  3686. }
  3687. }, function(error) {
  3688. if (typeof args[1] === 'function') {
  3689. args[1].apply(null, [error]);
  3690. }
  3691. });
  3692. }
  3693. return nativeMethod.apply(this, arguments);
  3694. };
  3695. });
  3696. methods = ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'];
  3697. methods.forEach(function(method) {
  3698. var nativeMethod = RTCPeerConnection.prototype[method];
  3699. RTCPeerConnection.prototype[method] = function() {
  3700. var args = arguments;
  3701. if (typeof args[1] === 'function' ||
  3702. typeof args[2] === 'function') { // legacy
  3703. return nativeMethod.apply(this, arguments)
  3704. .then(function() {
  3705. if (typeof args[1] === 'function') {
  3706. args[1].apply(null);
  3707. }
  3708. }, function(error) {
  3709. if (typeof args[2] === 'function') {
  3710. args[2].apply(null, [error]);
  3711. }
  3712. });
  3713. }
  3714. return nativeMethod.apply(this, arguments);
  3715. };
  3716. });
  3717. // getStats is special. It doesn't have a spec legacy method yet we support
  3718. // getStats(something, cb) without error callbacks.
  3719. ['getStats'].forEach(function(method) {
  3720. var nativeMethod = RTCPeerConnection.prototype[method];
  3721. RTCPeerConnection.prototype[method] = function() {
  3722. var args = arguments;
  3723. if (typeof args[1] === 'function') {
  3724. return nativeMethod.apply(this, arguments)
  3725. .then(function() {
  3726. if (typeof args[1] === 'function') {
  3727. args[1].apply(null);
  3728. }
  3729. });
  3730. }
  3731. return nativeMethod.apply(this, arguments);
  3732. };
  3733. });
  3734. return RTCPeerConnection;
  3735. };
  3736. /*
  3737. * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
  3738. *
  3739. * Use of this source code is governed by a BSD-style license
  3740. * that can be found in the LICENSE file in the root of the source
  3741. * tree.
  3742. */
  3743. function shimGetUserMedia$2(window) {
  3744. const navigator = window && window.navigator;
  3745. const shimError_ = function(e) {
  3746. return {
  3747. name: {PermissionDeniedError: 'NotAllowedError'}[e.name] || e.name,
  3748. message: e.message,
  3749. constraint: e.constraint,
  3750. toString() {
  3751. return this.name;
  3752. }
  3753. };
  3754. };
  3755. // getUserMedia error shim.
  3756. const origGetUserMedia = navigator.mediaDevices.getUserMedia.
  3757. bind(navigator.mediaDevices);
  3758. navigator.mediaDevices.getUserMedia = function(c) {
  3759. return origGetUserMedia(c).catch(e => Promise.reject(shimError_(e)));
  3760. };
  3761. }
  3762. /*
  3763. * Copyright (c) 2018 The adapter.js project authors. All Rights Reserved.
  3764. *
  3765. * Use of this source code is governed by a BSD-style license
  3766. * that can be found in the LICENSE file in the root of the source
  3767. * tree.
  3768. */
  3769. function shimGetDisplayMedia$1(window) {
  3770. if (!('getDisplayMedia' in window.navigator)) {
  3771. return;
  3772. }
  3773. if (!(window.navigator.mediaDevices)) {
  3774. return;
  3775. }
  3776. if (window.navigator.mediaDevices &&
  3777. 'getDisplayMedia' in window.navigator.mediaDevices) {
  3778. return;
  3779. }
  3780. window.navigator.mediaDevices.getDisplayMedia =
  3781. window.navigator.getDisplayMedia.bind(window.navigator);
  3782. }
  3783. /*
  3784. * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
  3785. *
  3786. * Use of this source code is governed by a BSD-style license
  3787. * that can be found in the LICENSE file in the root of the source
  3788. * tree.
  3789. */
  3790. function shimPeerConnection$1(window, browserDetails) {
  3791. if (window.RTCIceGatherer) {
  3792. if (!window.RTCIceCandidate) {
  3793. window.RTCIceCandidate = function RTCIceCandidate(args) {
  3794. return args;
  3795. };
  3796. }
  3797. if (!window.RTCSessionDescription) {
  3798. window.RTCSessionDescription = function RTCSessionDescription(args) {
  3799. return args;
  3800. };
  3801. }
  3802. // this adds an additional event listener to MediaStrackTrack that signals
  3803. // when a tracks enabled property was changed. Workaround for a bug in
  3804. // addStream, see below. No longer required in 15025+
  3805. if (browserDetails.version < 15025) {
  3806. const origMSTEnabled = Object.getOwnPropertyDescriptor(
  3807. window.MediaStreamTrack.prototype, 'enabled');
  3808. Object.defineProperty(window.MediaStreamTrack.prototype, 'enabled', {
  3809. set(value) {
  3810. origMSTEnabled.set.call(this, value);
  3811. const ev = new Event('enabled');
  3812. ev.enabled = value;
  3813. this.dispatchEvent(ev);
  3814. }
  3815. });
  3816. }
  3817. }
  3818. // ORTC defines the DTMF sender a bit different.
  3819. // https://github.com/w3c/ortc/issues/714
  3820. if (window.RTCRtpSender && !('dtmf' in window.RTCRtpSender.prototype)) {
  3821. Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', {
  3822. get() {
  3823. if (this._dtmf === undefined) {
  3824. if (this.track.kind === 'audio') {
  3825. this._dtmf = new window.RTCDtmfSender(this);
  3826. } else if (this.track.kind === 'video') {
  3827. this._dtmf = null;
  3828. }
  3829. }
  3830. return this._dtmf;
  3831. }
  3832. });
  3833. }
  3834. // Edge currently only implements the RTCDtmfSender, not the
  3835. // RTCDTMFSender alias. See http://draft.ortc.org/#rtcdtmfsender2*
  3836. if (window.RTCDtmfSender && !window.RTCDTMFSender) {
  3837. window.RTCDTMFSender = window.RTCDtmfSender;
  3838. }
  3839. const RTCPeerConnectionShim = rtcpeerconnection(window,
  3840. browserDetails.version);
  3841. window.RTCPeerConnection = function RTCPeerConnection(config) {
  3842. if (config && config.iceServers) {
  3843. config.iceServers = filterIceServers$1(config.iceServers,
  3844. browserDetails.version);
  3845. log$1('ICE servers after filtering:', config.iceServers);
  3846. }
  3847. return new RTCPeerConnectionShim(config);
  3848. };
  3849. window.RTCPeerConnection.prototype = RTCPeerConnectionShim.prototype;
  3850. }
  3851. function shimReplaceTrack(window) {
  3852. // ORTC has replaceTrack -- https://github.com/w3c/ortc/issues/614
  3853. if (window.RTCRtpSender &&
  3854. !('replaceTrack' in window.RTCRtpSender.prototype)) {
  3855. window.RTCRtpSender.prototype.replaceTrack =
  3856. window.RTCRtpSender.prototype.setTrack;
  3857. }
  3858. }
  3859. var edgeShim = /*#__PURE__*/Object.freeze({
  3860. __proto__: null,
  3861. shimPeerConnection: shimPeerConnection$1,
  3862. shimReplaceTrack: shimReplaceTrack,
  3863. shimGetUserMedia: shimGetUserMedia$2,
  3864. shimGetDisplayMedia: shimGetDisplayMedia$1
  3865. });
  3866. /*
  3867. * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
  3868. *
  3869. * Use of this source code is governed by a BSD-style license
  3870. * that can be found in the LICENSE file in the root of the source
  3871. * tree.
  3872. */
  3873. function shimGetUserMedia$1(window, browserDetails) {
  3874. const navigator = window && window.navigator;
  3875. const MediaStreamTrack = window && window.MediaStreamTrack;
  3876. navigator.getUserMedia = function(constraints, onSuccess, onError) {
  3877. // Replace Firefox 44+'s deprecation warning with unprefixed version.
  3878. deprecated('navigator.getUserMedia',
  3879. 'navigator.mediaDevices.getUserMedia');
  3880. navigator.mediaDevices.getUserMedia(constraints).then(onSuccess, onError);
  3881. };
  3882. if (!(browserDetails.version > 55 &&
  3883. 'autoGainControl' in navigator.mediaDevices.getSupportedConstraints())) {
  3884. const remap = function(obj, a, b) {
  3885. if (a in obj && !(b in obj)) {
  3886. obj[b] = obj[a];
  3887. delete obj[a];
  3888. }
  3889. };
  3890. const nativeGetUserMedia = navigator.mediaDevices.getUserMedia.
  3891. bind(navigator.mediaDevices);
  3892. navigator.mediaDevices.getUserMedia = function(c) {
  3893. if (typeof c === 'object' && typeof c.audio === 'object') {
  3894. c = JSON.parse(JSON.stringify(c));
  3895. remap(c.audio, 'autoGainControl', 'mozAutoGainControl');
  3896. remap(c.audio, 'noiseSuppression', 'mozNoiseSuppression');
  3897. }
  3898. return nativeGetUserMedia(c);
  3899. };
  3900. if (MediaStreamTrack && MediaStreamTrack.prototype.getSettings) {
  3901. const nativeGetSettings = MediaStreamTrack.prototype.getSettings;
  3902. MediaStreamTrack.prototype.getSettings = function() {
  3903. const obj = nativeGetSettings.apply(this, arguments);
  3904. remap(obj, 'mozAutoGainControl', 'autoGainControl');
  3905. remap(obj, 'mozNoiseSuppression', 'noiseSuppression');
  3906. return obj;
  3907. };
  3908. }
  3909. if (MediaStreamTrack && MediaStreamTrack.prototype.applyConstraints) {
  3910. const nativeApplyConstraints =
  3911. MediaStreamTrack.prototype.applyConstraints;
  3912. MediaStreamTrack.prototype.applyConstraints = function(c) {
  3913. if (this.kind === 'audio' && typeof c === 'object') {
  3914. c = JSON.parse(JSON.stringify(c));
  3915. remap(c, 'autoGainControl', 'mozAutoGainControl');
  3916. remap(c, 'noiseSuppression', 'mozNoiseSuppression');
  3917. }
  3918. return nativeApplyConstraints.apply(this, [c]);
  3919. };
  3920. }
  3921. }
  3922. }
  3923. /*
  3924. * Copyright (c) 2018 The adapter.js project authors. All Rights Reserved.
  3925. *
  3926. * Use of this source code is governed by a BSD-style license
  3927. * that can be found in the LICENSE file in the root of the source
  3928. * tree.
  3929. */
  3930. function shimGetDisplayMedia(window, preferredMediaSource) {
  3931. if (window.navigator.mediaDevices &&
  3932. 'getDisplayMedia' in window.navigator.mediaDevices) {
  3933. return;
  3934. }
  3935. if (!(window.navigator.mediaDevices)) {
  3936. return;
  3937. }
  3938. window.navigator.mediaDevices.getDisplayMedia =
  3939. function getDisplayMedia(constraints) {
  3940. if (!(constraints && constraints.video)) {
  3941. const err = new DOMException('getDisplayMedia without video ' +
  3942. 'constraints is undefined');
  3943. err.name = 'NotFoundError';
  3944. // from https://heycam.github.io/webidl/#idl-DOMException-error-names
  3945. err.code = 8;
  3946. return Promise.reject(err);
  3947. }
  3948. if (constraints.video === true) {
  3949. constraints.video = {mediaSource: preferredMediaSource};
  3950. } else {
  3951. constraints.video.mediaSource = preferredMediaSource;
  3952. }
  3953. return window.navigator.mediaDevices.getUserMedia(constraints);
  3954. };
  3955. }
  3956. /*
  3957. * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
  3958. *
  3959. * Use of this source code is governed by a BSD-style license
  3960. * that can be found in the LICENSE file in the root of the source
  3961. * tree.
  3962. */
  3963. function shimOnTrack(window) {
  3964. if (typeof window === 'object' && window.RTCTrackEvent &&
  3965. ('receiver' in window.RTCTrackEvent.prototype) &&
  3966. !('transceiver' in window.RTCTrackEvent.prototype)) {
  3967. Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', {
  3968. get() {
  3969. return {receiver: this.receiver};
  3970. }
  3971. });
  3972. }
  3973. }
  3974. function shimPeerConnection(window, browserDetails) {
  3975. if (typeof window !== 'object' ||
  3976. !(window.RTCPeerConnection || window.mozRTCPeerConnection)) {
  3977. return; // probably media.peerconnection.enabled=false in about:config
  3978. }
  3979. if (!window.RTCPeerConnection && window.mozRTCPeerConnection) {
  3980. // very basic support for old versions.
  3981. window.RTCPeerConnection = window.mozRTCPeerConnection;
  3982. }
  3983. if (browserDetails.version < 53) {
  3984. // shim away need for obsolete RTCIceCandidate/RTCSessionDescription.
  3985. ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate']
  3986. .forEach(function(method) {
  3987. const nativeMethod = window.RTCPeerConnection.prototype[method];
  3988. const methodObj = {[method]() {
  3989. arguments[0] = new ((method === 'addIceCandidate') ?
  3990. window.RTCIceCandidate :
  3991. window.RTCSessionDescription)(arguments[0]);
  3992. return nativeMethod.apply(this, arguments);
  3993. }};
  3994. window.RTCPeerConnection.prototype[method] = methodObj[method];
  3995. });
  3996. }
  3997. const modernStatsTypes = {
  3998. inboundrtp: 'inbound-rtp',
  3999. outboundrtp: 'outbound-rtp',
  4000. candidatepair: 'candidate-pair',
  4001. localcandidate: 'local-candidate',
  4002. remotecandidate: 'remote-candidate'
  4003. };
  4004. const nativeGetStats = window.RTCPeerConnection.prototype.getStats;
  4005. window.RTCPeerConnection.prototype.getStats = function getStats() {
  4006. const [selector, onSucc, onErr] = arguments;
  4007. return nativeGetStats.apply(this, [selector || null])
  4008. .then(stats => {
  4009. if (browserDetails.version < 53 && !onSucc) {
  4010. // Shim only promise getStats with spec-hyphens in type names
  4011. // Leave callback version alone; misc old uses of forEach before Map
  4012. try {
  4013. stats.forEach(stat => {
  4014. stat.type = modernStatsTypes[stat.type] || stat.type;
  4015. });
  4016. } catch (e) {
  4017. if (e.name !== 'TypeError') {
  4018. throw e;
  4019. }
  4020. // Avoid TypeError: "type" is read-only, in old versions. 34-43ish
  4021. stats.forEach((stat, i) => {
  4022. stats.set(i, Object.assign({}, stat, {
  4023. type: modernStatsTypes[stat.type] || stat.type
  4024. }));
  4025. });
  4026. }
  4027. }
  4028. return stats;
  4029. })
  4030. .then(onSucc, onErr);
  4031. };
  4032. }
  4033. function shimSenderGetStats(window) {
  4034. if (!(typeof window === 'object' && window.RTCPeerConnection &&
  4035. window.RTCRtpSender)) {
  4036. return;
  4037. }
  4038. if (window.RTCRtpSender && 'getStats' in window.RTCRtpSender.prototype) {
  4039. return;
  4040. }
  4041. const origGetSenders = window.RTCPeerConnection.prototype.getSenders;
  4042. if (origGetSenders) {
  4043. window.RTCPeerConnection.prototype.getSenders = function getSenders() {
  4044. const senders = origGetSenders.apply(this, []);
  4045. senders.forEach(sender => sender._pc = this);
  4046. return senders;
  4047. };
  4048. }
  4049. const origAddTrack = window.RTCPeerConnection.prototype.addTrack;
  4050. if (origAddTrack) {
  4051. window.RTCPeerConnection.prototype.addTrack = function addTrack() {
  4052. const sender = origAddTrack.apply(this, arguments);
  4053. sender._pc = this;
  4054. return sender;
  4055. };
  4056. }
  4057. window.RTCRtpSender.prototype.getStats = function getStats() {
  4058. return this.track ? this._pc.getStats(this.track) :
  4059. Promise.resolve(new Map());
  4060. };
  4061. }
  4062. function shimReceiverGetStats(window) {
  4063. if (!(typeof window === 'object' && window.RTCPeerConnection &&
  4064. window.RTCRtpSender)) {
  4065. return;
  4066. }
  4067. if (window.RTCRtpSender && 'getStats' in window.RTCRtpReceiver.prototype) {
  4068. return;
  4069. }
  4070. const origGetReceivers = window.RTCPeerConnection.prototype.getReceivers;
  4071. if (origGetReceivers) {
  4072. window.RTCPeerConnection.prototype.getReceivers = function getReceivers() {
  4073. const receivers = origGetReceivers.apply(this, []);
  4074. receivers.forEach(receiver => receiver._pc = this);
  4075. return receivers;
  4076. };
  4077. }
  4078. wrapPeerConnectionEvent(window, 'track', e => {
  4079. e.receiver._pc = e.srcElement;
  4080. return e;
  4081. });
  4082. window.RTCRtpReceiver.prototype.getStats = function getStats() {
  4083. return this._pc.getStats(this.track);
  4084. };
  4085. }
  4086. function shimRemoveStream(window) {
  4087. if (!window.RTCPeerConnection ||
  4088. 'removeStream' in window.RTCPeerConnection.prototype) {
  4089. return;
  4090. }
  4091. window.RTCPeerConnection.prototype.removeStream =
  4092. function removeStream(stream) {
  4093. deprecated('removeStream', 'removeTrack');
  4094. this.getSenders().forEach(sender => {
  4095. if (sender.track && stream.getTracks().includes(sender.track)) {
  4096. this.removeTrack(sender);
  4097. }
  4098. });
  4099. };
  4100. }
  4101. function shimRTCDataChannel(window) {
  4102. // rename DataChannel to RTCDataChannel (native fix in FF60):
  4103. // https://bugzilla.mozilla.org/show_bug.cgi?id=1173851
  4104. if (window.DataChannel && !window.RTCDataChannel) {
  4105. window.RTCDataChannel = window.DataChannel;
  4106. }
  4107. }
  4108. function shimAddTransceiver(window) {
  4109. // https://github.com/webrtcHacks/adapter/issues/998#issuecomment-516921647
  4110. // Firefox ignores the init sendEncodings options passed to addTransceiver
  4111. // https://bugzilla.mozilla.org/show_bug.cgi?id=1396918
  4112. if (!(typeof window === 'object' && window.RTCPeerConnection)) {
  4113. return;
  4114. }
  4115. const origAddTransceiver = window.RTCPeerConnection.prototype.addTransceiver;
  4116. if (origAddTransceiver) {
  4117. window.RTCPeerConnection.prototype.addTransceiver =
  4118. function addTransceiver() {
  4119. this.setParametersPromises = [];
  4120. const initParameters = arguments[1];
  4121. const shouldPerformCheck = initParameters &&
  4122. 'sendEncodings' in initParameters;
  4123. if (shouldPerformCheck) {
  4124. // If sendEncodings params are provided, validate grammar
  4125. initParameters.sendEncodings.forEach((encodingParam) => {
  4126. if ('rid' in encodingParam) {
  4127. const ridRegex = /^[a-z0-9]{0,16}$/i;
  4128. if (!ridRegex.test(encodingParam.rid)) {
  4129. throw new TypeError('Invalid RID value provided.');
  4130. }
  4131. }
  4132. if ('scaleResolutionDownBy' in encodingParam) {
  4133. if (!(parseFloat(encodingParam.scaleResolutionDownBy) >= 1.0)) {
  4134. throw new RangeError('scale_resolution_down_by must be >= 1.0');
  4135. }
  4136. }
  4137. if ('maxFramerate' in encodingParam) {
  4138. if (!(parseFloat(encodingParam.maxFramerate) >= 0)) {
  4139. throw new RangeError('max_framerate must be >= 0.0');
  4140. }
  4141. }
  4142. });
  4143. }
  4144. const transceiver = origAddTransceiver.apply(this, arguments);
  4145. if (shouldPerformCheck) {
  4146. // Check if the init options were applied. If not we do this in an
  4147. // asynchronous way and save the promise reference in a global object.
  4148. // This is an ugly hack, but at the same time is way more robust than
  4149. // checking the sender parameters before and after the createOffer
  4150. // Also note that after the createoffer we are not 100% sure that
  4151. // the params were asynchronously applied so we might miss the
  4152. // opportunity to recreate offer.
  4153. const {sender} = transceiver;
  4154. const params = sender.getParameters();
  4155. if (!('encodings' in params) ||
  4156. // Avoid being fooled by patched getParameters() below.
  4157. (params.encodings.length === 1 &&
  4158. Object.keys(params.encodings[0]).length === 0)) {
  4159. params.encodings = initParameters.sendEncodings;
  4160. sender.sendEncodings = initParameters.sendEncodings;
  4161. this.setParametersPromises.push(sender.setParameters(params)
  4162. .then(() => {
  4163. delete sender.sendEncodings;
  4164. }).catch(() => {
  4165. delete sender.sendEncodings;
  4166. })
  4167. );
  4168. }
  4169. }
  4170. return transceiver;
  4171. };
  4172. }
  4173. }
  4174. function shimGetParameters(window) {
  4175. if (!(typeof window === 'object' && window.RTCRtpSender)) {
  4176. return;
  4177. }
  4178. const origGetParameters = window.RTCRtpSender.prototype.getParameters;
  4179. if (origGetParameters) {
  4180. window.RTCRtpSender.prototype.getParameters =
  4181. function getParameters() {
  4182. const params = origGetParameters.apply(this, arguments);
  4183. if (!('encodings' in params)) {
  4184. params.encodings = [].concat(this.sendEncodings || [{}]);
  4185. }
  4186. return params;
  4187. };
  4188. }
  4189. }
  4190. function shimCreateOffer(window) {
  4191. // https://github.com/webrtcHacks/adapter/issues/998#issuecomment-516921647
  4192. // Firefox ignores the init sendEncodings options passed to addTransceiver
  4193. // https://bugzilla.mozilla.org/show_bug.cgi?id=1396918
  4194. if (!(typeof window === 'object' && window.RTCPeerConnection)) {
  4195. return;
  4196. }
  4197. const origCreateOffer = window.RTCPeerConnection.prototype.createOffer;
  4198. window.RTCPeerConnection.prototype.createOffer = function createOffer() {
  4199. if (this.setParametersPromises && this.setParametersPromises.length) {
  4200. return Promise.all(this.setParametersPromises)
  4201. .then(() => {
  4202. return origCreateOffer.apply(this, arguments);
  4203. })
  4204. .finally(() => {
  4205. this.setParametersPromises = [];
  4206. });
  4207. }
  4208. return origCreateOffer.apply(this, arguments);
  4209. };
  4210. }
  4211. function shimCreateAnswer(window) {
  4212. // https://github.com/webrtcHacks/adapter/issues/998#issuecomment-516921647
  4213. // Firefox ignores the init sendEncodings options passed to addTransceiver
  4214. // https://bugzilla.mozilla.org/show_bug.cgi?id=1396918
  4215. if (!(typeof window === 'object' && window.RTCPeerConnection)) {
  4216. return;
  4217. }
  4218. const origCreateAnswer = window.RTCPeerConnection.prototype.createAnswer;
  4219. window.RTCPeerConnection.prototype.createAnswer = function createAnswer() {
  4220. if (this.setParametersPromises && this.setParametersPromises.length) {
  4221. return Promise.all(this.setParametersPromises)
  4222. .then(() => {
  4223. return origCreateAnswer.apply(this, arguments);
  4224. })
  4225. .finally(() => {
  4226. this.setParametersPromises = [];
  4227. });
  4228. }
  4229. return origCreateAnswer.apply(this, arguments);
  4230. };
  4231. }
  4232. var firefoxShim = /*#__PURE__*/Object.freeze({
  4233. __proto__: null,
  4234. shimOnTrack: shimOnTrack,
  4235. shimPeerConnection: shimPeerConnection,
  4236. shimSenderGetStats: shimSenderGetStats,
  4237. shimReceiverGetStats: shimReceiverGetStats,
  4238. shimRemoveStream: shimRemoveStream,
  4239. shimRTCDataChannel: shimRTCDataChannel,
  4240. shimAddTransceiver: shimAddTransceiver,
  4241. shimGetParameters: shimGetParameters,
  4242. shimCreateOffer: shimCreateOffer,
  4243. shimCreateAnswer: shimCreateAnswer,
  4244. shimGetUserMedia: shimGetUserMedia$1,
  4245. shimGetDisplayMedia: shimGetDisplayMedia
  4246. });
  4247. /*
  4248. * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
  4249. *
  4250. * Use of this source code is governed by a BSD-style license
  4251. * that can be found in the LICENSE file in the root of the source
  4252. * tree.
  4253. */
  4254. function shimLocalStreamsAPI(window) {
  4255. if (typeof window !== 'object' || !window.RTCPeerConnection) {
  4256. return;
  4257. }
  4258. if (!('getLocalStreams' in window.RTCPeerConnection.prototype)) {
  4259. window.RTCPeerConnection.prototype.getLocalStreams =
  4260. function getLocalStreams() {
  4261. if (!this._localStreams) {
  4262. this._localStreams = [];
  4263. }
  4264. return this._localStreams;
  4265. };
  4266. }
  4267. if (!('addStream' in window.RTCPeerConnection.prototype)) {
  4268. const _addTrack = window.RTCPeerConnection.prototype.addTrack;
  4269. window.RTCPeerConnection.prototype.addStream = function addStream(stream) {
  4270. if (!this._localStreams) {
  4271. this._localStreams = [];
  4272. }
  4273. if (!this._localStreams.includes(stream)) {
  4274. this._localStreams.push(stream);
  4275. }
  4276. // Try to emulate Chrome's behaviour of adding in audio-video order.
  4277. // Safari orders by track id.
  4278. stream.getAudioTracks().forEach(track => _addTrack.call(this, track,
  4279. stream));
  4280. stream.getVideoTracks().forEach(track => _addTrack.call(this, track,
  4281. stream));
  4282. };
  4283. window.RTCPeerConnection.prototype.addTrack =
  4284. function addTrack(track, ...streams) {
  4285. if (streams) {
  4286. streams.forEach((stream) => {
  4287. if (!this._localStreams) {
  4288. this._localStreams = [stream];
  4289. } else if (!this._localStreams.includes(stream)) {
  4290. this._localStreams.push(stream);
  4291. }
  4292. });
  4293. }
  4294. return _addTrack.apply(this, arguments);
  4295. };
  4296. }
  4297. if (!('removeStream' in window.RTCPeerConnection.prototype)) {
  4298. window.RTCPeerConnection.prototype.removeStream =
  4299. function removeStream(stream) {
  4300. if (!this._localStreams) {
  4301. this._localStreams = [];
  4302. }
  4303. const index = this._localStreams.indexOf(stream);
  4304. if (index === -1) {
  4305. return;
  4306. }
  4307. this._localStreams.splice(index, 1);
  4308. const tracks = stream.getTracks();
  4309. this.getSenders().forEach(sender => {
  4310. if (tracks.includes(sender.track)) {
  4311. this.removeTrack(sender);
  4312. }
  4313. });
  4314. };
  4315. }
  4316. }
  4317. function shimRemoteStreamsAPI(window) {
  4318. if (typeof window !== 'object' || !window.RTCPeerConnection) {
  4319. return;
  4320. }
  4321. if (!('getRemoteStreams' in window.RTCPeerConnection.prototype)) {
  4322. window.RTCPeerConnection.prototype.getRemoteStreams =
  4323. function getRemoteStreams() {
  4324. return this._remoteStreams ? this._remoteStreams : [];
  4325. };
  4326. }
  4327. if (!('onaddstream' in window.RTCPeerConnection.prototype)) {
  4328. Object.defineProperty(window.RTCPeerConnection.prototype, 'onaddstream', {
  4329. get() {
  4330. return this._onaddstream;
  4331. },
  4332. set(f) {
  4333. if (this._onaddstream) {
  4334. this.removeEventListener('addstream', this._onaddstream);
  4335. this.removeEventListener('track', this._onaddstreampoly);
  4336. }
  4337. this.addEventListener('addstream', this._onaddstream = f);
  4338. this.addEventListener('track', this._onaddstreampoly = (e) => {
  4339. e.streams.forEach(stream => {
  4340. if (!this._remoteStreams) {
  4341. this._remoteStreams = [];
  4342. }
  4343. if (this._remoteStreams.includes(stream)) {
  4344. return;
  4345. }
  4346. this._remoteStreams.push(stream);
  4347. const event = new Event('addstream');
  4348. event.stream = stream;
  4349. this.dispatchEvent(event);
  4350. });
  4351. });
  4352. }
  4353. });
  4354. const origSetRemoteDescription =
  4355. window.RTCPeerConnection.prototype.setRemoteDescription;
  4356. window.RTCPeerConnection.prototype.setRemoteDescription =
  4357. function setRemoteDescription() {
  4358. const pc = this;
  4359. if (!this._onaddstreampoly) {
  4360. this.addEventListener('track', this._onaddstreampoly = function(e) {
  4361. e.streams.forEach(stream => {
  4362. if (!pc._remoteStreams) {
  4363. pc._remoteStreams = [];
  4364. }
  4365. if (pc._remoteStreams.indexOf(stream) >= 0) {
  4366. return;
  4367. }
  4368. pc._remoteStreams.push(stream);
  4369. const event = new Event('addstream');
  4370. event.stream = stream;
  4371. pc.dispatchEvent(event);
  4372. });
  4373. });
  4374. }
  4375. return origSetRemoteDescription.apply(pc, arguments);
  4376. };
  4377. }
  4378. }
  4379. function shimCallbacksAPI(window) {
  4380. if (typeof window !== 'object' || !window.RTCPeerConnection) {
  4381. return;
  4382. }
  4383. const prototype = window.RTCPeerConnection.prototype;
  4384. const origCreateOffer = prototype.createOffer;
  4385. const origCreateAnswer = prototype.createAnswer;
  4386. const setLocalDescription = prototype.setLocalDescription;
  4387. const setRemoteDescription = prototype.setRemoteDescription;
  4388. const addIceCandidate = prototype.addIceCandidate;
  4389. prototype.createOffer =
  4390. function createOffer(successCallback, failureCallback) {
  4391. const options = (arguments.length >= 2) ? arguments[2] : arguments[0];
  4392. const promise = origCreateOffer.apply(this, [options]);
  4393. if (!failureCallback) {
  4394. return promise;
  4395. }
  4396. promise.then(successCallback, failureCallback);
  4397. return Promise.resolve();
  4398. };
  4399. prototype.createAnswer =
  4400. function createAnswer(successCallback, failureCallback) {
  4401. const options = (arguments.length >= 2) ? arguments[2] : arguments[0];
  4402. const promise = origCreateAnswer.apply(this, [options]);
  4403. if (!failureCallback) {
  4404. return promise;
  4405. }
  4406. promise.then(successCallback, failureCallback);
  4407. return Promise.resolve();
  4408. };
  4409. let withCallback = function(description, successCallback, failureCallback) {
  4410. const promise = setLocalDescription.apply(this, [description]);
  4411. if (!failureCallback) {
  4412. return promise;
  4413. }
  4414. promise.then(successCallback, failureCallback);
  4415. return Promise.resolve();
  4416. };
  4417. prototype.setLocalDescription = withCallback;
  4418. withCallback = function(description, successCallback, failureCallback) {
  4419. const promise = setRemoteDescription.apply(this, [description]);
  4420. if (!failureCallback) {
  4421. return promise;
  4422. }
  4423. promise.then(successCallback, failureCallback);
  4424. return Promise.resolve();
  4425. };
  4426. prototype.setRemoteDescription = withCallback;
  4427. withCallback = function(candidate, successCallback, failureCallback) {
  4428. const promise = addIceCandidate.apply(this, [candidate]);
  4429. if (!failureCallback) {
  4430. return promise;
  4431. }
  4432. promise.then(successCallback, failureCallback);
  4433. return Promise.resolve();
  4434. };
  4435. prototype.addIceCandidate = withCallback;
  4436. }
  4437. function shimGetUserMedia(window) {
  4438. const navigator = window && window.navigator;
  4439. if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
  4440. // shim not needed in Safari 12.1
  4441. const mediaDevices = navigator.mediaDevices;
  4442. const _getUserMedia = mediaDevices.getUserMedia.bind(mediaDevices);
  4443. navigator.mediaDevices.getUserMedia = (constraints) => {
  4444. return _getUserMedia(shimConstraints(constraints));
  4445. };
  4446. }
  4447. if (!navigator.getUserMedia && navigator.mediaDevices &&
  4448. navigator.mediaDevices.getUserMedia) {
  4449. navigator.getUserMedia = function getUserMedia(constraints, cb, errcb) {
  4450. navigator.mediaDevices.getUserMedia(constraints)
  4451. .then(cb, errcb);
  4452. }.bind(navigator);
  4453. }
  4454. }
  4455. function shimConstraints(constraints) {
  4456. if (constraints && constraints.video !== undefined) {
  4457. return Object.assign({},
  4458. constraints,
  4459. {video: compactObject(constraints.video)}
  4460. );
  4461. }
  4462. return constraints;
  4463. }
  4464. function shimRTCIceServerUrls(window) {
  4465. if (!window.RTCPeerConnection) {
  4466. return;
  4467. }
  4468. // migrate from non-spec RTCIceServer.url to RTCIceServer.urls
  4469. const OrigPeerConnection = window.RTCPeerConnection;
  4470. window.RTCPeerConnection =
  4471. function RTCPeerConnection(pcConfig, pcConstraints) {
  4472. if (pcConfig && pcConfig.iceServers) {
  4473. const newIceServers = [];
  4474. for (let i = 0; i < pcConfig.iceServers.length; i++) {
  4475. let server = pcConfig.iceServers[i];
  4476. if (!server.hasOwnProperty('urls') &&
  4477. server.hasOwnProperty('url')) {
  4478. deprecated('RTCIceServer.url', 'RTCIceServer.urls');
  4479. server = JSON.parse(JSON.stringify(server));
  4480. server.urls = server.url;
  4481. delete server.url;
  4482. newIceServers.push(server);
  4483. } else {
  4484. newIceServers.push(pcConfig.iceServers[i]);
  4485. }
  4486. }
  4487. pcConfig.iceServers = newIceServers;
  4488. }
  4489. return new OrigPeerConnection(pcConfig, pcConstraints);
  4490. };
  4491. window.RTCPeerConnection.prototype = OrigPeerConnection.prototype;
  4492. // wrap static methods. Currently just generateCertificate.
  4493. if ('generateCertificate' in OrigPeerConnection) {
  4494. Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', {
  4495. get() {
  4496. return OrigPeerConnection.generateCertificate;
  4497. }
  4498. });
  4499. }
  4500. }
  4501. function shimTrackEventTransceiver(window) {
  4502. // Add event.transceiver member over deprecated event.receiver
  4503. if (typeof window === 'object' && window.RTCTrackEvent &&
  4504. 'receiver' in window.RTCTrackEvent.prototype &&
  4505. !('transceiver' in window.RTCTrackEvent.prototype)) {
  4506. Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', {
  4507. get() {
  4508. return {receiver: this.receiver};
  4509. }
  4510. });
  4511. }
  4512. }
  4513. function shimCreateOfferLegacy(window) {
  4514. const origCreateOffer = window.RTCPeerConnection.prototype.createOffer;
  4515. window.RTCPeerConnection.prototype.createOffer =
  4516. function createOffer(offerOptions) {
  4517. if (offerOptions) {
  4518. if (typeof offerOptions.offerToReceiveAudio !== 'undefined') {
  4519. // support bit values
  4520. offerOptions.offerToReceiveAudio =
  4521. !!offerOptions.offerToReceiveAudio;
  4522. }
  4523. const audioTransceiver = this.getTransceivers().find(transceiver =>
  4524. transceiver.receiver.track.kind === 'audio');
  4525. if (offerOptions.offerToReceiveAudio === false && audioTransceiver) {
  4526. if (audioTransceiver.direction === 'sendrecv') {
  4527. if (audioTransceiver.setDirection) {
  4528. audioTransceiver.setDirection('sendonly');
  4529. } else {
  4530. audioTransceiver.direction = 'sendonly';
  4531. }
  4532. } else if (audioTransceiver.direction === 'recvonly') {
  4533. if (audioTransceiver.setDirection) {
  4534. audioTransceiver.setDirection('inactive');
  4535. } else {
  4536. audioTransceiver.direction = 'inactive';
  4537. }
  4538. }
  4539. } else if (offerOptions.offerToReceiveAudio === true &&
  4540. !audioTransceiver) {
  4541. this.addTransceiver('audio');
  4542. }
  4543. if (typeof offerOptions.offerToReceiveVideo !== 'undefined') {
  4544. // support bit values
  4545. offerOptions.offerToReceiveVideo =
  4546. !!offerOptions.offerToReceiveVideo;
  4547. }
  4548. const videoTransceiver = this.getTransceivers().find(transceiver =>
  4549. transceiver.receiver.track.kind === 'video');
  4550. if (offerOptions.offerToReceiveVideo === false && videoTransceiver) {
  4551. if (videoTransceiver.direction === 'sendrecv') {
  4552. if (videoTransceiver.setDirection) {
  4553. videoTransceiver.setDirection('sendonly');
  4554. } else {
  4555. videoTransceiver.direction = 'sendonly';
  4556. }
  4557. } else if (videoTransceiver.direction === 'recvonly') {
  4558. if (videoTransceiver.setDirection) {
  4559. videoTransceiver.setDirection('inactive');
  4560. } else {
  4561. videoTransceiver.direction = 'inactive';
  4562. }
  4563. }
  4564. } else if (offerOptions.offerToReceiveVideo === true &&
  4565. !videoTransceiver) {
  4566. this.addTransceiver('video');
  4567. }
  4568. }
  4569. return origCreateOffer.apply(this, arguments);
  4570. };
  4571. }
  4572. function shimAudioContext(window) {
  4573. if (typeof window !== 'object' || window.AudioContext) {
  4574. return;
  4575. }
  4576. window.AudioContext = window.webkitAudioContext;
  4577. }
  4578. var safariShim = /*#__PURE__*/Object.freeze({
  4579. __proto__: null,
  4580. shimLocalStreamsAPI: shimLocalStreamsAPI,
  4581. shimRemoteStreamsAPI: shimRemoteStreamsAPI,
  4582. shimCallbacksAPI: shimCallbacksAPI,
  4583. shimGetUserMedia: shimGetUserMedia,
  4584. shimConstraints: shimConstraints,
  4585. shimRTCIceServerUrls: shimRTCIceServerUrls,
  4586. shimTrackEventTransceiver: shimTrackEventTransceiver,
  4587. shimCreateOfferLegacy: shimCreateOfferLegacy,
  4588. shimAudioContext: shimAudioContext
  4589. });
  4590. /*
  4591. * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
  4592. *
  4593. * Use of this source code is governed by a BSD-style license
  4594. * that can be found in the LICENSE file in the root of the source
  4595. * tree.
  4596. */
  4597. function shimRTCIceCandidate(window) {
  4598. // foundation is arbitrarily chosen as an indicator for full support for
  4599. // https://w3c.github.io/webrtc-pc/#rtcicecandidate-interface
  4600. if (!window.RTCIceCandidate || (window.RTCIceCandidate && 'foundation' in
  4601. window.RTCIceCandidate.prototype)) {
  4602. return;
  4603. }
  4604. const NativeRTCIceCandidate = window.RTCIceCandidate;
  4605. window.RTCIceCandidate = function RTCIceCandidate(args) {
  4606. // Remove the a= which shouldn't be part of the candidate string.
  4607. if (typeof args === 'object' && args.candidate &&
  4608. args.candidate.indexOf('a=') === 0) {
  4609. args = JSON.parse(JSON.stringify(args));
  4610. args.candidate = args.candidate.substr(2);
  4611. }
  4612. if (args.candidate && args.candidate.length) {
  4613. // Augment the native candidate with the parsed fields.
  4614. const nativeCandidate = new NativeRTCIceCandidate(args);
  4615. const parsedCandidate = sdp.parseCandidate(args.candidate);
  4616. const augmentedCandidate = Object.assign(nativeCandidate,
  4617. parsedCandidate);
  4618. // Add a serializer that does not serialize the extra attributes.
  4619. augmentedCandidate.toJSON = function toJSON() {
  4620. return {
  4621. candidate: augmentedCandidate.candidate,
  4622. sdpMid: augmentedCandidate.sdpMid,
  4623. sdpMLineIndex: augmentedCandidate.sdpMLineIndex,
  4624. usernameFragment: augmentedCandidate.usernameFragment,
  4625. };
  4626. };
  4627. return augmentedCandidate;
  4628. }
  4629. return new NativeRTCIceCandidate(args);
  4630. };
  4631. window.RTCIceCandidate.prototype = NativeRTCIceCandidate.prototype;
  4632. // Hook up the augmented candidate in onicecandidate and
  4633. // addEventListener('icecandidate', ...)
  4634. wrapPeerConnectionEvent(window, 'icecandidate', e => {
  4635. if (e.candidate) {
  4636. Object.defineProperty(e, 'candidate', {
  4637. value: new window.RTCIceCandidate(e.candidate),
  4638. writable: 'false'
  4639. });
  4640. }
  4641. return e;
  4642. });
  4643. }
  4644. function shimMaxMessageSize(window, browserDetails) {
  4645. if (!window.RTCPeerConnection) {
  4646. return;
  4647. }
  4648. if (!('sctp' in window.RTCPeerConnection.prototype)) {
  4649. Object.defineProperty(window.RTCPeerConnection.prototype, 'sctp', {
  4650. get() {
  4651. return typeof this._sctp === 'undefined' ? null : this._sctp;
  4652. }
  4653. });
  4654. }
  4655. const sctpInDescription = function(description) {
  4656. if (!description || !description.sdp) {
  4657. return false;
  4658. }
  4659. const sections = sdp.splitSections(description.sdp);
  4660. sections.shift();
  4661. return sections.some(mediaSection => {
  4662. const mLine = sdp.parseMLine(mediaSection);
  4663. return mLine && mLine.kind === 'application'
  4664. && mLine.protocol.indexOf('SCTP') !== -1;
  4665. });
  4666. };
  4667. const getRemoteFirefoxVersion = function(description) {
  4668. // TODO: Is there a better solution for detecting Firefox?
  4669. const match = description.sdp.match(/mozilla...THIS_IS_SDPARTA-(\d+)/);
  4670. if (match === null || match.length < 2) {
  4671. return -1;
  4672. }
  4673. const version = parseInt(match[1], 10);
  4674. // Test for NaN (yes, this is ugly)
  4675. return version !== version ? -1 : version;
  4676. };
  4677. const getCanSendMaxMessageSize = function(remoteIsFirefox) {
  4678. // Every implementation we know can send at least 64 KiB.
  4679. // Note: Although Chrome is technically able to send up to 256 KiB, the
  4680. // data does not reach the other peer reliably.
  4681. // See: https://bugs.chromium.org/p/webrtc/issues/detail?id=8419
  4682. let canSendMaxMessageSize = 65536;
  4683. if (browserDetails.browser === 'firefox') {
  4684. if (browserDetails.version < 57) {
  4685. if (remoteIsFirefox === -1) {
  4686. // FF < 57 will send in 16 KiB chunks using the deprecated PPID
  4687. // fragmentation.
  4688. canSendMaxMessageSize = 16384;
  4689. } else {
  4690. // However, other FF (and RAWRTC) can reassemble PPID-fragmented
  4691. // messages. Thus, supporting ~2 GiB when sending.
  4692. canSendMaxMessageSize = 2147483637;
  4693. }
  4694. } else if (browserDetails.version < 60) {
  4695. // Currently, all FF >= 57 will reset the remote maximum message size
  4696. // to the default value when a data channel is created at a later
  4697. // stage. :(
  4698. // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1426831
  4699. canSendMaxMessageSize =
  4700. browserDetails.version === 57 ? 65535 : 65536;
  4701. } else {
  4702. // FF >= 60 supports sending ~2 GiB
  4703. canSendMaxMessageSize = 2147483637;
  4704. }
  4705. }
  4706. return canSendMaxMessageSize;
  4707. };
  4708. const getMaxMessageSize = function(description, remoteIsFirefox) {
  4709. // Note: 65536 bytes is the default value from the SDP spec. Also,
  4710. // every implementation we know supports receiving 65536 bytes.
  4711. let maxMessageSize = 65536;
  4712. // FF 57 has a slightly incorrect default remote max message size, so
  4713. // we need to adjust it here to avoid a failure when sending.
  4714. // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1425697
  4715. if (browserDetails.browser === 'firefox'
  4716. && browserDetails.version === 57) {
  4717. maxMessageSize = 65535;
  4718. }
  4719. const match = sdp.matchPrefix(description.sdp,
  4720. 'a=max-message-size:');
  4721. if (match.length > 0) {
  4722. maxMessageSize = parseInt(match[0].substr(19), 10);
  4723. } else if (browserDetails.browser === 'firefox' &&
  4724. remoteIsFirefox !== -1) {
  4725. // If the maximum message size is not present in the remote SDP and
  4726. // both local and remote are Firefox, the remote peer can receive
  4727. // ~2 GiB.
  4728. maxMessageSize = 2147483637;
  4729. }
  4730. return maxMessageSize;
  4731. };
  4732. const origSetRemoteDescription =
  4733. window.RTCPeerConnection.prototype.setRemoteDescription;
  4734. window.RTCPeerConnection.prototype.setRemoteDescription =
  4735. function setRemoteDescription() {
  4736. this._sctp = null;
  4737. // Chrome decided to not expose .sctp in plan-b mode.
  4738. // As usual, adapter.js has to do an 'ugly worakaround'
  4739. // to cover up the mess.
  4740. if (browserDetails.browser === 'chrome' && browserDetails.version >= 76) {
  4741. const {sdpSemantics} = this.getConfiguration();
  4742. if (sdpSemantics === 'plan-b') {
  4743. Object.defineProperty(this, 'sctp', {
  4744. get() {
  4745. return typeof this._sctp === 'undefined' ? null : this._sctp;
  4746. },
  4747. enumerable: true,
  4748. configurable: true,
  4749. });
  4750. }
  4751. }
  4752. if (sctpInDescription(arguments[0])) {
  4753. // Check if the remote is FF.
  4754. const isFirefox = getRemoteFirefoxVersion(arguments[0]);
  4755. // Get the maximum message size the local peer is capable of sending
  4756. const canSendMMS = getCanSendMaxMessageSize(isFirefox);
  4757. // Get the maximum message size of the remote peer.
  4758. const remoteMMS = getMaxMessageSize(arguments[0], isFirefox);
  4759. // Determine final maximum message size
  4760. let maxMessageSize;
  4761. if (canSendMMS === 0 && remoteMMS === 0) {
  4762. maxMessageSize = Number.POSITIVE_INFINITY;
  4763. } else if (canSendMMS === 0 || remoteMMS === 0) {
  4764. maxMessageSize = Math.max(canSendMMS, remoteMMS);
  4765. } else {
  4766. maxMessageSize = Math.min(canSendMMS, remoteMMS);
  4767. }
  4768. // Create a dummy RTCSctpTransport object and the 'maxMessageSize'
  4769. // attribute.
  4770. const sctp = {};
  4771. Object.defineProperty(sctp, 'maxMessageSize', {
  4772. get() {
  4773. return maxMessageSize;
  4774. }
  4775. });
  4776. this._sctp = sctp;
  4777. }
  4778. return origSetRemoteDescription.apply(this, arguments);
  4779. };
  4780. }
  4781. function shimSendThrowTypeError(window) {
  4782. if (!(window.RTCPeerConnection &&
  4783. 'createDataChannel' in window.RTCPeerConnection.prototype)) {
  4784. return;
  4785. }
  4786. // Note: Although Firefox >= 57 has a native implementation, the maximum
  4787. // message size can be reset for all data channels at a later stage.
  4788. // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1426831
  4789. function wrapDcSend(dc, pc) {
  4790. const origDataChannelSend = dc.send;
  4791. dc.send = function send() {
  4792. const data = arguments[0];
  4793. const length = data.length || data.size || data.byteLength;
  4794. if (dc.readyState === 'open' &&
  4795. pc.sctp && length > pc.sctp.maxMessageSize) {
  4796. throw new TypeError('Message too large (can send a maximum of ' +
  4797. pc.sctp.maxMessageSize + ' bytes)');
  4798. }
  4799. return origDataChannelSend.apply(dc, arguments);
  4800. };
  4801. }
  4802. const origCreateDataChannel =
  4803. window.RTCPeerConnection.prototype.createDataChannel;
  4804. window.RTCPeerConnection.prototype.createDataChannel =
  4805. function createDataChannel() {
  4806. const dataChannel = origCreateDataChannel.apply(this, arguments);
  4807. wrapDcSend(dataChannel, this);
  4808. return dataChannel;
  4809. };
  4810. wrapPeerConnectionEvent(window, 'datachannel', e => {
  4811. wrapDcSend(e.channel, e.target);
  4812. return e;
  4813. });
  4814. }
  4815. /* shims RTCConnectionState by pretending it is the same as iceConnectionState.
  4816. * See https://bugs.chromium.org/p/webrtc/issues/detail?id=6145#c12
  4817. * for why this is a valid hack in Chrome. In Firefox it is slightly incorrect
  4818. * since DTLS failures would be hidden. See
  4819. * https://bugzilla.mozilla.org/show_bug.cgi?id=1265827
  4820. * for the Firefox tracking bug.
  4821. */
  4822. function shimConnectionState(window) {
  4823. if (!window.RTCPeerConnection ||
  4824. 'connectionState' in window.RTCPeerConnection.prototype) {
  4825. return;
  4826. }
  4827. const proto = window.RTCPeerConnection.prototype;
  4828. Object.defineProperty(proto, 'connectionState', {
  4829. get() {
  4830. return {
  4831. completed: 'connected',
  4832. checking: 'connecting'
  4833. }[this.iceConnectionState] || this.iceConnectionState;
  4834. },
  4835. enumerable: true,
  4836. configurable: true
  4837. });
  4838. Object.defineProperty(proto, 'onconnectionstatechange', {
  4839. get() {
  4840. return this._onconnectionstatechange || null;
  4841. },
  4842. set(cb) {
  4843. if (this._onconnectionstatechange) {
  4844. this.removeEventListener('connectionstatechange',
  4845. this._onconnectionstatechange);
  4846. delete this._onconnectionstatechange;
  4847. }
  4848. if (cb) {
  4849. this.addEventListener('connectionstatechange',
  4850. this._onconnectionstatechange = cb);
  4851. }
  4852. },
  4853. enumerable: true,
  4854. configurable: true
  4855. });
  4856. ['setLocalDescription', 'setRemoteDescription'].forEach((method) => {
  4857. const origMethod = proto[method];
  4858. proto[method] = function() {
  4859. if (!this._connectionstatechangepoly) {
  4860. this._connectionstatechangepoly = e => {
  4861. const pc = e.target;
  4862. if (pc._lastConnectionState !== pc.connectionState) {
  4863. pc._lastConnectionState = pc.connectionState;
  4864. const newEvent = new Event('connectionstatechange', e);
  4865. pc.dispatchEvent(newEvent);
  4866. }
  4867. return e;
  4868. };
  4869. this.addEventListener('iceconnectionstatechange',
  4870. this._connectionstatechangepoly);
  4871. }
  4872. return origMethod.apply(this, arguments);
  4873. };
  4874. });
  4875. }
  4876. function removeExtmapAllowMixed(window, browserDetails) {
  4877. /* remove a=extmap-allow-mixed for webrtc.org < M71 */
  4878. if (!window.RTCPeerConnection) {
  4879. return;
  4880. }
  4881. if (browserDetails.browser === 'chrome' && browserDetails.version >= 71) {
  4882. return;
  4883. }
  4884. if (browserDetails.browser === 'safari' && browserDetails.version >= 605) {
  4885. return;
  4886. }
  4887. const nativeSRD = window.RTCPeerConnection.prototype.setRemoteDescription;
  4888. window.RTCPeerConnection.prototype.setRemoteDescription =
  4889. function setRemoteDescription(desc) {
  4890. if (desc && desc.sdp && desc.sdp.indexOf('\na=extmap-allow-mixed') !== -1) {
  4891. const sdp = desc.sdp.split('\n').filter((line) => {
  4892. return line.trim() !== 'a=extmap-allow-mixed';
  4893. }).join('\n');
  4894. // Safari enforces read-only-ness of RTCSessionDescription fields.
  4895. if (window.RTCSessionDescription &&
  4896. desc instanceof window.RTCSessionDescription) {
  4897. arguments[0] = new window.RTCSessionDescription({
  4898. type: desc.type,
  4899. sdp,
  4900. });
  4901. } else {
  4902. desc.sdp = sdp;
  4903. }
  4904. }
  4905. return nativeSRD.apply(this, arguments);
  4906. };
  4907. }
  4908. function shimAddIceCandidateNullOrEmpty(window, browserDetails) {
  4909. // Support for addIceCandidate(null or undefined)
  4910. // as well as addIceCandidate({candidate: "", ...})
  4911. // https://bugs.chromium.org/p/chromium/issues/detail?id=978582
  4912. // Note: must be called before other polyfills which change the signature.
  4913. if (!(window.RTCPeerConnection && window.RTCPeerConnection.prototype)) {
  4914. return;
  4915. }
  4916. const nativeAddIceCandidate =
  4917. window.RTCPeerConnection.prototype.addIceCandidate;
  4918. if (!nativeAddIceCandidate || nativeAddIceCandidate.length === 0) {
  4919. return;
  4920. }
  4921. window.RTCPeerConnection.prototype.addIceCandidate =
  4922. function addIceCandidate() {
  4923. if (!arguments[0]) {
  4924. if (arguments[1]) {
  4925. arguments[1].apply(null);
  4926. }
  4927. return Promise.resolve();
  4928. }
  4929. // Firefox 68+ emits and processes {candidate: "", ...}, ignore
  4930. // in older versions.
  4931. // Native support for ignoring exists for Chrome M77+.
  4932. // Safari ignores as well, exact version unknown but works in the same
  4933. // version that also ignores addIceCandidate(null).
  4934. if (((browserDetails.browser === 'chrome' && browserDetails.version < 78)
  4935. || (browserDetails.browser === 'firefox'
  4936. && browserDetails.version < 68)
  4937. || (browserDetails.browser === 'safari'))
  4938. && arguments[0] && arguments[0].candidate === '') {
  4939. return Promise.resolve();
  4940. }
  4941. return nativeAddIceCandidate.apply(this, arguments);
  4942. };
  4943. }
  4944. var commonShim = /*#__PURE__*/Object.freeze({
  4945. __proto__: null,
  4946. shimRTCIceCandidate: shimRTCIceCandidate,
  4947. shimMaxMessageSize: shimMaxMessageSize,
  4948. shimSendThrowTypeError: shimSendThrowTypeError,
  4949. shimConnectionState: shimConnectionState,
  4950. removeExtmapAllowMixed: removeExtmapAllowMixed,
  4951. shimAddIceCandidateNullOrEmpty: shimAddIceCandidateNullOrEmpty
  4952. });
  4953. /*
  4954. * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
  4955. *
  4956. * Use of this source code is governed by a BSD-style license
  4957. * that can be found in the LICENSE file in the root of the source
  4958. * tree.
  4959. */
  4960. // Shimming starts here.
  4961. function adapterFactory({window} = {}, options = {
  4962. shimChrome: true,
  4963. shimFirefox: true,
  4964. shimEdge: true,
  4965. shimSafari: true,
  4966. }) {
  4967. // Utils.
  4968. const logging = log$1;
  4969. const browserDetails = detectBrowser(window);
  4970. const adapter = {
  4971. browserDetails,
  4972. commonShim,
  4973. extractVersion: extractVersion,
  4974. disableLog: disableLog,
  4975. disableWarnings: disableWarnings
  4976. };
  4977. // Shim browser if found.
  4978. switch (browserDetails.browser) {
  4979. case 'chrome':
  4980. if (!chromeShim || !shimPeerConnection$2 ||
  4981. !options.shimChrome) {
  4982. logging('Chrome shim is not included in this adapter release.');
  4983. return adapter;
  4984. }
  4985. if (browserDetails.version === null) {
  4986. logging('Chrome shim can not determine version, not shimming.');
  4987. return adapter;
  4988. }
  4989. logging('adapter.js shimming chrome.');
  4990. // Export to the adapter global object visible in the browser.
  4991. adapter.browserShim = chromeShim;
  4992. // Must be called before shimPeerConnection.
  4993. shimAddIceCandidateNullOrEmpty(window, browserDetails);
  4994. shimGetUserMedia$3(window, browserDetails);
  4995. shimMediaStream(window);
  4996. shimPeerConnection$2(window, browserDetails);
  4997. shimOnTrack$1(window);
  4998. shimAddTrackRemoveTrack(window, browserDetails);
  4999. shimGetSendersWithDtmf(window);
  5000. shimGetStats(window);
  5001. shimSenderReceiverGetStats(window);
  5002. fixNegotiationNeeded(window, browserDetails);
  5003. shimRTCIceCandidate(window);
  5004. shimConnectionState(window);
  5005. shimMaxMessageSize(window, browserDetails);
  5006. shimSendThrowTypeError(window);
  5007. removeExtmapAllowMixed(window, browserDetails);
  5008. break;
  5009. case 'firefox':
  5010. if (!firefoxShim || !shimPeerConnection ||
  5011. !options.shimFirefox) {
  5012. logging('Firefox shim is not included in this adapter release.');
  5013. return adapter;
  5014. }
  5015. logging('adapter.js shimming firefox.');
  5016. // Export to the adapter global object visible in the browser.
  5017. adapter.browserShim = firefoxShim;
  5018. // Must be called before shimPeerConnection.
  5019. shimAddIceCandidateNullOrEmpty(window, browserDetails);
  5020. shimGetUserMedia$1(window, browserDetails);
  5021. shimPeerConnection(window, browserDetails);
  5022. shimOnTrack(window);
  5023. shimRemoveStream(window);
  5024. shimSenderGetStats(window);
  5025. shimReceiverGetStats(window);
  5026. shimRTCDataChannel(window);
  5027. shimAddTransceiver(window);
  5028. shimGetParameters(window);
  5029. shimCreateOffer(window);
  5030. shimCreateAnswer(window);
  5031. shimRTCIceCandidate(window);
  5032. shimConnectionState(window);
  5033. shimMaxMessageSize(window, browserDetails);
  5034. shimSendThrowTypeError(window);
  5035. break;
  5036. case 'edge':
  5037. if (!edgeShim || !shimPeerConnection$1 || !options.shimEdge) {
  5038. logging('MS edge shim is not included in this adapter release.');
  5039. return adapter;
  5040. }
  5041. logging('adapter.js shimming edge.');
  5042. // Export to the adapter global object visible in the browser.
  5043. adapter.browserShim = edgeShim;
  5044. shimGetUserMedia$2(window);
  5045. shimGetDisplayMedia$1(window);
  5046. shimPeerConnection$1(window, browserDetails);
  5047. shimReplaceTrack(window);
  5048. // the edge shim implements the full RTCIceCandidate object.
  5049. shimMaxMessageSize(window, browserDetails);
  5050. shimSendThrowTypeError(window);
  5051. break;
  5052. case 'safari':
  5053. if (!safariShim || !options.shimSafari) {
  5054. logging('Safari shim is not included in this adapter release.');
  5055. return adapter;
  5056. }
  5057. logging('adapter.js shimming safari.');
  5058. // Export to the adapter global object visible in the browser.
  5059. adapter.browserShim = safariShim;
  5060. // Must be called before shimCallbackAPI.
  5061. shimAddIceCandidateNullOrEmpty(window, browserDetails);
  5062. shimRTCIceServerUrls(window);
  5063. shimCreateOfferLegacy(window);
  5064. shimCallbacksAPI(window);
  5065. shimLocalStreamsAPI(window);
  5066. shimRemoteStreamsAPI(window);
  5067. shimTrackEventTransceiver(window);
  5068. shimGetUserMedia(window);
  5069. shimAudioContext(window);
  5070. shimRTCIceCandidate(window);
  5071. shimMaxMessageSize(window, browserDetails);
  5072. shimSendThrowTypeError(window);
  5073. removeExtmapAllowMixed(window, browserDetails);
  5074. break;
  5075. default:
  5076. logging('Unsupported browser!');
  5077. break;
  5078. }
  5079. return adapter;
  5080. }
  5081. /*
  5082. * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
  5083. *
  5084. * Use of this source code is governed by a BSD-style license
  5085. * that can be found in the LICENSE file in the root of the source
  5086. * tree.
  5087. */
  5088. adapterFactory({window: typeof window === 'undefined' ? undefined : window});
  5089. /**
  5090. * @class AudioTrackConstraints
  5091. * @classDesc Constraints for creating an audio MediaStreamTrack.
  5092. * @memberof Owt.Base
  5093. * @constructor
  5094. * @param {Owt.Base.AudioSourceInfo} source Source info of this audio track.
  5095. */
  5096. class AudioTrackConstraints {
  5097. // eslint-disable-next-line require-jsdoc
  5098. constructor(source) {
  5099. if (!Object.values(AudioSourceInfo).some(v => v === source)) {
  5100. throw new TypeError('Invalid source.');
  5101. }
  5102. /**
  5103. * @member {string} source
  5104. * @memberof Owt.Base.AudioTrackConstraints
  5105. * @desc Values could be "mic", "screen-cast", "file" or "mixed".
  5106. * @instance
  5107. */
  5108. this.source = source;
  5109. /**
  5110. * @member {string} deviceId
  5111. * @memberof Owt.Base.AudioTrackConstraints
  5112. * @desc Do not provide deviceId if source is not "mic".
  5113. * @instance
  5114. * @see https://w3c.github.io/mediacapture-main/#def-constraint-deviceId
  5115. */
  5116. this.deviceId = undefined;
  5117. }
  5118. }
  5119. /**
  5120. * @class VideoTrackConstraints
  5121. * @classDesc Constraints for creating a video MediaStreamTrack.
  5122. * @memberof Owt.Base
  5123. * @constructor
  5124. * @param {Owt.Base.VideoSourceInfo} source Source info of this video track.
  5125. */
  5126. class VideoTrackConstraints {
  5127. // eslint-disable-next-line require-jsdoc
  5128. constructor(source) {
  5129. if (!Object.values(VideoSourceInfo).some(v => v === source)) {
  5130. throw new TypeError('Invalid source.');
  5131. }
  5132. /**
  5133. * @member {string} source
  5134. * @memberof Owt.Base.VideoTrackConstraints
  5135. * @desc Values could be "camera", "screen-cast", "file" or "mixed".
  5136. * @instance
  5137. */
  5138. this.source = source;
  5139. /**
  5140. * @member {string} deviceId
  5141. * @memberof Owt.Base.VideoTrackConstraints
  5142. * @desc Do not provide deviceId if source is not "camera".
  5143. * @instance
  5144. * @see https://w3c.github.io/mediacapture-main/#def-constraint-deviceId
  5145. */
  5146. this.deviceId = undefined;
  5147. /**
  5148. * @member {Owt.Base.Resolution} resolution
  5149. * @memberof Owt.Base.VideoTrackConstraints
  5150. * @instance
  5151. */
  5152. this.resolution = undefined;
  5153. /**
  5154. * @member {number} frameRate
  5155. * @memberof Owt.Base.VideoTrackConstraints
  5156. * @instance
  5157. */
  5158. this.frameRate = undefined;
  5159. }
  5160. }
  5161. /**
  5162. * @class StreamConstraints
  5163. * @classDesc Constraints for creating a MediaStream from screen mic and camera.
  5164. * @memberof Owt.Base
  5165. * @constructor
  5166. * @param {?Owt.Base.AudioTrackConstraints} audioConstraints
  5167. * @param {?Owt.Base.VideoTrackConstraints} videoConstraints
  5168. */
  5169. class StreamConstraints {
  5170. // eslint-disable-next-line require-jsdoc
  5171. constructor(audioConstraints = false, videoConstraints = false) {
  5172. /**
  5173. * @member {Owt.Base.MediaStreamTrackDeviceConstraintsForAudio} audio
  5174. * @memberof Owt.Base.MediaStreamDeviceConstraints
  5175. * @instance
  5176. */
  5177. this.audio = audioConstraints;
  5178. /**
  5179. * @member {Owt.Base.MediaStreamTrackDeviceConstraintsForVideo} Video
  5180. * @memberof Owt.Base.MediaStreamDeviceConstraints
  5181. * @instance
  5182. */
  5183. this.video = videoConstraints;
  5184. }
  5185. } // eslint-disable-next-line require-jsdoc
  5186. function isVideoConstrainsForScreenCast(constraints) {
  5187. return typeof constraints.video === 'object' && constraints.video.source === VideoSourceInfo.SCREENCAST;
  5188. }
  5189. /**
  5190. * @class MediaStreamFactory
  5191. * @classDesc A factory to create MediaStream. You can also create MediaStream by yourself.
  5192. * @memberof Owt.Base
  5193. */
  5194. class MediaStreamFactory {
  5195. /**
  5196. * @function createMediaStream
  5197. * @static
  5198. * @desc Create a MediaStream with given constraints. If you want to create a MediaStream for screen cast, please make sure both audio and video's source are "screen-cast".
  5199. * @memberof Owt.Base.MediaStreamFactory
  5200. * @return {Promise<MediaStream, Error>} Return a promise that is resolved when stream is successfully created, or rejected if one of the following error happened:
  5201. * - One or more parameters cannot be satisfied.
  5202. * - Specified device is busy.
  5203. * - Cannot obtain necessary permission or operation is canceled by user.
  5204. * - Video source is screen cast, while audio source is not.
  5205. * - Audio source is screen cast, while video source is disabled.
  5206. * @param {Owt.Base.StreamConstraints} constraints
  5207. */
  5208. static createMediaStream(constraints) {
  5209. if (typeof constraints !== 'object' || !constraints.audio && !constraints.video) {
  5210. return Promise.reject(new TypeError('Invalid constrains'));
  5211. }
  5212. if (!isVideoConstrainsForScreenCast(constraints) && typeof constraints.audio === 'object' && constraints.audio.source === AudioSourceInfo.SCREENCAST) {
  5213. return Promise.reject(new TypeError('Cannot share screen without video.'));
  5214. }
  5215. if (isVideoConstrainsForScreenCast(constraints) && !isChrome() && !isFirefox()) {
  5216. return Promise.reject(new TypeError('Screen sharing only supports Chrome and Firefox.'));
  5217. }
  5218. if (isVideoConstrainsForScreenCast(constraints) && typeof constraints.audio === 'object' && constraints.audio.source !== AudioSourceInfo.SCREENCAST) {
  5219. return Promise.reject(new TypeError('Cannot capture video from screen cast while capture audio from' + ' other source.'));
  5220. } // Check and convert constraints.
  5221. if (!constraints.audio && !constraints.video) {
  5222. return Promise.reject(new TypeError('At least one of audio and video must be requested.'));
  5223. }
  5224. const mediaConstraints = Object.create({});
  5225. if (typeof constraints.audio === 'object' && constraints.audio.source === AudioSourceInfo.MIC) {
  5226. mediaConstraints.audio = Object.create({});
  5227. if (isEdge()) {
  5228. mediaConstraints.audio.deviceId = constraints.audio.deviceId;
  5229. } else {
  5230. mediaConstraints.audio.deviceId = {
  5231. exact: constraints.audio.deviceId
  5232. };
  5233. }
  5234. } else {
  5235. if (constraints.audio.source === AudioSourceInfo.SCREENCAST) {
  5236. mediaConstraints.audio = true;
  5237. } else {
  5238. mediaConstraints.audio = constraints.audio;
  5239. }
  5240. }
  5241. if (typeof constraints.video === 'object') {
  5242. mediaConstraints.video = Object.create({});
  5243. if (typeof constraints.video.frameRate === 'number') {
  5244. mediaConstraints.video.frameRate = constraints.video.frameRate;
  5245. }
  5246. if (constraints.video.resolution && constraints.video.resolution.width && constraints.video.resolution.height) {
  5247. if (constraints.video.source === VideoSourceInfo.SCREENCAST) {
  5248. mediaConstraints.video.width = constraints.video.resolution.width;
  5249. mediaConstraints.video.height = constraints.video.resolution.height;
  5250. } else {
  5251. mediaConstraints.video.width = Object.create({});
  5252. mediaConstraints.video.width.exact = constraints.video.resolution.width;
  5253. mediaConstraints.video.height = Object.create({});
  5254. mediaConstraints.video.height.exact = constraints.video.resolution.height;
  5255. }
  5256. }
  5257. if (typeof constraints.video.deviceId === 'string') {
  5258. mediaConstraints.video.deviceId = {
  5259. exact: constraints.video.deviceId
  5260. };
  5261. }
  5262. if (isFirefox() && constraints.video.source === VideoSourceInfo.SCREENCAST) {
  5263. mediaConstraints.video.mediaSource = 'screen';
  5264. }
  5265. } else {
  5266. mediaConstraints.video = constraints.video;
  5267. }
  5268. if (isVideoConstrainsForScreenCast(constraints)) {
  5269. return navigator.mediaDevices.getDisplayMedia(mediaConstraints);
  5270. } else {
  5271. return navigator.mediaDevices.getUserMedia(mediaConstraints);
  5272. }
  5273. }
  5274. }
  5275. // Copyright (C) <2018> Intel Corporation
  5276. var media = /*#__PURE__*/Object.freeze({
  5277. __proto__: null,
  5278. AudioTrackConstraints: AudioTrackConstraints,
  5279. VideoTrackConstraints: VideoTrackConstraints,
  5280. StreamConstraints: StreamConstraints,
  5281. MediaStreamFactory: MediaStreamFactory,
  5282. AudioSourceInfo: AudioSourceInfo,
  5283. VideoSourceInfo: VideoSourceInfo,
  5284. TrackKind: TrackKind,
  5285. Resolution: Resolution
  5286. });
  5287. let logger;
  5288. let errorLogger;
  5289. function setLogger() {
  5290. /*eslint-disable */
  5291. logger = console.log;
  5292. errorLogger = console.error;
  5293. /*eslint-enable */
  5294. }
  5295. function log(message, ...optionalParams) {
  5296. if (logger) {
  5297. logger(message, ...optionalParams);
  5298. }
  5299. }
  5300. function error(message, ...optionalParams) {
  5301. if (errorLogger) {
  5302. errorLogger(message, ...optionalParams);
  5303. }
  5304. // todo 触发on error 事件
  5305. }
  5306. class Event$1 {
  5307. constructor(type) {
  5308. this.listener = {};
  5309. this.type = type | '';
  5310. }
  5311. on(event, fn) {
  5312. if (!this.listener[event]) {
  5313. this.listener[event] = [];
  5314. }
  5315. this.listener[event].push(fn);
  5316. return true;
  5317. }
  5318. off(event, fn) {
  5319. if (this.listener[event]) {
  5320. var index = this.listener[event].indexOf(fn);
  5321. if (index > -1) {
  5322. this.listener[event].splice(index, 1);
  5323. }
  5324. return true;
  5325. }
  5326. return false;
  5327. }
  5328. offAll() {
  5329. this.listener = {};
  5330. }
  5331. dispatch(event, data) {
  5332. if (this.listener[event]) {
  5333. this.listener[event].map(each => {
  5334. each.apply(null, [data]);
  5335. });
  5336. return true;
  5337. }
  5338. return false;
  5339. }
  5340. }
  5341. var bind = function bind(fn, thisArg) {
  5342. return function wrap() {
  5343. var args = new Array(arguments.length);
  5344. for (var i = 0; i < args.length; i++) {
  5345. args[i] = arguments[i];
  5346. }
  5347. return fn.apply(thisArg, args);
  5348. };
  5349. };
  5350. // utils is a library of generic helper functions non-specific to axios
  5351. var toString = Object.prototype.toString;
  5352. // eslint-disable-next-line func-names
  5353. var kindOf = (function(cache) {
  5354. // eslint-disable-next-line func-names
  5355. return function(thing) {
  5356. var str = toString.call(thing);
  5357. return cache[str] || (cache[str] = str.slice(8, -1).toLowerCase());
  5358. };
  5359. })(Object.create(null));
  5360. function kindOfTest(type) {
  5361. type = type.toLowerCase();
  5362. return function isKindOf(thing) {
  5363. return kindOf(thing) === type;
  5364. };
  5365. }
  5366. /**
  5367. * Determine if a value is an Array
  5368. *
  5369. * @param {Object} val The value to test
  5370. * @returns {boolean} True if value is an Array, otherwise false
  5371. */
  5372. function isArray(val) {
  5373. return Array.isArray(val);
  5374. }
  5375. /**
  5376. * Determine if a value is undefined
  5377. *
  5378. * @param {Object} val The value to test
  5379. * @returns {boolean} True if the value is undefined, otherwise false
  5380. */
  5381. function isUndefined(val) {
  5382. return typeof val === 'undefined';
  5383. }
  5384. /**
  5385. * Determine if a value is a Buffer
  5386. *
  5387. * @param {Object} val The value to test
  5388. * @returns {boolean} True if value is a Buffer, otherwise false
  5389. */
  5390. function isBuffer(val) {
  5391. return val !== null && !isUndefined(val) && val.constructor !== null && !isUndefined(val.constructor)
  5392. && typeof val.constructor.isBuffer === 'function' && val.constructor.isBuffer(val);
  5393. }
  5394. /**
  5395. * Determine if a value is an ArrayBuffer
  5396. *
  5397. * @function
  5398. * @param {Object} val The value to test
  5399. * @returns {boolean} True if value is an ArrayBuffer, otherwise false
  5400. */
  5401. var isArrayBuffer = kindOfTest('ArrayBuffer');
  5402. /**
  5403. * Determine if a value is a view on an ArrayBuffer
  5404. *
  5405. * @param {Object} val The value to test
  5406. * @returns {boolean} True if value is a view on an ArrayBuffer, otherwise false
  5407. */
  5408. function isArrayBufferView(val) {
  5409. var result;
  5410. if ((typeof ArrayBuffer !== 'undefined') && (ArrayBuffer.isView)) {
  5411. result = ArrayBuffer.isView(val);
  5412. } else {
  5413. result = (val) && (val.buffer) && (isArrayBuffer(val.buffer));
  5414. }
  5415. return result;
  5416. }
  5417. /**
  5418. * Determine if a value is a String
  5419. *
  5420. * @param {Object} val The value to test
  5421. * @returns {boolean} True if value is a String, otherwise false
  5422. */
  5423. function isString(val) {
  5424. return typeof val === 'string';
  5425. }
  5426. /**
  5427. * Determine if a value is a Number
  5428. *
  5429. * @param {Object} val The value to test
  5430. * @returns {boolean} True if value is a Number, otherwise false
  5431. */
  5432. function isNumber(val) {
  5433. return typeof val === 'number';
  5434. }
  5435. /**
  5436. * Determine if a value is an Object
  5437. *
  5438. * @param {Object} val The value to test
  5439. * @returns {boolean} True if value is an Object, otherwise false
  5440. */
  5441. function isObject(val) {
  5442. return val !== null && typeof val === 'object';
  5443. }
  5444. /**
  5445. * Determine if a value is a plain Object
  5446. *
  5447. * @param {Object} val The value to test
  5448. * @return {boolean} True if value is a plain Object, otherwise false
  5449. */
  5450. function isPlainObject(val) {
  5451. if (kindOf(val) !== 'object') {
  5452. return false;
  5453. }
  5454. var prototype = Object.getPrototypeOf(val);
  5455. return prototype === null || prototype === Object.prototype;
  5456. }
  5457. /**
  5458. * Determine if a value is a Date
  5459. *
  5460. * @function
  5461. * @param {Object} val The value to test
  5462. * @returns {boolean} True if value is a Date, otherwise false
  5463. */
  5464. var isDate = kindOfTest('Date');
  5465. /**
  5466. * Determine if a value is a File
  5467. *
  5468. * @function
  5469. * @param {Object} val The value to test
  5470. * @returns {boolean} True if value is a File, otherwise false
  5471. */
  5472. var isFile = kindOfTest('File');
  5473. /**
  5474. * Determine if a value is a Blob
  5475. *
  5476. * @function
  5477. * @param {Object} val The value to test
  5478. * @returns {boolean} True if value is a Blob, otherwise false
  5479. */
  5480. var isBlob = kindOfTest('Blob');
  5481. /**
  5482. * Determine if a value is a FileList
  5483. *
  5484. * @function
  5485. * @param {Object} val The value to test
  5486. * @returns {boolean} True if value is a File, otherwise false
  5487. */
  5488. var isFileList = kindOfTest('FileList');
  5489. /**
  5490. * Determine if a value is a Function
  5491. *
  5492. * @param {Object} val The value to test
  5493. * @returns {boolean} True if value is a Function, otherwise false
  5494. */
  5495. function isFunction(val) {
  5496. return toString.call(val) === '[object Function]';
  5497. }
  5498. /**
  5499. * Determine if a value is a Stream
  5500. *
  5501. * @param {Object} val The value to test
  5502. * @returns {boolean} True if value is a Stream, otherwise false
  5503. */
  5504. function isStream(val) {
  5505. return isObject(val) && isFunction(val.pipe);
  5506. }
  5507. /**
  5508. * Determine if a value is a FormData
  5509. *
  5510. * @param {Object} thing The value to test
  5511. * @returns {boolean} True if value is an FormData, otherwise false
  5512. */
  5513. function isFormData(thing) {
  5514. var pattern = '[object FormData]';
  5515. return thing && (
  5516. (typeof FormData === 'function' && thing instanceof FormData) ||
  5517. toString.call(thing) === pattern ||
  5518. (isFunction(thing.toString) && thing.toString() === pattern)
  5519. );
  5520. }
  5521. /**
  5522. * Determine if a value is a URLSearchParams object
  5523. * @function
  5524. * @param {Object} val The value to test
  5525. * @returns {boolean} True if value is a URLSearchParams object, otherwise false
  5526. */
  5527. var isURLSearchParams = kindOfTest('URLSearchParams');
  5528. /**
  5529. * Trim excess whitespace off the beginning and end of a string
  5530. *
  5531. * @param {String} str The String to trim
  5532. * @returns {String} The String freed of excess whitespace
  5533. */
  5534. function trim(str) {
  5535. return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, '');
  5536. }
  5537. /**
  5538. * Determine if we're running in a standard browser environment
  5539. *
  5540. * This allows axios to run in a web worker, and react-native.
  5541. * Both environments support XMLHttpRequest, but not fully standard globals.
  5542. *
  5543. * web workers:
  5544. * typeof window -> undefined
  5545. * typeof document -> undefined
  5546. *
  5547. * react-native:
  5548. * navigator.product -> 'ReactNative'
  5549. * nativescript
  5550. * navigator.product -> 'NativeScript' or 'NS'
  5551. */
  5552. function isStandardBrowserEnv() {
  5553. if (typeof navigator !== 'undefined' && (navigator.product === 'ReactNative' ||
  5554. navigator.product === 'NativeScript' ||
  5555. navigator.product === 'NS')) {
  5556. return false;
  5557. }
  5558. return (
  5559. typeof window !== 'undefined' &&
  5560. typeof document !== 'undefined'
  5561. );
  5562. }
  5563. /**
  5564. * Iterate over an Array or an Object invoking a function for each item.
  5565. *
  5566. * If `obj` is an Array callback will be called passing
  5567. * the value, index, and complete array for each item.
  5568. *
  5569. * If 'obj' is an Object callback will be called passing
  5570. * the value, key, and complete object for each property.
  5571. *
  5572. * @param {Object|Array} obj The object to iterate
  5573. * @param {Function} fn The callback to invoke for each item
  5574. */
  5575. function forEach(obj, fn) {
  5576. // Don't bother if no value provided
  5577. if (obj === null || typeof obj === 'undefined') {
  5578. return;
  5579. }
  5580. // Force an array if not already something iterable
  5581. if (typeof obj !== 'object') {
  5582. /*eslint no-param-reassign:0*/
  5583. obj = [obj];
  5584. }
  5585. if (isArray(obj)) {
  5586. // Iterate over array values
  5587. for (var i = 0, l = obj.length; i < l; i++) {
  5588. fn.call(null, obj[i], i, obj);
  5589. }
  5590. } else {
  5591. // Iterate over object keys
  5592. for (var key in obj) {
  5593. if (Object.prototype.hasOwnProperty.call(obj, key)) {
  5594. fn.call(null, obj[key], key, obj);
  5595. }
  5596. }
  5597. }
  5598. }
  5599. /**
  5600. * Accepts varargs expecting each argument to be an object, then
  5601. * immutably merges the properties of each object and returns result.
  5602. *
  5603. * When multiple objects contain the same key the later object in
  5604. * the arguments list will take precedence.
  5605. *
  5606. * Example:
  5607. *
  5608. * ```js
  5609. * var result = merge({foo: 123}, {foo: 456});
  5610. * console.log(result.foo); // outputs 456
  5611. * ```
  5612. *
  5613. * @param {Object} obj1 Object to merge
  5614. * @returns {Object} Result of all merge properties
  5615. */
  5616. function merge(/* obj1, obj2, obj3, ... */) {
  5617. var result = {};
  5618. function assignValue(val, key) {
  5619. if (isPlainObject(result[key]) && isPlainObject(val)) {
  5620. result[key] = merge(result[key], val);
  5621. } else if (isPlainObject(val)) {
  5622. result[key] = merge({}, val);
  5623. } else if (isArray(val)) {
  5624. result[key] = val.slice();
  5625. } else {
  5626. result[key] = val;
  5627. }
  5628. }
  5629. for (var i = 0, l = arguments.length; i < l; i++) {
  5630. forEach(arguments[i], assignValue);
  5631. }
  5632. return result;
  5633. }
  5634. /**
  5635. * Extends object a by mutably adding to it the properties of object b.
  5636. *
  5637. * @param {Object} a The object to be extended
  5638. * @param {Object} b The object to copy properties from
  5639. * @param {Object} thisArg The object to bind function to
  5640. * @return {Object} The resulting value of object a
  5641. */
  5642. function extend(a, b, thisArg) {
  5643. forEach(b, function assignValue(val, key) {
  5644. if (thisArg && typeof val === 'function') {
  5645. a[key] = bind(val, thisArg);
  5646. } else {
  5647. a[key] = val;
  5648. }
  5649. });
  5650. return a;
  5651. }
  5652. /**
  5653. * Remove byte order marker. This catches EF BB BF (the UTF-8 BOM)
  5654. *
  5655. * @param {string} content with BOM
  5656. * @return {string} content value without BOM
  5657. */
  5658. function stripBOM(content) {
  5659. if (content.charCodeAt(0) === 0xFEFF) {
  5660. content = content.slice(1);
  5661. }
  5662. return content;
  5663. }
  5664. /**
  5665. * Inherit the prototype methods from one constructor into another
  5666. * @param {function} constructor
  5667. * @param {function} superConstructor
  5668. * @param {object} [props]
  5669. * @param {object} [descriptors]
  5670. */
  5671. function inherits(constructor, superConstructor, props, descriptors) {
  5672. constructor.prototype = Object.create(superConstructor.prototype, descriptors);
  5673. constructor.prototype.constructor = constructor;
  5674. props && Object.assign(constructor.prototype, props);
  5675. }
  5676. /**
  5677. * Resolve object with deep prototype chain to a flat object
  5678. * @param {Object} sourceObj source object
  5679. * @param {Object} [destObj]
  5680. * @param {Function} [filter]
  5681. * @returns {Object}
  5682. */
  5683. function toFlatObject(sourceObj, destObj, filter) {
  5684. var props;
  5685. var i;
  5686. var prop;
  5687. var merged = {};
  5688. destObj = destObj || {};
  5689. do {
  5690. props = Object.getOwnPropertyNames(sourceObj);
  5691. i = props.length;
  5692. while (i-- > 0) {
  5693. prop = props[i];
  5694. if (!merged[prop]) {
  5695. destObj[prop] = sourceObj[prop];
  5696. merged[prop] = true;
  5697. }
  5698. }
  5699. sourceObj = Object.getPrototypeOf(sourceObj);
  5700. } while (sourceObj && (!filter || filter(sourceObj, destObj)) && sourceObj !== Object.prototype);
  5701. return destObj;
  5702. }
  5703. /*
  5704. * determines whether a string ends with the characters of a specified string
  5705. * @param {String} str
  5706. * @param {String} searchString
  5707. * @param {Number} [position= 0]
  5708. * @returns {boolean}
  5709. */
  5710. function endsWith(str, searchString, position) {
  5711. str = String(str);
  5712. if (position === undefined || position > str.length) {
  5713. position = str.length;
  5714. }
  5715. position -= searchString.length;
  5716. var lastIndex = str.indexOf(searchString, position);
  5717. return lastIndex !== -1 && lastIndex === position;
  5718. }
  5719. /**
  5720. * Returns new array from array like object
  5721. * @param {*} [thing]
  5722. * @returns {Array}
  5723. */
  5724. function toArray(thing) {
  5725. if (!thing) return null;
  5726. var i = thing.length;
  5727. if (isUndefined(i)) return null;
  5728. var arr = new Array(i);
  5729. while (i-- > 0) {
  5730. arr[i] = thing[i];
  5731. }
  5732. return arr;
  5733. }
  5734. // eslint-disable-next-line func-names
  5735. var isTypedArray = (function(TypedArray) {
  5736. // eslint-disable-next-line func-names
  5737. return function(thing) {
  5738. return TypedArray && thing instanceof TypedArray;
  5739. };
  5740. })(typeof Uint8Array !== 'undefined' && Object.getPrototypeOf(Uint8Array));
  5741. var utils = {
  5742. isArray: isArray,
  5743. isArrayBuffer: isArrayBuffer,
  5744. isBuffer: isBuffer,
  5745. isFormData: isFormData,
  5746. isArrayBufferView: isArrayBufferView,
  5747. isString: isString,
  5748. isNumber: isNumber,
  5749. isObject: isObject,
  5750. isPlainObject: isPlainObject,
  5751. isUndefined: isUndefined,
  5752. isDate: isDate,
  5753. isFile: isFile,
  5754. isBlob: isBlob,
  5755. isFunction: isFunction,
  5756. isStream: isStream,
  5757. isURLSearchParams: isURLSearchParams,
  5758. isStandardBrowserEnv: isStandardBrowserEnv,
  5759. forEach: forEach,
  5760. merge: merge,
  5761. extend: extend,
  5762. trim: trim,
  5763. stripBOM: stripBOM,
  5764. inherits: inherits,
  5765. toFlatObject: toFlatObject,
  5766. kindOf: kindOf,
  5767. kindOfTest: kindOfTest,
  5768. endsWith: endsWith,
  5769. toArray: toArray,
  5770. isTypedArray: isTypedArray,
  5771. isFileList: isFileList
  5772. };
  5773. function encode(val) {
  5774. return encodeURIComponent(val).
  5775. replace(/%3A/gi, ':').
  5776. replace(/%24/g, '$').
  5777. replace(/%2C/gi, ',').
  5778. replace(/%20/g, '+').
  5779. replace(/%5B/gi, '[').
  5780. replace(/%5D/gi, ']');
  5781. }
  5782. /**
  5783. * Build a URL by appending params to the end
  5784. *
  5785. * @param {string} url The base of the url (e.g., http://www.google.com)
  5786. * @param {object} [params] The params to be appended
  5787. * @returns {string} The formatted url
  5788. */
  5789. var buildURL = function buildURL(url, params, paramsSerializer) {
  5790. /*eslint no-param-reassign:0*/
  5791. if (!params) {
  5792. return url;
  5793. }
  5794. var serializedParams;
  5795. if (paramsSerializer) {
  5796. serializedParams = paramsSerializer(params);
  5797. } else if (utils.isURLSearchParams(params)) {
  5798. serializedParams = params.toString();
  5799. } else {
  5800. var parts = [];
  5801. utils.forEach(params, function serialize(val, key) {
  5802. if (val === null || typeof val === 'undefined') {
  5803. return;
  5804. }
  5805. if (utils.isArray(val)) {
  5806. key = key + '[]';
  5807. } else {
  5808. val = [val];
  5809. }
  5810. utils.forEach(val, function parseValue(v) {
  5811. if (utils.isDate(v)) {
  5812. v = v.toISOString();
  5813. } else if (utils.isObject(v)) {
  5814. v = JSON.stringify(v);
  5815. }
  5816. parts.push(encode(key) + '=' + encode(v));
  5817. });
  5818. });
  5819. serializedParams = parts.join('&');
  5820. }
  5821. if (serializedParams) {
  5822. var hashmarkIndex = url.indexOf('#');
  5823. if (hashmarkIndex !== -1) {
  5824. url = url.slice(0, hashmarkIndex);
  5825. }
  5826. url += (url.indexOf('?') === -1 ? '?' : '&') + serializedParams;
  5827. }
  5828. return url;
  5829. };
  5830. function InterceptorManager() {
  5831. this.handlers = [];
  5832. }
  5833. /**
  5834. * Add a new interceptor to the stack
  5835. *
  5836. * @param {Function} fulfilled The function to handle `then` for a `Promise`
  5837. * @param {Function} rejected The function to handle `reject` for a `Promise`
  5838. *
  5839. * @return {Number} An ID used to remove interceptor later
  5840. */
  5841. InterceptorManager.prototype.use = function use(fulfilled, rejected, options) {
  5842. this.handlers.push({
  5843. fulfilled: fulfilled,
  5844. rejected: rejected,
  5845. synchronous: options ? options.synchronous : false,
  5846. runWhen: options ? options.runWhen : null
  5847. });
  5848. return this.handlers.length - 1;
  5849. };
  5850. /**
  5851. * Remove an interceptor from the stack
  5852. *
  5853. * @param {Number} id The ID that was returned by `use`
  5854. */
  5855. InterceptorManager.prototype.eject = function eject(id) {
  5856. if (this.handlers[id]) {
  5857. this.handlers[id] = null;
  5858. }
  5859. };
  5860. /**
  5861. * Iterate over all the registered interceptors
  5862. *
  5863. * This method is particularly useful for skipping over any
  5864. * interceptors that may have become `null` calling `eject`.
  5865. *
  5866. * @param {Function} fn The function to call for each interceptor
  5867. */
  5868. InterceptorManager.prototype.forEach = function forEach(fn) {
  5869. utils.forEach(this.handlers, function forEachHandler(h) {
  5870. if (h !== null) {
  5871. fn(h);
  5872. }
  5873. });
  5874. };
  5875. var InterceptorManager_1 = InterceptorManager;
  5876. var normalizeHeaderName = function normalizeHeaderName(headers, normalizedName) {
  5877. utils.forEach(headers, function processHeader(value, name) {
  5878. if (name !== normalizedName && name.toUpperCase() === normalizedName.toUpperCase()) {
  5879. headers[normalizedName] = value;
  5880. delete headers[name];
  5881. }
  5882. });
  5883. };
  5884. /**
  5885. * Create an Error with the specified message, config, error code, request and response.
  5886. *
  5887. * @param {string} message The error message.
  5888. * @param {string} [code] The error code (for example, 'ECONNABORTED').
  5889. * @param {Object} [config] The config.
  5890. * @param {Object} [request] The request.
  5891. * @param {Object} [response] The response.
  5892. * @returns {Error} The created error.
  5893. */
  5894. function AxiosError(message, code, config, request, response) {
  5895. Error.call(this);
  5896. this.message = message;
  5897. this.name = 'AxiosError';
  5898. code && (this.code = code);
  5899. config && (this.config = config);
  5900. request && (this.request = request);
  5901. response && (this.response = response);
  5902. }
  5903. utils.inherits(AxiosError, Error, {
  5904. toJSON: function toJSON() {
  5905. return {
  5906. // Standard
  5907. message: this.message,
  5908. name: this.name,
  5909. // Microsoft
  5910. description: this.description,
  5911. number: this.number,
  5912. // Mozilla
  5913. fileName: this.fileName,
  5914. lineNumber: this.lineNumber,
  5915. columnNumber: this.columnNumber,
  5916. stack: this.stack,
  5917. // Axios
  5918. config: this.config,
  5919. code: this.code,
  5920. status: this.response && this.response.status ? this.response.status : null
  5921. };
  5922. }
  5923. });
  5924. var prototype = AxiosError.prototype;
  5925. var descriptors = {};
  5926. [
  5927. 'ERR_BAD_OPTION_VALUE',
  5928. 'ERR_BAD_OPTION',
  5929. 'ECONNABORTED',
  5930. 'ETIMEDOUT',
  5931. 'ERR_NETWORK',
  5932. 'ERR_FR_TOO_MANY_REDIRECTS',
  5933. 'ERR_DEPRECATED',
  5934. 'ERR_BAD_RESPONSE',
  5935. 'ERR_BAD_REQUEST',
  5936. 'ERR_CANCELED'
  5937. // eslint-disable-next-line func-names
  5938. ].forEach(function(code) {
  5939. descriptors[code] = {value: code};
  5940. });
  5941. Object.defineProperties(AxiosError, descriptors);
  5942. Object.defineProperty(prototype, 'isAxiosError', {value: true});
  5943. // eslint-disable-next-line func-names
  5944. AxiosError.from = function(error, code, config, request, response, customProps) {
  5945. var axiosError = Object.create(prototype);
  5946. utils.toFlatObject(error, axiosError, function filter(obj) {
  5947. return obj !== Error.prototype;
  5948. });
  5949. AxiosError.call(axiosError, error.message, code, config, request, response);
  5950. axiosError.name = error.name;
  5951. customProps && Object.assign(axiosError, customProps);
  5952. return axiosError;
  5953. };
  5954. var AxiosError_1 = AxiosError;
  5955. var transitional = {
  5956. silentJSONParsing: true,
  5957. forcedJSONParsing: true,
  5958. clarifyTimeoutError: false
  5959. };
  5960. /**
  5961. * Convert a data object to FormData
  5962. * @param {Object} obj
  5963. * @param {?Object} [formData]
  5964. * @returns {Object}
  5965. **/
  5966. function toFormData(obj, formData) {
  5967. // eslint-disable-next-line no-param-reassign
  5968. formData = formData || new FormData();
  5969. var stack = [];
  5970. function convertValue(value) {
  5971. if (value === null) return '';
  5972. if (utils.isDate(value)) {
  5973. return value.toISOString();
  5974. }
  5975. if (utils.isArrayBuffer(value) || utils.isTypedArray(value)) {
  5976. return typeof Blob === 'function' ? new Blob([value]) : Buffer.from(value);
  5977. }
  5978. return value;
  5979. }
  5980. function build(data, parentKey) {
  5981. if (utils.isPlainObject(data) || utils.isArray(data)) {
  5982. if (stack.indexOf(data) !== -1) {
  5983. throw Error('Circular reference detected in ' + parentKey);
  5984. }
  5985. stack.push(data);
  5986. utils.forEach(data, function each(value, key) {
  5987. if (utils.isUndefined(value)) return;
  5988. var fullKey = parentKey ? parentKey + '.' + key : key;
  5989. var arr;
  5990. if (value && !parentKey && typeof value === 'object') {
  5991. if (utils.endsWith(key, '{}')) {
  5992. // eslint-disable-next-line no-param-reassign
  5993. value = JSON.stringify(value);
  5994. } else if (utils.endsWith(key, '[]') && (arr = utils.toArray(value))) {
  5995. // eslint-disable-next-line func-names
  5996. arr.forEach(function(el) {
  5997. !utils.isUndefined(el) && formData.append(fullKey, convertValue(el));
  5998. });
  5999. return;
  6000. }
  6001. }
  6002. build(value, fullKey);
  6003. });
  6004. stack.pop();
  6005. } else {
  6006. formData.append(parentKey, convertValue(data));
  6007. }
  6008. }
  6009. build(obj);
  6010. return formData;
  6011. }
  6012. var toFormData_1 = toFormData;
  6013. /**
  6014. * Resolve or reject a Promise based on response status.
  6015. *
  6016. * @param {Function} resolve A function that resolves the promise.
  6017. * @param {Function} reject A function that rejects the promise.
  6018. * @param {object} response The response.
  6019. */
  6020. var settle = function settle(resolve, reject, response) {
  6021. var validateStatus = response.config.validateStatus;
  6022. if (!response.status || !validateStatus || validateStatus(response.status)) {
  6023. resolve(response);
  6024. } else {
  6025. reject(new AxiosError_1(
  6026. 'Request failed with status code ' + response.status,
  6027. [AxiosError_1.ERR_BAD_REQUEST, AxiosError_1.ERR_BAD_RESPONSE][Math.floor(response.status / 100) - 4],
  6028. response.config,
  6029. response.request,
  6030. response
  6031. ));
  6032. }
  6033. };
  6034. var cookies = (
  6035. utils.isStandardBrowserEnv() ?
  6036. // Standard browser envs support document.cookie
  6037. (function standardBrowserEnv() {
  6038. return {
  6039. write: function write(name, value, expires, path, domain, secure) {
  6040. var cookie = [];
  6041. cookie.push(name + '=' + encodeURIComponent(value));
  6042. if (utils.isNumber(expires)) {
  6043. cookie.push('expires=' + new Date(expires).toGMTString());
  6044. }
  6045. if (utils.isString(path)) {
  6046. cookie.push('path=' + path);
  6047. }
  6048. if (utils.isString(domain)) {
  6049. cookie.push('domain=' + domain);
  6050. }
  6051. if (secure === true) {
  6052. cookie.push('secure');
  6053. }
  6054. document.cookie = cookie.join('; ');
  6055. },
  6056. read: function read(name) {
  6057. var match = document.cookie.match(new RegExp('(^|;\\s*)(' + name + ')=([^;]*)'));
  6058. return (match ? decodeURIComponent(match[3]) : null);
  6059. },
  6060. remove: function remove(name) {
  6061. this.write(name, '', Date.now() - 86400000);
  6062. }
  6063. };
  6064. })() :
  6065. // Non standard browser env (web workers, react-native) lack needed support.
  6066. (function nonStandardBrowserEnv() {
  6067. return {
  6068. write: function write() {},
  6069. read: function read() { return null; },
  6070. remove: function remove() {}
  6071. };
  6072. })()
  6073. );
  6074. /**
  6075. * Determines whether the specified URL is absolute
  6076. *
  6077. * @param {string} url The URL to test
  6078. * @returns {boolean} True if the specified URL is absolute, otherwise false
  6079. */
  6080. var isAbsoluteURL = function isAbsoluteURL(url) {
  6081. // A URL is considered absolute if it begins with "<scheme>://" or "//" (protocol-relative URL).
  6082. // RFC 3986 defines scheme name as a sequence of characters beginning with a letter and followed
  6083. // by any combination of letters, digits, plus, period, or hyphen.
  6084. return /^([a-z][a-z\d+\-.]*:)?\/\//i.test(url);
  6085. };
  6086. /**
  6087. * Creates a new URL by combining the specified URLs
  6088. *
  6089. * @param {string} baseURL The base URL
  6090. * @param {string} relativeURL The relative URL
  6091. * @returns {string} The combined URL
  6092. */
  6093. var combineURLs = function combineURLs(baseURL, relativeURL) {
  6094. return relativeURL
  6095. ? baseURL.replace(/\/+$/, '') + '/' + relativeURL.replace(/^\/+/, '')
  6096. : baseURL;
  6097. };
  6098. /**
  6099. * Creates a new URL by combining the baseURL with the requestedURL,
  6100. * only when the requestedURL is not already an absolute URL.
  6101. * If the requestURL is absolute, this function returns the requestedURL untouched.
  6102. *
  6103. * @param {string} baseURL The base URL
  6104. * @param {string} requestedURL Absolute or relative URL to combine
  6105. * @returns {string} The combined full path
  6106. */
  6107. var buildFullPath = function buildFullPath(baseURL, requestedURL) {
  6108. if (baseURL && !isAbsoluteURL(requestedURL)) {
  6109. return combineURLs(baseURL, requestedURL);
  6110. }
  6111. return requestedURL;
  6112. };
  6113. // Headers whose duplicates are ignored by node
  6114. // c.f. https://nodejs.org/api/http.html#http_message_headers
  6115. var ignoreDuplicateOf = [
  6116. 'age', 'authorization', 'content-length', 'content-type', 'etag',
  6117. 'expires', 'from', 'host', 'if-modified-since', 'if-unmodified-since',
  6118. 'last-modified', 'location', 'max-forwards', 'proxy-authorization',
  6119. 'referer', 'retry-after', 'user-agent'
  6120. ];
  6121. /**
  6122. * Parse headers into an object
  6123. *
  6124. * ```
  6125. * Date: Wed, 27 Aug 2014 08:58:49 GMT
  6126. * Content-Type: application/json
  6127. * Connection: keep-alive
  6128. * Transfer-Encoding: chunked
  6129. * ```
  6130. *
  6131. * @param {String} headers Headers needing to be parsed
  6132. * @returns {Object} Headers parsed into an object
  6133. */
  6134. var parseHeaders = function parseHeaders(headers) {
  6135. var parsed = {};
  6136. var key;
  6137. var val;
  6138. var i;
  6139. if (!headers) { return parsed; }
  6140. utils.forEach(headers.split('\n'), function parser(line) {
  6141. i = line.indexOf(':');
  6142. key = utils.trim(line.substr(0, i)).toLowerCase();
  6143. val = utils.trim(line.substr(i + 1));
  6144. if (key) {
  6145. if (parsed[key] && ignoreDuplicateOf.indexOf(key) >= 0) {
  6146. return;
  6147. }
  6148. if (key === 'set-cookie') {
  6149. parsed[key] = (parsed[key] ? parsed[key] : []).concat([val]);
  6150. } else {
  6151. parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;
  6152. }
  6153. }
  6154. });
  6155. return parsed;
  6156. };
  6157. var isURLSameOrigin = (
  6158. utils.isStandardBrowserEnv() ?
  6159. // Standard browser envs have full support of the APIs needed to test
  6160. // whether the request URL is of the same origin as current location.
  6161. (function standardBrowserEnv() {
  6162. var msie = /(msie|trident)/i.test(navigator.userAgent);
  6163. var urlParsingNode = document.createElement('a');
  6164. var originURL;
  6165. /**
  6166. * Parse a URL to discover it's components
  6167. *
  6168. * @param {String} url The URL to be parsed
  6169. * @returns {Object}
  6170. */
  6171. function resolveURL(url) {
  6172. var href = url;
  6173. if (msie) {
  6174. // IE needs attribute set twice to normalize properties
  6175. urlParsingNode.setAttribute('href', href);
  6176. href = urlParsingNode.href;
  6177. }
  6178. urlParsingNode.setAttribute('href', href);
  6179. // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
  6180. return {
  6181. href: urlParsingNode.href,
  6182. protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',
  6183. host: urlParsingNode.host,
  6184. search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '',
  6185. hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
  6186. hostname: urlParsingNode.hostname,
  6187. port: urlParsingNode.port,
  6188. pathname: (urlParsingNode.pathname.charAt(0) === '/') ?
  6189. urlParsingNode.pathname :
  6190. '/' + urlParsingNode.pathname
  6191. };
  6192. }
  6193. originURL = resolveURL(window.location.href);
  6194. /**
  6195. * Determine if a URL shares the same origin as the current location
  6196. *
  6197. * @param {String} requestURL The URL to test
  6198. * @returns {boolean} True if URL shares the same origin, otherwise false
  6199. */
  6200. return function isURLSameOrigin(requestURL) {
  6201. var parsed = (utils.isString(requestURL)) ? resolveURL(requestURL) : requestURL;
  6202. return (parsed.protocol === originURL.protocol &&
  6203. parsed.host === originURL.host);
  6204. };
  6205. })() :
  6206. // Non standard browser envs (web workers, react-native) lack needed support.
  6207. (function nonStandardBrowserEnv() {
  6208. return function isURLSameOrigin() {
  6209. return true;
  6210. };
  6211. })()
  6212. );
  6213. /**
  6214. * A `CanceledError` is an object that is thrown when an operation is canceled.
  6215. *
  6216. * @class
  6217. * @param {string=} message The message.
  6218. */
  6219. function CanceledError(message) {
  6220. // eslint-disable-next-line no-eq-null,eqeqeq
  6221. AxiosError_1.call(this, message == null ? 'canceled' : message, AxiosError_1.ERR_CANCELED);
  6222. this.name = 'CanceledError';
  6223. }
  6224. utils.inherits(CanceledError, AxiosError_1, {
  6225. __CANCEL__: true
  6226. });
  6227. var CanceledError_1 = CanceledError;
  6228. var parseProtocol = function parseProtocol(url) {
  6229. var match = /^([-+\w]{1,25})(:?\/\/|:)/.exec(url);
  6230. return match && match[1] || '';
  6231. };
  6232. var xhr = function xhrAdapter(config) {
  6233. return new Promise(function dispatchXhrRequest(resolve, reject) {
  6234. var requestData = config.data;
  6235. var requestHeaders = config.headers;
  6236. var responseType = config.responseType;
  6237. var onCanceled;
  6238. function done() {
  6239. if (config.cancelToken) {
  6240. config.cancelToken.unsubscribe(onCanceled);
  6241. }
  6242. if (config.signal) {
  6243. config.signal.removeEventListener('abort', onCanceled);
  6244. }
  6245. }
  6246. if (utils.isFormData(requestData) && utils.isStandardBrowserEnv()) {
  6247. delete requestHeaders['Content-Type']; // Let the browser set it
  6248. }
  6249. var request = new XMLHttpRequest();
  6250. // HTTP basic authentication
  6251. if (config.auth) {
  6252. var username = config.auth.username || '';
  6253. var password = config.auth.password ? unescape(encodeURIComponent(config.auth.password)) : '';
  6254. requestHeaders.Authorization = 'Basic ' + btoa(username + ':' + password);
  6255. }
  6256. var fullPath = buildFullPath(config.baseURL, config.url);
  6257. request.open(config.method.toUpperCase(), buildURL(fullPath, config.params, config.paramsSerializer), true);
  6258. // Set the request timeout in MS
  6259. request.timeout = config.timeout;
  6260. function onloadend() {
  6261. if (!request) {
  6262. return;
  6263. }
  6264. // Prepare the response
  6265. var responseHeaders = 'getAllResponseHeaders' in request ? parseHeaders(request.getAllResponseHeaders()) : null;
  6266. var responseData = !responseType || responseType === 'text' || responseType === 'json' ?
  6267. request.responseText : request.response;
  6268. var response = {
  6269. data: responseData,
  6270. status: request.status,
  6271. statusText: request.statusText,
  6272. headers: responseHeaders,
  6273. config: config,
  6274. request: request
  6275. };
  6276. settle(function _resolve(value) {
  6277. resolve(value);
  6278. done();
  6279. }, function _reject(err) {
  6280. reject(err);
  6281. done();
  6282. }, response);
  6283. // Clean up request
  6284. request = null;
  6285. }
  6286. if ('onloadend' in request) {
  6287. // Use onloadend if available
  6288. request.onloadend = onloadend;
  6289. } else {
  6290. // Listen for ready state to emulate onloadend
  6291. request.onreadystatechange = function handleLoad() {
  6292. if (!request || request.readyState !== 4) {
  6293. return;
  6294. }
  6295. // The request errored out and we didn't get a response, this will be
  6296. // handled by onerror instead
  6297. // With one exception: request that using file: protocol, most browsers
  6298. // will return status as 0 even though it's a successful request
  6299. if (request.status === 0 && !(request.responseURL && request.responseURL.indexOf('file:') === 0)) {
  6300. return;
  6301. }
  6302. // readystate handler is calling before onerror or ontimeout handlers,
  6303. // so we should call onloadend on the next 'tick'
  6304. setTimeout(onloadend);
  6305. };
  6306. }
  6307. // Handle browser request cancellation (as opposed to a manual cancellation)
  6308. request.onabort = function handleAbort() {
  6309. if (!request) {
  6310. return;
  6311. }
  6312. reject(new AxiosError_1('Request aborted', AxiosError_1.ECONNABORTED, config, request));
  6313. // Clean up request
  6314. request = null;
  6315. };
  6316. // Handle low level network errors
  6317. request.onerror = function handleError() {
  6318. // Real errors are hidden from us by the browser
  6319. // onerror should only fire if it's a network error
  6320. reject(new AxiosError_1('Network Error', AxiosError_1.ERR_NETWORK, config, request, request));
  6321. // Clean up request
  6322. request = null;
  6323. };
  6324. // Handle timeout
  6325. request.ontimeout = function handleTimeout() {
  6326. var timeoutErrorMessage = config.timeout ? 'timeout of ' + config.timeout + 'ms exceeded' : 'timeout exceeded';
  6327. var transitional$1 = config.transitional || transitional;
  6328. if (config.timeoutErrorMessage) {
  6329. timeoutErrorMessage = config.timeoutErrorMessage;
  6330. }
  6331. reject(new AxiosError_1(
  6332. timeoutErrorMessage,
  6333. transitional$1.clarifyTimeoutError ? AxiosError_1.ETIMEDOUT : AxiosError_1.ECONNABORTED,
  6334. config,
  6335. request));
  6336. // Clean up request
  6337. request = null;
  6338. };
  6339. // Add xsrf header
  6340. // This is only done if running in a standard browser environment.
  6341. // Specifically not if we're in a web worker, or react-native.
  6342. if (utils.isStandardBrowserEnv()) {
  6343. // Add xsrf header
  6344. var xsrfValue = (config.withCredentials || isURLSameOrigin(fullPath)) && config.xsrfCookieName ?
  6345. cookies.read(config.xsrfCookieName) :
  6346. undefined;
  6347. if (xsrfValue) {
  6348. requestHeaders[config.xsrfHeaderName] = xsrfValue;
  6349. }
  6350. }
  6351. // Add headers to the request
  6352. if ('setRequestHeader' in request) {
  6353. utils.forEach(requestHeaders, function setRequestHeader(val, key) {
  6354. if (typeof requestData === 'undefined' && key.toLowerCase() === 'content-type') {
  6355. // Remove Content-Type if data is undefined
  6356. delete requestHeaders[key];
  6357. } else {
  6358. // Otherwise add header to the request
  6359. request.setRequestHeader(key, val);
  6360. }
  6361. });
  6362. }
  6363. // Add withCredentials to request if needed
  6364. if (!utils.isUndefined(config.withCredentials)) {
  6365. request.withCredentials = !!config.withCredentials;
  6366. }
  6367. // Add responseType to request if needed
  6368. if (responseType && responseType !== 'json') {
  6369. request.responseType = config.responseType;
  6370. }
  6371. // Handle progress if needed
  6372. if (typeof config.onDownloadProgress === 'function') {
  6373. request.addEventListener('progress', config.onDownloadProgress);
  6374. }
  6375. // Not all browsers support upload events
  6376. if (typeof config.onUploadProgress === 'function' && request.upload) {
  6377. request.upload.addEventListener('progress', config.onUploadProgress);
  6378. }
  6379. if (config.cancelToken || config.signal) {
  6380. // Handle cancellation
  6381. // eslint-disable-next-line func-names
  6382. onCanceled = function(cancel) {
  6383. if (!request) {
  6384. return;
  6385. }
  6386. reject(!cancel || (cancel && cancel.type) ? new CanceledError_1() : cancel);
  6387. request.abort();
  6388. request = null;
  6389. };
  6390. config.cancelToken && config.cancelToken.subscribe(onCanceled);
  6391. if (config.signal) {
  6392. config.signal.aborted ? onCanceled() : config.signal.addEventListener('abort', onCanceled);
  6393. }
  6394. }
  6395. if (!requestData) {
  6396. requestData = null;
  6397. }
  6398. var protocol = parseProtocol(fullPath);
  6399. if (protocol && [ 'http', 'https', 'file' ].indexOf(protocol) === -1) {
  6400. reject(new AxiosError_1('Unsupported protocol ' + protocol + ':', AxiosError_1.ERR_BAD_REQUEST, config));
  6401. return;
  6402. }
  6403. // Send the request
  6404. request.send(requestData);
  6405. });
  6406. };
  6407. // eslint-disable-next-line strict
  6408. var _null = null;
  6409. var DEFAULT_CONTENT_TYPE = {
  6410. 'Content-Type': 'application/x-www-form-urlencoded'
  6411. };
  6412. function setContentTypeIfUnset(headers, value) {
  6413. if (!utils.isUndefined(headers) && utils.isUndefined(headers['Content-Type'])) {
  6414. headers['Content-Type'] = value;
  6415. }
  6416. }
  6417. function getDefaultAdapter() {
  6418. var adapter;
  6419. if (typeof XMLHttpRequest !== 'undefined') {
  6420. // For browsers use XHR adapter
  6421. adapter = xhr;
  6422. } else if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') {
  6423. // For node use HTTP adapter
  6424. adapter = xhr;
  6425. }
  6426. return adapter;
  6427. }
  6428. function stringifySafely(rawValue, parser, encoder) {
  6429. if (utils.isString(rawValue)) {
  6430. try {
  6431. (parser || JSON.parse)(rawValue);
  6432. return utils.trim(rawValue);
  6433. } catch (e) {
  6434. if (e.name !== 'SyntaxError') {
  6435. throw e;
  6436. }
  6437. }
  6438. }
  6439. return (encoder || JSON.stringify)(rawValue);
  6440. }
  6441. var defaults = {
  6442. transitional: transitional,
  6443. adapter: getDefaultAdapter(),
  6444. transformRequest: [function transformRequest(data, headers) {
  6445. normalizeHeaderName(headers, 'Accept');
  6446. normalizeHeaderName(headers, 'Content-Type');
  6447. if (utils.isFormData(data) ||
  6448. utils.isArrayBuffer(data) ||
  6449. utils.isBuffer(data) ||
  6450. utils.isStream(data) ||
  6451. utils.isFile(data) ||
  6452. utils.isBlob(data)
  6453. ) {
  6454. return data;
  6455. }
  6456. if (utils.isArrayBufferView(data)) {
  6457. return data.buffer;
  6458. }
  6459. if (utils.isURLSearchParams(data)) {
  6460. setContentTypeIfUnset(headers, 'application/x-www-form-urlencoded;charset=utf-8');
  6461. return data.toString();
  6462. }
  6463. var isObjectPayload = utils.isObject(data);
  6464. var contentType = headers && headers['Content-Type'];
  6465. var isFileList;
  6466. if ((isFileList = utils.isFileList(data)) || (isObjectPayload && contentType === 'multipart/form-data')) {
  6467. var _FormData = this.env && this.env.FormData;
  6468. return toFormData_1(isFileList ? {'files[]': data} : data, _FormData && new _FormData());
  6469. } else if (isObjectPayload || contentType === 'application/json') {
  6470. setContentTypeIfUnset(headers, 'application/json');
  6471. return stringifySafely(data);
  6472. }
  6473. return data;
  6474. }],
  6475. transformResponse: [function transformResponse(data) {
  6476. var transitional = this.transitional || defaults.transitional;
  6477. var silentJSONParsing = transitional && transitional.silentJSONParsing;
  6478. var forcedJSONParsing = transitional && transitional.forcedJSONParsing;
  6479. var strictJSONParsing = !silentJSONParsing && this.responseType === 'json';
  6480. if (strictJSONParsing || (forcedJSONParsing && utils.isString(data) && data.length)) {
  6481. try {
  6482. return JSON.parse(data);
  6483. } catch (e) {
  6484. if (strictJSONParsing) {
  6485. if (e.name === 'SyntaxError') {
  6486. throw AxiosError_1.from(e, AxiosError_1.ERR_BAD_RESPONSE, this, null, this.response);
  6487. }
  6488. throw e;
  6489. }
  6490. }
  6491. }
  6492. return data;
  6493. }],
  6494. /**
  6495. * A timeout in milliseconds to abort a request. If set to 0 (default) a
  6496. * timeout is not created.
  6497. */
  6498. timeout: 0,
  6499. xsrfCookieName: 'XSRF-TOKEN',
  6500. xsrfHeaderName: 'X-XSRF-TOKEN',
  6501. maxContentLength: -1,
  6502. maxBodyLength: -1,
  6503. env: {
  6504. FormData: _null
  6505. },
  6506. validateStatus: function validateStatus(status) {
  6507. return status >= 200 && status < 300;
  6508. },
  6509. headers: {
  6510. common: {
  6511. 'Accept': 'application/json, text/plain, */*'
  6512. }
  6513. }
  6514. };
  6515. utils.forEach(['delete', 'get', 'head'], function forEachMethodNoData(method) {
  6516. defaults.headers[method] = {};
  6517. });
  6518. utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
  6519. defaults.headers[method] = utils.merge(DEFAULT_CONTENT_TYPE);
  6520. });
  6521. var defaults_1 = defaults;
  6522. /**
  6523. * Transform the data for a request or a response
  6524. *
  6525. * @param {Object|String} data The data to be transformed
  6526. * @param {Array} headers The headers for the request or response
  6527. * @param {Array|Function} fns A single function or Array of functions
  6528. * @returns {*} The resulting transformed data
  6529. */
  6530. var transformData = function transformData(data, headers, fns) {
  6531. var context = this || defaults_1;
  6532. /*eslint no-param-reassign:0*/
  6533. utils.forEach(fns, function transform(fn) {
  6534. data = fn.call(context, data, headers);
  6535. });
  6536. return data;
  6537. };
  6538. var isCancel = function isCancel(value) {
  6539. return !!(value && value.__CANCEL__);
  6540. };
  6541. /**
  6542. * Throws a `CanceledError` if cancellation has been requested.
  6543. */
  6544. function throwIfCancellationRequested(config) {
  6545. if (config.cancelToken) {
  6546. config.cancelToken.throwIfRequested();
  6547. }
  6548. if (config.signal && config.signal.aborted) {
  6549. throw new CanceledError_1();
  6550. }
  6551. }
  6552. /**
  6553. * Dispatch a request to the server using the configured adapter.
  6554. *
  6555. * @param {object} config The config that is to be used for the request
  6556. * @returns {Promise} The Promise to be fulfilled
  6557. */
  6558. var dispatchRequest = function dispatchRequest(config) {
  6559. throwIfCancellationRequested(config);
  6560. // Ensure headers exist
  6561. config.headers = config.headers || {};
  6562. // Transform request data
  6563. config.data = transformData.call(
  6564. config,
  6565. config.data,
  6566. config.headers,
  6567. config.transformRequest
  6568. );
  6569. // Flatten headers
  6570. config.headers = utils.merge(
  6571. config.headers.common || {},
  6572. config.headers[config.method] || {},
  6573. config.headers
  6574. );
  6575. utils.forEach(
  6576. ['delete', 'get', 'head', 'post', 'put', 'patch', 'common'],
  6577. function cleanHeaderConfig(method) {
  6578. delete config.headers[method];
  6579. }
  6580. );
  6581. var adapter = config.adapter || defaults_1.adapter;
  6582. return adapter(config).then(function onAdapterResolution(response) {
  6583. throwIfCancellationRequested(config);
  6584. // Transform response data
  6585. response.data = transformData.call(
  6586. config,
  6587. response.data,
  6588. response.headers,
  6589. config.transformResponse
  6590. );
  6591. return response;
  6592. }, function onAdapterRejection(reason) {
  6593. if (!isCancel(reason)) {
  6594. throwIfCancellationRequested(config);
  6595. // Transform response data
  6596. if (reason && reason.response) {
  6597. reason.response.data = transformData.call(
  6598. config,
  6599. reason.response.data,
  6600. reason.response.headers,
  6601. config.transformResponse
  6602. );
  6603. }
  6604. }
  6605. return Promise.reject(reason);
  6606. });
  6607. };
  6608. /**
  6609. * Config-specific merge-function which creates a new config-object
  6610. * by merging two configuration objects together.
  6611. *
  6612. * @param {Object} config1
  6613. * @param {Object} config2
  6614. * @returns {Object} New object resulting from merging config2 to config1
  6615. */
  6616. var mergeConfig = function mergeConfig(config1, config2) {
  6617. // eslint-disable-next-line no-param-reassign
  6618. config2 = config2 || {};
  6619. var config = {};
  6620. function getMergedValue(target, source) {
  6621. if (utils.isPlainObject(target) && utils.isPlainObject(source)) {
  6622. return utils.merge(target, source);
  6623. } else if (utils.isPlainObject(source)) {
  6624. return utils.merge({}, source);
  6625. } else if (utils.isArray(source)) {
  6626. return source.slice();
  6627. }
  6628. return source;
  6629. }
  6630. // eslint-disable-next-line consistent-return
  6631. function mergeDeepProperties(prop) {
  6632. if (!utils.isUndefined(config2[prop])) {
  6633. return getMergedValue(config1[prop], config2[prop]);
  6634. } else if (!utils.isUndefined(config1[prop])) {
  6635. return getMergedValue(undefined, config1[prop]);
  6636. }
  6637. }
  6638. // eslint-disable-next-line consistent-return
  6639. function valueFromConfig2(prop) {
  6640. if (!utils.isUndefined(config2[prop])) {
  6641. return getMergedValue(undefined, config2[prop]);
  6642. }
  6643. }
  6644. // eslint-disable-next-line consistent-return
  6645. function defaultToConfig2(prop) {
  6646. if (!utils.isUndefined(config2[prop])) {
  6647. return getMergedValue(undefined, config2[prop]);
  6648. } else if (!utils.isUndefined(config1[prop])) {
  6649. return getMergedValue(undefined, config1[prop]);
  6650. }
  6651. }
  6652. // eslint-disable-next-line consistent-return
  6653. function mergeDirectKeys(prop) {
  6654. if (prop in config2) {
  6655. return getMergedValue(config1[prop], config2[prop]);
  6656. } else if (prop in config1) {
  6657. return getMergedValue(undefined, config1[prop]);
  6658. }
  6659. }
  6660. var mergeMap = {
  6661. 'url': valueFromConfig2,
  6662. 'method': valueFromConfig2,
  6663. 'data': valueFromConfig2,
  6664. 'baseURL': defaultToConfig2,
  6665. 'transformRequest': defaultToConfig2,
  6666. 'transformResponse': defaultToConfig2,
  6667. 'paramsSerializer': defaultToConfig2,
  6668. 'timeout': defaultToConfig2,
  6669. 'timeoutMessage': defaultToConfig2,
  6670. 'withCredentials': defaultToConfig2,
  6671. 'adapter': defaultToConfig2,
  6672. 'responseType': defaultToConfig2,
  6673. 'xsrfCookieName': defaultToConfig2,
  6674. 'xsrfHeaderName': defaultToConfig2,
  6675. 'onUploadProgress': defaultToConfig2,
  6676. 'onDownloadProgress': defaultToConfig2,
  6677. 'decompress': defaultToConfig2,
  6678. 'maxContentLength': defaultToConfig2,
  6679. 'maxBodyLength': defaultToConfig2,
  6680. 'beforeRedirect': defaultToConfig2,
  6681. 'transport': defaultToConfig2,
  6682. 'httpAgent': defaultToConfig2,
  6683. 'httpsAgent': defaultToConfig2,
  6684. 'cancelToken': defaultToConfig2,
  6685. 'socketPath': defaultToConfig2,
  6686. 'responseEncoding': defaultToConfig2,
  6687. 'validateStatus': mergeDirectKeys
  6688. };
  6689. utils.forEach(Object.keys(config1).concat(Object.keys(config2)), function computeConfigValue(prop) {
  6690. var merge = mergeMap[prop] || mergeDeepProperties;
  6691. var configValue = merge(prop);
  6692. (utils.isUndefined(configValue) && merge !== mergeDirectKeys) || (config[prop] = configValue);
  6693. });
  6694. return config;
  6695. };
  6696. var data = {
  6697. "version": "0.27.2"
  6698. };
  6699. var VERSION = data.version;
  6700. var validators$1 = {};
  6701. // eslint-disable-next-line func-names
  6702. ['object', 'boolean', 'number', 'function', 'string', 'symbol'].forEach(function(type, i) {
  6703. validators$1[type] = function validator(thing) {
  6704. return typeof thing === type || 'a' + (i < 1 ? 'n ' : ' ') + type;
  6705. };
  6706. });
  6707. var deprecatedWarnings = {};
  6708. /**
  6709. * Transitional option validator
  6710. * @param {function|boolean?} validator - set to false if the transitional option has been removed
  6711. * @param {string?} version - deprecated version / removed since version
  6712. * @param {string?} message - some message with additional info
  6713. * @returns {function}
  6714. */
  6715. validators$1.transitional = function transitional(validator, version, message) {
  6716. function formatMessage(opt, desc) {
  6717. return '[Axios v' + VERSION + '] Transitional option \'' + opt + '\'' + desc + (message ? '. ' + message : '');
  6718. }
  6719. // eslint-disable-next-line func-names
  6720. return function(value, opt, opts) {
  6721. if (validator === false) {
  6722. throw new AxiosError_1(
  6723. formatMessage(opt, ' has been removed' + (version ? ' in ' + version : '')),
  6724. AxiosError_1.ERR_DEPRECATED
  6725. );
  6726. }
  6727. if (version && !deprecatedWarnings[opt]) {
  6728. deprecatedWarnings[opt] = true;
  6729. // eslint-disable-next-line no-console
  6730. console.warn(
  6731. formatMessage(
  6732. opt,
  6733. ' has been deprecated since v' + version + ' and will be removed in the near future'
  6734. )
  6735. );
  6736. }
  6737. return validator ? validator(value, opt, opts) : true;
  6738. };
  6739. };
  6740. /**
  6741. * Assert object's properties type
  6742. * @param {object} options
  6743. * @param {object} schema
  6744. * @param {boolean?} allowUnknown
  6745. */
  6746. function assertOptions(options, schema, allowUnknown) {
  6747. if (typeof options !== 'object') {
  6748. throw new AxiosError_1('options must be an object', AxiosError_1.ERR_BAD_OPTION_VALUE);
  6749. }
  6750. var keys = Object.keys(options);
  6751. var i = keys.length;
  6752. while (i-- > 0) {
  6753. var opt = keys[i];
  6754. var validator = schema[opt];
  6755. if (validator) {
  6756. var value = options[opt];
  6757. var result = value === undefined || validator(value, opt, options);
  6758. if (result !== true) {
  6759. throw new AxiosError_1('option ' + opt + ' must be ' + result, AxiosError_1.ERR_BAD_OPTION_VALUE);
  6760. }
  6761. continue;
  6762. }
  6763. if (allowUnknown !== true) {
  6764. throw new AxiosError_1('Unknown option ' + opt, AxiosError_1.ERR_BAD_OPTION);
  6765. }
  6766. }
  6767. }
  6768. var validator = {
  6769. assertOptions: assertOptions,
  6770. validators: validators$1
  6771. };
  6772. var validators = validator.validators;
  6773. /**
  6774. * Create a new instance of Axios
  6775. *
  6776. * @param {Object} instanceConfig The default config for the instance
  6777. */
  6778. function Axios(instanceConfig) {
  6779. this.defaults = instanceConfig;
  6780. this.interceptors = {
  6781. request: new InterceptorManager_1(),
  6782. response: new InterceptorManager_1()
  6783. };
  6784. }
  6785. /**
  6786. * Dispatch a request
  6787. *
  6788. * @param {Object} config The config specific for this request (merged with this.defaults)
  6789. */
  6790. Axios.prototype.request = function request(configOrUrl, config) {
  6791. /*eslint no-param-reassign:0*/
  6792. // Allow for axios('example/url'[, config]) a la fetch API
  6793. if (typeof configOrUrl === 'string') {
  6794. config = config || {};
  6795. config.url = configOrUrl;
  6796. } else {
  6797. config = configOrUrl || {};
  6798. }
  6799. config = mergeConfig(this.defaults, config);
  6800. // Set config.method
  6801. if (config.method) {
  6802. config.method = config.method.toLowerCase();
  6803. } else if (this.defaults.method) {
  6804. config.method = this.defaults.method.toLowerCase();
  6805. } else {
  6806. config.method = 'get';
  6807. }
  6808. var transitional = config.transitional;
  6809. if (transitional !== undefined) {
  6810. validator.assertOptions(transitional, {
  6811. silentJSONParsing: validators.transitional(validators.boolean),
  6812. forcedJSONParsing: validators.transitional(validators.boolean),
  6813. clarifyTimeoutError: validators.transitional(validators.boolean)
  6814. }, false);
  6815. }
  6816. // filter out skipped interceptors
  6817. var requestInterceptorChain = [];
  6818. var synchronousRequestInterceptors = true;
  6819. this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
  6820. if (typeof interceptor.runWhen === 'function' && interceptor.runWhen(config) === false) {
  6821. return;
  6822. }
  6823. synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous;
  6824. requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);
  6825. });
  6826. var responseInterceptorChain = [];
  6827. this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
  6828. responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
  6829. });
  6830. var promise;
  6831. if (!synchronousRequestInterceptors) {
  6832. var chain = [dispatchRequest, undefined];
  6833. Array.prototype.unshift.apply(chain, requestInterceptorChain);
  6834. chain = chain.concat(responseInterceptorChain);
  6835. promise = Promise.resolve(config);
  6836. while (chain.length) {
  6837. promise = promise.then(chain.shift(), chain.shift());
  6838. }
  6839. return promise;
  6840. }
  6841. var newConfig = config;
  6842. while (requestInterceptorChain.length) {
  6843. var onFulfilled = requestInterceptorChain.shift();
  6844. var onRejected = requestInterceptorChain.shift();
  6845. try {
  6846. newConfig = onFulfilled(newConfig);
  6847. } catch (error) {
  6848. onRejected(error);
  6849. break;
  6850. }
  6851. }
  6852. try {
  6853. promise = dispatchRequest(newConfig);
  6854. } catch (error) {
  6855. return Promise.reject(error);
  6856. }
  6857. while (responseInterceptorChain.length) {
  6858. promise = promise.then(responseInterceptorChain.shift(), responseInterceptorChain.shift());
  6859. }
  6860. return promise;
  6861. };
  6862. Axios.prototype.getUri = function getUri(config) {
  6863. config = mergeConfig(this.defaults, config);
  6864. var fullPath = buildFullPath(config.baseURL, config.url);
  6865. return buildURL(fullPath, config.params, config.paramsSerializer);
  6866. };
  6867. // Provide aliases for supported request methods
  6868. utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) {
  6869. /*eslint func-names:0*/
  6870. Axios.prototype[method] = function(url, config) {
  6871. return this.request(mergeConfig(config || {}, {
  6872. method: method,
  6873. url: url,
  6874. data: (config || {}).data
  6875. }));
  6876. };
  6877. });
  6878. utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
  6879. /*eslint func-names:0*/
  6880. function generateHTTPMethod(isForm) {
  6881. return function httpMethod(url, data, config) {
  6882. return this.request(mergeConfig(config || {}, {
  6883. method: method,
  6884. headers: isForm ? {
  6885. 'Content-Type': 'multipart/form-data'
  6886. } : {},
  6887. url: url,
  6888. data: data
  6889. }));
  6890. };
  6891. }
  6892. Axios.prototype[method] = generateHTTPMethod();
  6893. Axios.prototype[method + 'Form'] = generateHTTPMethod(true);
  6894. });
  6895. var Axios_1 = Axios;
  6896. /**
  6897. * A `CancelToken` is an object that can be used to request cancellation of an operation.
  6898. *
  6899. * @class
  6900. * @param {Function} executor The executor function.
  6901. */
  6902. function CancelToken(executor) {
  6903. if (typeof executor !== 'function') {
  6904. throw new TypeError('executor must be a function.');
  6905. }
  6906. var resolvePromise;
  6907. this.promise = new Promise(function promiseExecutor(resolve) {
  6908. resolvePromise = resolve;
  6909. });
  6910. var token = this;
  6911. // eslint-disable-next-line func-names
  6912. this.promise.then(function(cancel) {
  6913. if (!token._listeners) return;
  6914. var i;
  6915. var l = token._listeners.length;
  6916. for (i = 0; i < l; i++) {
  6917. token._listeners[i](cancel);
  6918. }
  6919. token._listeners = null;
  6920. });
  6921. // eslint-disable-next-line func-names
  6922. this.promise.then = function(onfulfilled) {
  6923. var _resolve;
  6924. // eslint-disable-next-line func-names
  6925. var promise = new Promise(function(resolve) {
  6926. token.subscribe(resolve);
  6927. _resolve = resolve;
  6928. }).then(onfulfilled);
  6929. promise.cancel = function reject() {
  6930. token.unsubscribe(_resolve);
  6931. };
  6932. return promise;
  6933. };
  6934. executor(function cancel(message) {
  6935. if (token.reason) {
  6936. // Cancellation has already been requested
  6937. return;
  6938. }
  6939. token.reason = new CanceledError_1(message);
  6940. resolvePromise(token.reason);
  6941. });
  6942. }
  6943. /**
  6944. * Throws a `CanceledError` if cancellation has been requested.
  6945. */
  6946. CancelToken.prototype.throwIfRequested = function throwIfRequested() {
  6947. if (this.reason) {
  6948. throw this.reason;
  6949. }
  6950. };
  6951. /**
  6952. * Subscribe to the cancel signal
  6953. */
  6954. CancelToken.prototype.subscribe = function subscribe(listener) {
  6955. if (this.reason) {
  6956. listener(this.reason);
  6957. return;
  6958. }
  6959. if (this._listeners) {
  6960. this._listeners.push(listener);
  6961. } else {
  6962. this._listeners = [listener];
  6963. }
  6964. };
  6965. /**
  6966. * Unsubscribe from the cancel signal
  6967. */
  6968. CancelToken.prototype.unsubscribe = function unsubscribe(listener) {
  6969. if (!this._listeners) {
  6970. return;
  6971. }
  6972. var index = this._listeners.indexOf(listener);
  6973. if (index !== -1) {
  6974. this._listeners.splice(index, 1);
  6975. }
  6976. };
  6977. /**
  6978. * Returns an object that contains a new `CancelToken` and a function that, when called,
  6979. * cancels the `CancelToken`.
  6980. */
  6981. CancelToken.source = function source() {
  6982. var cancel;
  6983. var token = new CancelToken(function executor(c) {
  6984. cancel = c;
  6985. });
  6986. return {
  6987. token: token,
  6988. cancel: cancel
  6989. };
  6990. };
  6991. var CancelToken_1 = CancelToken;
  6992. /**
  6993. * Syntactic sugar for invoking a function and expanding an array for arguments.
  6994. *
  6995. * Common use case would be to use `Function.prototype.apply`.
  6996. *
  6997. * ```js
  6998. * function f(x, y, z) {}
  6999. * var args = [1, 2, 3];
  7000. * f.apply(null, args);
  7001. * ```
  7002. *
  7003. * With `spread` this example can be re-written.
  7004. *
  7005. * ```js
  7006. * spread(function(x, y, z) {})([1, 2, 3]);
  7007. * ```
  7008. *
  7009. * @param {Function} callback
  7010. * @returns {Function}
  7011. */
  7012. var spread = function spread(callback) {
  7013. return function wrap(arr) {
  7014. return callback.apply(null, arr);
  7015. };
  7016. };
  7017. /**
  7018. * Determines whether the payload is an error thrown by Axios
  7019. *
  7020. * @param {*} payload The value to test
  7021. * @returns {boolean} True if the payload is an error thrown by Axios, otherwise false
  7022. */
  7023. var isAxiosError = function isAxiosError(payload) {
  7024. return utils.isObject(payload) && (payload.isAxiosError === true);
  7025. };
  7026. /**
  7027. * Create an instance of Axios
  7028. *
  7029. * @param {Object} defaultConfig The default config for the instance
  7030. * @return {Axios} A new instance of Axios
  7031. */
  7032. function createInstance(defaultConfig) {
  7033. var context = new Axios_1(defaultConfig);
  7034. var instance = bind(Axios_1.prototype.request, context);
  7035. // Copy axios.prototype to instance
  7036. utils.extend(instance, Axios_1.prototype, context);
  7037. // Copy context to instance
  7038. utils.extend(instance, context);
  7039. // Factory for creating new instances
  7040. instance.create = function create(instanceConfig) {
  7041. return createInstance(mergeConfig(defaultConfig, instanceConfig));
  7042. };
  7043. return instance;
  7044. }
  7045. // Create the default instance to be exported
  7046. var axios$1 = createInstance(defaults_1);
  7047. // Expose Axios class to allow class inheritance
  7048. axios$1.Axios = Axios_1;
  7049. // Expose Cancel & CancelToken
  7050. axios$1.CanceledError = CanceledError_1;
  7051. axios$1.CancelToken = CancelToken_1;
  7052. axios$1.isCancel = isCancel;
  7053. axios$1.VERSION = data.version;
  7054. axios$1.toFormData = toFormData_1;
  7055. // Expose AxiosError class
  7056. axios$1.AxiosError = AxiosError_1;
  7057. // alias for CanceledError for backward compatibility
  7058. axios$1.Cancel = axios$1.CanceledError;
  7059. // Expose all/spread
  7060. axios$1.all = function all(promises) {
  7061. return Promise.all(promises);
  7062. };
  7063. axios$1.spread = spread;
  7064. // Expose isAxiosError
  7065. axios$1.isAxiosError = isAxiosError;
  7066. var axios_1 = axios$1;
  7067. // Allow use of default import syntax in TypeScript
  7068. var _default = axios$1;
  7069. axios_1.default = _default;
  7070. var axios = axios_1;
  7071. class RTCEndpoint extends Event$1 {
  7072. constructor(options) {
  7073. super('RTCPusherPlayer');
  7074. this.TAG = '[RTCPusherPlayer]';
  7075. let defaults = {
  7076. element: '',
  7077. // html video element
  7078. debug: false,
  7079. // if output debug log
  7080. zlmsdpUrl: '',
  7081. simulcast: false,
  7082. useCamera: true,
  7083. audioEnable: true,
  7084. videoEnable: true,
  7085. recvOnly: false,
  7086. resolution: {
  7087. w: 0,
  7088. h: 0
  7089. },
  7090. enableCodings: [0,8,9,13],
  7091. usedatachannel: false
  7092. };
  7093. console.log(options);
  7094. this.options = Object.assign({}, defaults, options);
  7095. console.log(this.options );
  7096. if (this.options.debug) {
  7097. setLogger();
  7098. }
  7099. this.e = {
  7100. onicecandidate: this._onIceCandidate.bind(this),
  7101. ontrack: this._onTrack.bind(this),
  7102. onicecandidateerror: this._onIceCandidateError.bind(this),
  7103. onconnectionstatechange: this._onconnectionstatechange.bind(this),
  7104. ondatachannelopen: this._onDataChannelOpen.bind(this),
  7105. ondatachannelmsg: this._onDataChannelMsg.bind(this),
  7106. ondatachannelerr: this._onDataChannelErr.bind(this),
  7107. ondatachannelclose: this._onDataChannelClose.bind(this)
  7108. };
  7109. this._remoteStream = null;
  7110. this._localStream = null;
  7111. this.pc = new RTCPeerConnection(null);
  7112. this.pc.onicecandidate = this.e.onicecandidate;
  7113. this.pc.onicecandidateerror = this.e.onicecandidateerror;
  7114. this.pc.ontrack = this.e.ontrack;
  7115. this.pc.onconnectionstatechange = this.e.onconnectionstatechange;
  7116. this.datachannel = null;
  7117. if (this.options.usedatachannel) {
  7118. this.datachannel = this.pc.createDataChannel('chat');
  7119. this.datachannel.onclose = this.e.ondatachannelclose;
  7120. this.datachannel.onerror = this.e.ondatachannelerr;
  7121. this.datachannel.onmessage = this.e.ondatachannelmsg;
  7122. this.datachannel.onopen = this.e.ondatachannelopen;
  7123. }
  7124. if (!this.options.recvOnly && (this.options.audioEnable || this.options.videoEnable)) this.start();else this.receive();
  7125. }
  7126. receive() {
  7127. const AudioTransceiverInit = {
  7128. direction: 'recvonly',
  7129. sendEncodings: []
  7130. };
  7131. const VideoTransceiverInit = {
  7132. direction: 'recvonly',
  7133. sendEncodings: []
  7134. };
  7135. if (this.options.videoEnable) {
  7136. this.pc.addTransceiver('video', VideoTransceiverInit);
  7137. }
  7138. if (this.options.audioEnable) {
  7139. this.pc.addTransceiver('audio', AudioTransceiverInit);
  7140. }
  7141. this.pc.createOffer().then(desc => {
  7142. // log(this.TAG, 'offer:');
  7143. let sdp = this.reWriteAudioCodingSdp(desc.sdp.toString());
  7144. // sdp = sdp.replace("a=rtpmap:9 G722/8000","");
  7145. log(this.Tag,"offer sdp:\n",sdp)
  7146. this.pc.setLocalDescription(desc).then(() => {
  7147. axios({
  7148. method: 'post',
  7149. url: this.options.zlmsdpUrl,
  7150. responseType: 'json',
  7151. data: sdp,
  7152. headers: {
  7153. 'Content-Type': 'text/plain;charset=utf-8'
  7154. }
  7155. }).then(response => {
  7156. let ret = response.data; //JSON.parse(response.data);
  7157. if (ret.code != 0) {
  7158. // mean failed for offer/anwser exchange
  7159. this.dispatch(Events$1.WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED, ret);
  7160. return;
  7161. }
  7162. let anwser = {};
  7163. anwser.sdp = ret.sdp;
  7164. anwser.type = 'answer';
  7165. log(this.TAG, 'answer:', ret.sdp);
  7166. this.pc.setRemoteDescription(anwser).then(() => {
  7167. log(this.TAG, 'set remote sucess');
  7168. }).catch(e => {
  7169. error(this.TAG, e);
  7170. });
  7171. }).catch(e => {
  7172. this.dispatch(Events$1.CONNECT_FAIL,e);
  7173. });
  7174. });
  7175. }).catch(e => {
  7176. error(this.TAG, e);
  7177. });
  7178. }
  7179. start() {
  7180. let videoConstraints = false;
  7181. let audioConstraints = false;
  7182. if (this.options.useCamera) {
  7183. if (this.options.videoEnable) videoConstraints = new VideoTrackConstraints(VideoSourceInfo.CAMERA);
  7184. if (this.options.audioEnable) audioConstraints = new AudioTrackConstraints(AudioSourceInfo.MIC);
  7185. } else {
  7186. if (this.options.videoEnable) {
  7187. videoConstraints = new VideoTrackConstraints(VideoSourceInfo.SCREENCAST);
  7188. if (this.options.audioEnable) audioConstraints = new AudioTrackConstraints(AudioSourceInfo.SCREENCAST);
  7189. } else {
  7190. if (this.options.audioEnable) audioConstraints = new AudioTrackConstraints(AudioSourceInfo.MIC);else {
  7191. // error shared display media not only audio
  7192. error(this.TAG, 'error paramter');
  7193. }
  7194. }
  7195. }
  7196. if (this.options.resolution.w != 0 && this.options.resolution.h != 0 && typeof videoConstraints == 'object') {
  7197. videoConstraints.resolution = new Resolution(this.options.resolution.w, this.options.resolution.h);
  7198. }
  7199. MediaStreamFactory.createMediaStream(new StreamConstraints(audioConstraints, videoConstraints)).then(stream => {
  7200. this._localStream = stream;
  7201. this.dispatch(Events$1.WEBRTC_ON_LOCAL_STREAM, stream);
  7202. const AudioTransceiverInit = {
  7203. direction: 'sendrecv',
  7204. sendEncodings: []
  7205. };
  7206. const VideoTransceiverInit = {
  7207. direction: 'sendrecv',
  7208. sendEncodings: []
  7209. };
  7210. if (this.options.simulcast && stream.getVideoTracks().length > 0) {
  7211. VideoTransceiverInit.sendEncodings = [{
  7212. rid: 'h',
  7213. active: true,
  7214. maxBitrate: 1000000
  7215. }, {
  7216. rid: 'm',
  7217. active: true,
  7218. maxBitrate: 500000,
  7219. scaleResolutionDownBy: 2
  7220. }, {
  7221. rid: 'l',
  7222. active: true,
  7223. maxBitrate: 200000,
  7224. scaleResolutionDownBy: 4
  7225. }];
  7226. }
  7227. if (this.options.audioEnable) {
  7228. if (stream.getAudioTracks().length > 0) {
  7229. this.pc.addTransceiver(stream.getAudioTracks()[0], AudioTransceiverInit);
  7230. } else {
  7231. AudioTransceiverInit.direction = 'recvonly';
  7232. this.pc.addTransceiver('audio', AudioTransceiverInit);
  7233. }
  7234. }
  7235. if (this.options.videoEnable) {
  7236. if (stream.getVideoTracks().length > 0) {
  7237. this.pc.addTransceiver(stream.getVideoTracks()[0], VideoTransceiverInit);
  7238. } else {
  7239. VideoTransceiverInit.direction = 'recvonly';
  7240. this.pc.addTransceiver('video', VideoTransceiverInit);
  7241. }
  7242. }
  7243. /*
  7244. stream.getTracks().forEach((track,idx)=>{
  7245. debug.log(this.TAG,track);
  7246. this.pc.addTrack(track);
  7247. });
  7248. */
  7249. this.pc.createOffer().then(desc => {
  7250. // log(this.TAG, 'offer:', desc.sdp);
  7251. // console.log(desc.sdp.replace("a=rtpmap:0 PCMU/8000\n",""));
  7252. let sdp = this.reWriteAudioCodingSdp(desc.sdp.toString());
  7253. log(this.TAG, 'offer sdp :', sdp);
  7254. this.pc.setLocalDescription(desc).then(() => {
  7255. axios({
  7256. method: 'post',
  7257. url: this.options.zlmsdpUrl,
  7258. responseType: 'json',
  7259. data: sdp,
  7260. headers: {
  7261. 'Content-Type': 'text/plain;charset=utf-8'
  7262. }
  7263. }).then(response => {
  7264. let ret = response.data; //JSON.parse(response.data);
  7265. if (ret.code != 0) {
  7266. // mean failed for offer/anwser exchange
  7267. this.dispatch(Events$1.WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED, ret);
  7268. return;
  7269. }
  7270. let anwser = {};
  7271. anwser.sdp = ret.sdp;
  7272. anwser.type = 'answer';
  7273. log(this.TAG, 'answer:', ret.sdp);
  7274. this.pc.setRemoteDescription(anwser).then(() => {
  7275. log(this.TAG, 'set remote sucess');
  7276. }).catch(e => {
  7277. error(this.TAG, e);
  7278. });
  7279. }).catch(e => {
  7280. this.dispatch(Events$1.CONNECT_FAIL,e);
  7281. });
  7282. });
  7283. }).catch(e => {
  7284. error(this.TAG, e);
  7285. });
  7286. }).catch(e => {
  7287. this.dispatch(Events$1.CAPTURE_STREAM_FAILED); //debug.error(this.TAG,e);
  7288. }); //const offerOptions = {};
  7289. /*
  7290. if (typeof this.pc.addTransceiver === 'function') {
  7291. // |direction| seems not working on Safari.
  7292. this.pc.addTransceiver('audio', { direction: 'recvonly' });
  7293. this.pc.addTransceiver('video', { direction: 'recvonly' });
  7294. } else {
  7295. offerOptions.offerToReceiveAudio = true;
  7296. offerOptions.offerToReceiveVideo = true;
  7297. }
  7298. */
  7299. }
  7300. _onIceCandidate(event) {
  7301. if (event.candidate) {
  7302. log('Remote ICE candidate: \n ' + event.candidate.candidate); // Send the candidate to the remote peer
  7303. }
  7304. }
  7305. _onTrack(event) {
  7306. if (this.options.element && event.streams && event.streams.length > 0) {
  7307. this.options.element.srcObject = event.streams[0];
  7308. this._remoteStream = event.streams[0];
  7309. this.dispatch(Events$1.WEBRTC_ON_REMOTE_STREAMS, event);
  7310. } else {
  7311. error('element pararm is failed');
  7312. }
  7313. }
  7314. _onIceCandidateError(event) {
  7315. this.dispatch(Events$1.WEBRTC_ICE_CANDIDATE_ERROR, event);
  7316. }
  7317. _onconnectionstatechange(event) {
  7318. this.dispatch(Events$1.WEBRTC_ON_CONNECTION_STATE_CHANGE, this.pc.connectionState);
  7319. }
  7320. _onDataChannelOpen(event) {
  7321. log(this.TAG, 'ondatachannel open:', event);
  7322. this.dispatch(Events$1.WEBRTC_ON_DATA_CHANNEL_OPEN, event);
  7323. }
  7324. _onDataChannelMsg(event) {
  7325. log(this.TAG, 'ondatachannel msg:', event);
  7326. this.dispatch(Events$1.WEBRTC_ON_DATA_CHANNEL_MSG, event);
  7327. }
  7328. _onDataChannelErr(event) {
  7329. log(this.TAG, 'ondatachannel err:', event);
  7330. this.dispatch(Events$1.WEBRTC_ON_DATA_CHANNEL_ERR, event);
  7331. }
  7332. _onDataChannelClose(event) {
  7333. log(this.TAG, 'ondatachannel close:', event);
  7334. this.dispatch(Events$1.WEBRTC_ON_DATA_CHANNEL_CLOSE, event);
  7335. }
  7336. sendMsg(data) {
  7337. if (this.datachannel != null) {
  7338. this.datachannel.send(data);
  7339. } else {
  7340. error(this.TAG, 'data channel is null');
  7341. }
  7342. }
  7343. closeDataChannel() {
  7344. if (this.datachannel) {
  7345. this.datachannel.close();
  7346. this.datachannel = null;
  7347. }
  7348. }
  7349. close() {
  7350. this.closeDataChannel();
  7351. if (this.pc) {
  7352. this.pc.close();
  7353. this.pc = null;
  7354. }
  7355. if (this.options) {
  7356. this.options = null;
  7357. }
  7358. if (this._localStream) {
  7359. this._localStream.getTracks().forEach((track, idx) => {
  7360. track.stop();
  7361. });
  7362. }
  7363. if (this._remoteStream) {
  7364. this._remoteStream.getTracks().forEach((track, idx) => {
  7365. track.stop();
  7366. });
  7367. }
  7368. }
  7369. get remoteStream() {
  7370. return this._remoteStream;
  7371. }
  7372. get localStream() {
  7373. return this._localStream;
  7374. }
  7375. reWriteAudioCodingSdp(sdp){
  7376. // 获取需要修改
  7377. console.log(sdp);
  7378. let _sdp = sdp;
  7379. let audioEncodingKeys = Object.keys(audioEncoding);
  7380. console.log(audioEncoding);
  7381. // console.log(audioEncodingKeys);
  7382. let ptReg = /m=audio\s9\sUDP\/TLS\/RTP\/SAVPF(\s\d+)+/
  7383. _sdp=_sdp.replace(ptReg,`m=audio 9 UDP/TLS/RTP/SAVPF 111 63 9 ${this.options.enableCodings.join(' ')}`)
  7384. // _sdp=_sdp.replace(ptReg,`m=audio 9 UDP/TLS/RTP/SAVPF 111 63 9 0 8 13 110 126`)
  7385. // _sdp=_sdp.replace("a=group:BUNDLE 0","a=group:BUNDLE 8")
  7386. for(let key of audioEncodingKeys){
  7387. if(this.options.enableCodings.includes(key)){
  7388. console.log(`已经启用的音频编码 ${audioEncoding[key].name}`);
  7389. // continue;
  7390. }else{
  7391. // console.log(key);
  7392. // console.log(audioEncoding[key]);
  7393. // console.log(audioEncoding[key].replaceStr);
  7394. // console.log(_sdp)
  7395. // console.log(_sdp.replace(new RegExp(audioEncoding[key].replaceStr,"g"),""))
  7396. // console.log(_sdp.replace("a=rtpmap:0 PCMU/8000\n",""));
  7397. //
  7398. // console.log(Function.prototype.toString.call(_sdp.replace))
  7399. _sdp = _sdp.replace(new RegExp(audioEncoding[key].replaceStr,"g"),"");
  7400. // console.log(_sdp)
  7401. }
  7402. }
  7403. // console.log(_sdp);
  7404. return _sdp;
  7405. }
  7406. }
  7407. const quickScan = [{
  7408. 'label': '4K(UHD)',
  7409. 'width': 3840,
  7410. 'height': 2160
  7411. }, {
  7412. 'label': '1080p(FHD)',
  7413. 'width': 1920,
  7414. 'height': 1080
  7415. }, {
  7416. 'label': 'UXGA',
  7417. 'width': 1600,
  7418. 'height': 1200,
  7419. 'ratio': '4:3'
  7420. }, {
  7421. 'label': '720p(HD)',
  7422. 'width': 1280,
  7423. 'height': 720
  7424. }, {
  7425. 'label': 'SVGA',
  7426. 'width': 800,
  7427. 'height': 600
  7428. }, {
  7429. 'label': 'VGA',
  7430. 'width': 640,
  7431. 'height': 480
  7432. }, {
  7433. 'label': '360p(nHD)',
  7434. 'width': 640,
  7435. 'height': 360
  7436. }, {
  7437. 'label': 'CIF',
  7438. 'width': 352,
  7439. 'height': 288
  7440. }, {
  7441. 'label': 'QVGA',
  7442. 'width': 320,
  7443. 'height': 240
  7444. }, {
  7445. 'label': 'QCIF',
  7446. 'width': 176,
  7447. 'height': 144
  7448. }, {
  7449. 'label': 'QQVGA',
  7450. 'width': 160,
  7451. 'height': 120
  7452. }];
  7453. function GetSupportCameraResolutions$1() {
  7454. return new Promise(function (resolve, reject) {
  7455. let resolutions = [];
  7456. let ok = 0;
  7457. let err = 0;
  7458. for (let i = 0; i < quickScan.length; ++i) {
  7459. let videoConstraints = new VideoTrackConstraints(VideoSourceInfo.CAMERA);
  7460. videoConstraints.resolution = new Resolution(quickScan[i].width, quickScan[i].height);
  7461. MediaStreamFactory.createMediaStream(new StreamConstraints(false, videoConstraints)).then(stream => {
  7462. resolutions.push(quickScan[i]);
  7463. ok++;
  7464. if (ok + err == quickScan.length) {
  7465. resolve(resolutions);
  7466. }
  7467. }).catch(e => {
  7468. err++;
  7469. if (ok + err == quickScan.length) {
  7470. resolve(resolutions);
  7471. }
  7472. });
  7473. }
  7474. });
  7475. }
  7476. function GetAllScanResolution$1() {
  7477. return quickScan;
  7478. }
  7479. function isSupportResolution$1(w, h) {
  7480. return new Promise(function (resolve, reject) {
  7481. let videoConstraints = new VideoTrackConstraints(VideoSourceInfo.CAMERA);
  7482. videoConstraints.resolution = new Resolution(w, h);
  7483. MediaStreamFactory.createMediaStream(new StreamConstraints(false, videoConstraints)).then(stream => {
  7484. resolve();
  7485. }).catch(e => {
  7486. reject(e);
  7487. });
  7488. });
  7489. }
  7490. console.log('build date:', BUILD_DATE);
  7491. console.log('version:', VERSION$1);
  7492. const Events = Events$1;
  7493. const Media = media;
  7494. const Endpoint = RTCEndpoint;
  7495. const GetSupportCameraResolutions = GetSupportCameraResolutions$1;
  7496. const GetAllScanResolution = GetAllScanResolution$1;
  7497. const isSupportResolution = isSupportResolution$1;
  7498. exports.Endpoint = Endpoint;
  7499. exports.Events = Events;
  7500. exports.GetAllScanResolution = GetAllScanResolution;
  7501. exports.GetSupportCameraResolutions = GetSupportCameraResolutions;
  7502. exports.Media = Media;
  7503. exports.isSupportResolution = isSupportResolution;
  7504. Object.defineProperty(exports, '__esModule', { value: true });
  7505. return exports;
  7506. })({});
  7507. //# sourceMappingURL=ZLMRTCClient.js.map
  7508. export default ZLMRTCClient;