{"_id":"easemob-emedia","_rev":"33-f6d97589aed1654b9282b294effcce6b","name":"easemob-emedia","dist-tags":{"latest":"3.4.1","beta":"3.4.1-beta"},"versions":{"2.0.1":{"name":"easemob-emedia","version":"2.0.1","description":"webrtc","main":"EMedia_sdk-dev.js","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"author":{"name":"easemob"},"license":"ISC","_id":"easemob-emedia@2.0.1","_nodeVersion":"8.5.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-ps5FilkOL8wxvZiXP7PUh1838SDIWYbt4UtL0nuvCN+/aF/jUNxZF1aaCUTB6kTU8M/mg7q2cTX/andHqcdltg==","shasum":"a7b34c1edfcbea3a0ecbda15c6d5119bacd16792","tarball":"https://registry.npmjs.org/easemob-emedia/-/easemob-emedia-2.0.1.tgz","fileCount":3,"unpackedSize":1407893,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdFHqzCRA9TVsSAnZWagAA/wMP/j4gf6ACJq47LKlMwDM0\nCifN7LdMlhj83sUXgWMUM2wKHosnxCMSnS7MlzNOaz1+VBSNKZRRePnMqTFQ\nod/TZGCcOoXUwmkvCxs/8Alctb3zBMg1nDaR+zz3w4rHX6ZDr9GI1ZZo+RQA\n7qSkuGExJuV5P9lKqJPUKspfemYHI7iOslFdFGiITExDzwWTxaoayCJLAx6y\n0fXjRvEmNxxVvIac82ZvBYTyAC9Zw+UGPdC+Q0a9B+adSNyPkvBkogdS2IGi\n610rDAn1FVeji0YEDBMV30ZnMVLG5fmg0T3T74XE13o9DGskHTFsK41YHN3p\niWViDZr3dslKdiK4DQ6eufxK67p5oB/oU0iw1LXWBjHGCEla8MB66QLQ5HTL\nQK6B+2vwm/XQiDbcsOtgwzLiP3Gr/2haDfwGdJhPMQYSk0nfDBOp6R8O9EHs\nk2G2J8C+p4z7hUs1FASLbrm1dYBiSYYK1kva3bab/yTL8qwqzpzEif1NBjAg\nGIdwsryOey6F/xihF2Benx8s/I2bL4Q3o8a8YwsS4DWX9vy1CIMGQPgXrcab\nM5AtVJpt25iv/ExJ5OwgCiqdwypMxeqdpQWYXdZumGEYQSQoMWGzPHVVwmVF\n4XI8tGvzMmDULTF197GfQmZufefgtc7fxr10jwQaOzypmoBJ/XzLNegGlUwX\nyXJd\r\n=USRd\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCy7qERgdSxSkjlR7uU9vc6UOPJv7Ws3rA9upUDrbodXwIhAKN1G6r3IHxYdIqZl/XOcY6mzHONdlELQJZkse4IttKZ"}]},"maintainers":[{"name":"easemob","email":"npm@easemob.com"}],"_npmUser":{"name":"easemob","email":"npm@easemob.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/easemob-emedia_2.0.1_1561623219056_0.78313052362208"},"_hasShrinkwrap":false},"2.1.1":{"name":"easemob-emedia","version":"2.1.1","description":"webrtc","main":"EMedia_sdk-2.1.1.js","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"author":{"name":"easemob"},"license":"ISC","_id":"easemob-emedia@2.1.1","_nodeVersion":"10.16.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-gtABbhrUzVpNZgYBJh7M73dyqGAFPR69DrVlrCq7R0zsMJhSFWw49vFklalDkBLNyBNA3MDdlZ+A35etP9FLZQ==","shasum":"ced7c4dcc625660f155be56c8335b58fd22ef60d","tarball":"https://registry.npmjs.org/easemob-emedia/-/easemob-emedia-2.1.1.tgz","fileCount":3,"unpackedSize":1407895,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdJGIlCRA9TVsSAnZWagAAynMP/1W6k5bn4TI0NxZ6jKKQ\nyaczK1PSEW6QQ6zkkW4rZtB0znl68g6Xd3BvfCCBsrDnXUBOxaa6EGBYYTxJ\nMNJZhsig/epi+NaoAt5zS6pzerAm4rTAMB/z1bDohbrQkEK6GQw6IDESEduz\nUX2OujLHdAvBZcJ7KKUTqVE0h7lqTSMwOVijESW3H1MuOStWOxwvDss3jHnV\nHD6xvGRlcDfde3f3uRxaelolEZheS3ygHCPdR/FHIr0itbJiFk9yfOkfBKk/\nAWsD+OYQzOkv9Q+a9iqWg4NNQM9XjNKY1CoImOEMoC+Cjnrza122WJZTOgRR\ntBtmkRbzo3JfaZGo/Hmu4VzEhwwruvV+6flKRTKPvPffhMsF53E4+fIdaUth\nMb4DpMXimaAjkeyfxawemCtMQaSAccfK/OMUIh/07M9IrNBdDsm0f7oX+VjI\ng+Ws/jEBkEtr3VcePZNOIvDfruJ0ejgwsaBqOBWpkPYEvcVXDUONqsnNzeNs\naOEdokWC2/2NwYMROlpi3cY/xBy0HmCYp4j3PZIDuzoyLRxpy1fYFkJje7Ep\nXl3Mi97IfmuOs4M6qN/MphmnyNW7fTZesQ5XscwwNO6Hr6zBtdzNGwdnTvZM\njR9Y8vL5xAMeMZdE39carzhQ5bvaUa+Ux64WuWYhcRtWPxM3AmzR7zTAJtYy\nh4Ey\r\n=3RaV\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCBti3arT0IBgIJxD2elk77QHkr1iOU/SSEAZkTnUg/vwIhAPA2+P4wXjJbduRCLSy+lTkEIp4mSu408f0zs/qki30y"}]},"maintainers":[{"name":"easemob","email":"npm@easemob.com"}],"_npmUser":{"name":"easemob","email":"npm@easemob.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/easemob-emedia_2.1.1_1562665508792_0.5790699925522327"},"_hasShrinkwrap":false},"2.1.2":{"name":"easemob-emedia","version":"2.1.2","description":"webrtc","main":"EMedia_sdk-dev.js","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"author":{"name":"easemob"},"license":"ISC","_id":"easemob-emedia@2.1.2","_npmVersion":"5.4.0","_nodeVersion":"8.12.0","_npmUser":{"name":"easemob","email":"npm@easemob.com"},"dist":{"integrity":"sha512-Xsx5JQdlj2wntmNO0gngLDXA9hgO7NAC/Ps9WbATRjRYnZekkBppKU9zuhwo2VWpS92useI97PPlqySsrlZeRw==","shasum":"d69438dff52c676bf8359e78fc9355041d5b63bc","tarball":"https://registry.npmjs.org/easemob-emedia/-/easemob-emedia-2.1.2.tgz","fileCount":3,"unpackedSize":1438314,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdhKzDCRA9TVsSAnZWagAA7l8P/iS9pLHZSgoWKFr4uf4A\n0B3gGgSkuUR9npGz1D/Bg/GngI0WUcce/79RvoKJLq2li5+pCFFvYn4SwUEZ\n2h3qqjMP0gSTl/d6iRMufFIyn5qrplShPBkmxANX36fVTWL3gU8bVZZRJC1J\nH0XolCFa1+gKTASx759R7t6rmR4tYYiC8STxbV9O0Sl8qpvPypseMgNP5Oc9\ncHTukWWlGX8fnnPt+swOyseTuE3JXbGUb2UzYx28tcoAwp7yVWyew3yiu3MC\n+L3R0aWSf0sgA3OzCzIQ7uQ+gGFj7n5N0F2AQwgDn6Wtb8a1SbYBhpvJYVzB\ng85GKCx2/5Z5hl0MKfn0D/LYYzWo6rfit+7OnC8VctizniKBuKZxKvDlk/P1\ng9MiAMSEvLTeqcZwOMuNiQWbgwN7iBfFb63Wy9IkDKzuGxdfX+Mzxbw5Wy03\nMqbGiDgkBxtd9PqLBYi3Onz1OuuTdFGG0gdZ9R4bUPO4EJXd2goFNLoSsYx9\ne0uj9H4M/uagSnFXis3/F36BpNsGG7Oi1Cg2W/lxZeMo3gRYD7+boGhDNBbr\nVmGxhCEZG9RFaIm7y4ePW0aPcax9TPosWiFV2jEb0/NkOMK/s/i5+tNIY9ye\nJoes5prEfvkd0PUkuKZ9uHKAeUwIhYWndydcYWdFl65fwKyCoZn8KTGuu/UO\n8iPO\r\n=KNZA\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCRChGPdFpp8omX0fNAmyUEcRJ+ChvjYr5ek1zN3pDzsQIhAObclqB1M50uXm0vegW0Xe1GjfzeYnPAgpLSv/a1CT+5"}]},"maintainers":[{"name":"easemob","email":"npm@easemob.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/easemob-emedia_2.1.2_1568976066882_0.9415890823029545"},"_hasShrinkwrap":false},"2.1.3":{"name":"easemob-emedia","version":"2.1.3","description":"webrtc","main":"EMedia_sdk-dev.js","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"author":{"name":"easemob"},"license":"ISC","_id":"easemob-emedia@2.1.3","_npmVersion":"6.4.1","_nodeVersion":"8.16.2","_npmUser":{"name":"easemob","email":"npm@easemob.com"},"dist":{"integrity":"sha512-6XwK5wNvMvb3ARIgTO3bFRQ04vIJljZ5t9a6nOgCToUZtWCSKBM9jGRQ+CjjyOPT1I5fCmNqsmaQ7dIjfJQezg==","shasum":"d397009f8f0756ffc97161714d8ad3ca403e84cb","tarball":"https://registry.npmjs.org/easemob-emedia/-/easemob-emedia-2.1.3.tgz","fileCount":3,"unpackedSize":1205296,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeTKy2CRA9TVsSAnZWagAAoqUQAJTSqLr7FJMYuoSEendA\nNOPAhmd33u9KNKWalipdy2zh5S+dWCfWhR2IWaF8Y7s2gbStLbFhjOl6aXWv\n35SS3dWHTSnHCMaekkGMVmwozRpwVXWNJdhdokyVisLdL8yCIkfcAOjYX8ks\nztB8Zl5KGqLSE+TdKFgPIUTmBb75JPKhdS9h+efNWCJl7qXcFS5WrnfeDJWS\nKgu2UrVIBUcr4l0Xl6oj4CrzDtXZ478CSTRpiwOzmAyYV8hm0tSAYW4nbafi\nInITqi7hqTHsqk7iV4C/gxOpkGAoAMYrjk1I8O0333DTHCisBedp83etGuWz\nfGMQkwA8Y97jVIFEyjkVmRFKjxVOL5IFVw5MeauIUTYpHFKhvWaHSadyzfS1\nryTvBOra5T53mqC3tzkY/jj4YyDG9ZhmmL1EIYDxodwAm7t4+iNy9q6cVU0z\nmj6oYn0bHKtrVDO9gSIjUVZh+x6eyNOaUFRMWTS70eT5vw1Lv9kDpx++aTCQ\n5XQsCq4rJdcRteZijtVjeSD9r42p/ms10YlgkiO/Ii1pZGtyCvYC0t7oN7JU\nbnShjw5Y77e3Z/N6RcigDXNurc5JQMlKKjiwYRaIFNfwxwe8uPIa6xsM733K\nR55CF1hfAM+kS/QkicBeW8fQn7jnvaZFWlKS3lMulhQ81zTuheZvKJhFZJUa\nRqPK\r\n=qrts\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCG7DK1DlD5TSsOyZgr8D2RDBnYFd5hC+7VNagZVhmwHwIhAKeepJ8Xmf19xL2wKB6EPaw2Qpzp/2DYJe5VV16OJRtH"}]},"maintainers":[{"name":"easemob","email":"npm@easemob.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/easemob-emedia_2.1.3_1582083253732_0.9553238630991221"},"_hasShrinkwrap":false},"3.0.10":{"name":"easemob-emedia","version":"3.0.10","description":"webrtc","main":"EMedia_sdk.js","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"author":{"name":"easemob"},"license":"ISC","_id":"easemob-emedia@3.0.10","_npmVersion":"6.4.1","_nodeVersion":"8.16.2","_npmUser":{"name":"easemob","email":"npm@easemob.com"},"dist":{"integrity":"sha512-jJaODznpMfpgng1FpE1lAwE4DcPcEaE0oA0680+tNnQi60eF2KftlW9cos1rwceE0QdVzWKOGiPQFuN67cBLNg==","shasum":"280cb323b780b3c2db43cbc34b85a788875b51ae","tarball":"https://registry.npmjs.org/easemob-emedia/-/easemob-emedia-3.0.10.tgz","fileCount":3,"unpackedSize":632257,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJejqsCCRA9TVsSAnZWagAAhpEP/0Cf1lnUXWB3lWZS9B1Y\nELSX6oJ2f0elPcsdILRiz9zIeUQIdHAThGoKlhYa4T/CJ5tq9tEaD8m/e9BH\ncob7vbp8FmxF8Sf7xTY7DSaBHk0UW/10Mdc4AfB/Rz10If36N1gv1HLbGxr3\nwKRCAzC4NfQeItUc2lXixs+FSdLKwrtgTIKqRixUgnUUDHuD8fQhEhCspmul\nxr95+l+PxPHNvsBnkyKdvT1e00avZIOtSh/F/J9DTSFfERZehv5bC81BHa9i\naFP7ctzxXXx63hDZjmxDfgLmUc2mUegsJ8j+iA41QR0Z8MGZjbqBqnySXI/2\nyya8LtwRVadkEVMhZoelZyIrCCepAIJQLo+XCYyUWetMlIRhJ1Aqt9XYgBb7\ngl/20UmntL4d/QpKvt1NIO1Ov5LNex9cvtFUCmcENblvHB4JcMty+PL+23aA\neWa/a3GfWz1mdyg3trN37vzYxuyG/FKaC2UpPyMe9H1FIokEx07G2eJ/SYDF\n7dKmUTELB1EBF2NVJO2wHTE2W/0RmFidDuVPkCcpbSNqDW06OMwEEVgHm+Sn\nnz64BvKWZoXWsfM1V/bW2Y5KZstnwMfW0lRKjF3dlpPr0PjlGzrQWsZuR5F5\nqyszT1XsxwkImntCqbQKiG7fyKwPfgRWYskK6QXAuROSDRWHdU8qVIV+upKr\nxH00\r\n=Q6Zy\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQChvS4XXbBBPdXuD1M7jM6bXfsClmBlQNN6+zzwIekNHQIhAOulCoszmnljfKSfMHBbnBQNitLQfJsAbl0PjURpDDzq"}]},"maintainers":[{"name":"easemob","email":"npm@easemob.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/easemob-emedia_3.0.10_1586408193780_0.39977806256995807"},"_hasShrinkwrap":false},"3.1.0":{"name":"easemob-emedia","version":"3.1.0","description":"webrtc","main":"EMedia_sdk-dev.js","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"author":{"name":"easemob"},"license":"ISC","_id":"easemob-emedia@3.1.0","_npmVersion":"6.4.1","_nodeVersion":"8.16.2","_npmUser":{"name":"easemob","email":"npm@easemob.com"},"dist":{"integrity":"sha512-TSoVgaIOs4ZN0FnzhWfUKHD52J63uw7RJpLbABY83iX0lnC4Zme8SgSQKywWr1pdveacjdfx8VwtK1fkre5S/w==","shasum":"e1b12064b65c2739b103b33875f556f1545b122e","tarball":"https://registry.npmjs.org/easemob-emedia/-/easemob-emedia-3.1.0.tgz","fileCount":3,"unpackedSize":1443207,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJenZG3CRA9TVsSAnZWagAA0bYP/0kdLsGEN3yxAhZVecBk\nZdP44Mc5onbOA2bOGMSLwgmtdRU9LSg2NviNkVupIeEEEDz4jw9yY4cqbCgM\nwu7K/9wj96/770b6usu6sDYLa5nQYOgxkkoCN/jJANYtJPiwPwektu4aM3n6\nT4qYY5k30hFRnktgKfW9rGugxY/shRRvuuhDmqPKzLk+N42bRcie/o2DVwqH\n1MwfXYDgxshZkcaZ2Q31ea1jmmrgHEOZ49Wc7wfuqEklHpgyoy12sAQZNW2W\nEoUwMruK/1eMSayg+CIFbrTakX3rOdKZ3axRecSQGQwUC30Ygx2e/I9jGa42\nGZgoIyclrQz/IXSiBVSHzrAZgBhI1mWrEV+sOpkHKvWlmQYEBR2IouLaPhim\nVI6XT8kLOEyTJPk0fsYUC75JAoqUFQdHYiyDYPRLSu3SMW4v/9rI4qdpSKAh\nXbfhC/5ibniK4p4JplDscJuNSDNs6aZxA1H+UiRZpCMulUOomImqhw+vZ4/Z\n+cMJLWutg5KOIo74niIoLs4ie8+qnOUmjgx/I7KpJbVrNmEBMjAqtn5NDgRh\nRdvUzWgOG3jIDgT/vHqPhdMqjA+4BY3809KVvs9avKp8zWPsx/Ymhk7QFy5z\nrm+VNWQ4aeXt0nJK3UbsM19cGvFMmxeI+RZFMMTuT0UkCof1PD0cabN2TWhT\neSUy\r\n=av2Y\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIH9nhvUpge4vMbiQOLFRlrjwFlcs8fJGJRbvfOa5Q8G6AiEAjLlxhtefZIwmHAQlNWI15h6i19ydQJmwUvN1CfG1/a4="}]},"maintainers":[{"name":"easemob","email":"npm@easemob.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/easemob-emedia_3.1.0_1587384759081_0.8365536096858437"},"_hasShrinkwrap":false},"3.1.2":{"name":"easemob-emedia","version":"3.1.2","description":"webrtc","main":"EMedia_sdk-dev.js","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"author":{"name":"easemob"},"license":"ISC","_id":"easemob-emedia@3.1.2","_nodeVersion":"12.16.3","_npmVersion":"6.14.4","dist":{"integrity":"sha512-tNQQHhpWQYIMgxE3zzyIghE6CdesaF7B8587Ziwd2q4htBAGopdWgGPIv8PBNYLEmgb43iqXrub3/JDsJtwS4w==","shasum":"2033eeb2f43c960558a505d3fce181e2be6055f9","tarball":"https://registry.npmjs.org/easemob-emedia/-/easemob-emedia-3.1.2.tgz","fileCount":3,"unpackedSize":1596096,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeu72OCRA9TVsSAnZWagAAk7QP/RVv4tNPFQGy4y3ZsO+0\naxYm/M7GUS/vnBhLf2u1rePPGUGvsOKrZIzAJnowp2fI8pAVmKkGj3zckHrx\nSIpKms2uBMG+u8RGiz7PdaF17JTuaSuXYroEcXJMtJoNugnm8Mhy81y+2ZYX\nn+Kuq1yo1fYXDwNlgA7FLLi594oIhMevEKDt7qYC5zw2dXcK8Kav4IPNqgg2\nqbPOPq7UlrtyBW0SZn3XjxVsRfOkyQUx09qTRx2XPsEiYqAcMxfWteLxJYQ5\nM78AaNuXjkiEvzqY2Loy2inLjV28+7ziC6JsigTczwAwfz2MUwMULSiGVI6o\nms/BQFwt1yCSArECODCO++zqZv2Hgoj6IZy+KkMxxCImK2quWU8apFDq79tr\nTaU+1LoZkKFaffh9bQqGe4Tt3jEHRbOn9SAhIWzHD9bqfasu0eVS/oKNH9F4\nD3aUT/uf5LWStGuVCQNNT1pEa8s5jO/NrdUxjkIYZOWDNdTLo+cvNyO26p8q\nhGo7K5KrOKmUgMhwsQMadvfSdM5VOx1F+N0kpeRM0i8vKNHQLihKFEj5eWIq\nvRCzdcqE0avob06COjjlXn5gUE1mrZM7lMVM3JMbic8DunCur2auDY9V8EF1\nARFQ2TeVwVzAYSE/P/7up//aTht+qL1t7OJtV/deQCo1+jzDQqqVEwX4oFMQ\nnRtd\r\n=Vg00\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIG/b/PJpruhYlLVbe6lP2O/yHU65PoDdMiljkJzAt4+kAiBa09EyfED6cshWn78eszAGeIMMXAzMC7GYpaTPlmredw=="}]},"maintainers":[{"name":"easemob","email":"npm@easemob.com"}],"_npmUser":{"name":"easemob","email":"npm@easemob.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/easemob-emedia_3.1.2_1589362062293_0.43643570522114494"},"_hasShrinkwrap":false},"3.1.5-beta":{"name":"easemob-emedia","version":"3.1.5-beta","description":"webrtc","main":"EMedia_sdk-dev.js","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"author":{"name":"easemob"},"license":"ISC","readme":"# 集成文档\n\n[简介|功能说明|接入]\n\n**多人音视频Web SDK**是以Websocket为通讯基础，WebRTC为协议，支持多种浏览器 即时多媒体通话功能。通过SDK可快速完成即时视频通话功能。特点概述：\n\n- **浏览器支持** ：Chrome/50, Safari/11, Edge, Firefox；\n- **功能** ：视频通话，音频通话，远程抓拍，远程聚焦、镜头缩放；桌面共享（仅支持Chrome浏览器）；\n- **实现** ：H5，原生JS, 支持require；\n- **限制** ：https\n- **线上DEMO** ：__confr_id__随意定制，相同的为同一个会议<https://turn2.easemob.com/rtc-ws/EMedia/?__log_level___=0&__only_enter__=false&__auto_sub__=true&__url__=wss://turn2.easemob.com/ws&__confr_id__=HelloGod001&__member_name__=God001>\n\n-------------------\n\n# 接入\n\n下载**EMedia-3.0.0.x.zip**并解压后。添加script标签引用。\n\n# 集成\n```javascript\n<script src=\"./webrtc/dist/EMedia_sdk-dev.js\"></script>\n```\n# 创建\n同一个标签页可支持创建多个Service。但几乎没有这种场景。所以不建议在销毁前创建多个service，尽管这是没有问题的。\n\n```javascript\nvar service = new emedia.Service({\n    listeners: { //以下监听，this object == me == service.current\n        //退出\n        onMeExit: function (reason, failed) {\n            reason = (reason || 0);\n            switch (reason){\n                case 0:\n                    reason = \"正常挂断\";\n                    break;\n                case 1:\n                    reason = \"没响应\";\n                    break;\n                case 2:\n                    reason = \"服务器拒绝\";\n                    break;\n                case 3:\n                    reason = \"对方忙\";\n                    break;\n                case 4:\n                    reason = \"失败,可能是网络或服务器拒绝\";\n                    if(failed === -9527){\n                        reason = \"失败,网络原因\";\n                    }\n                    if(failed === -500){\n                        reason = \"Ticket失效\";\n                    }\n                    if(failed === -502){\n                        reason = \"Ticket过期\";\n                    }\n                    if(failed === -504){\n                        reason = \"链接已失效\";\n                    }\n                    if(failed === -508){\n                        reason = \"会议无效\";\n                    }\n                    if(failed === -510){\n                        reason = \"服务端限制\";\n                    }\n                    break;\n                case 5:\n                    reason = \"不支持\";\n                    break;\n                case 10:\n                    reason = \"其他设备登录\";\n                    break;\n                case 11:\n                    reason = \"会议关闭\";\n                    break;\n            }\n        },\n        //member加入会议\n        onAddMember: function (member) {\n        },\n        //member离开会议\n        onRemoveMember: function (member) {\n        },\n        //收到一个业务流\n        onAddStream: function (stream) {\n        },\n        //移除一个业务流\n        onRemoveStream: function (stream) {\n        },\n        //业务流更新\n        onUpdateStream: function (stream, update) {\n        },\n        //当前通话连接质量不佳\n        onNetworkWeak: function () {\n        },\n        //各类事件\n        onNotifyEvent: function (evt) {\n            if(evt instanceof emedia.event.ServerRefuseEnter){ //服务端拒绝进入\n            } else if(evt instanceof emedia.event.EnterSuccess){ //进入会议成功\n            } else if(evt instanceof emedia.event.EnterFail){ //进入会议失败\n            } else if(evt instanceof emedia.event.ICERemoteMediaStream) { //成功获取对方媒体数据 如：视频\n            } else if(evt instanceof emedia.event.PushSuccess){ //推流成功。本地打开摄像头并将数据成功发送\n            } else if(evt instanceof emedia.event.SubSuccess){ //订阅成功，可以看到对方了\n            } else if(evt instanceof emedia.event.PushFail){ //推送失败\n            } else if(evt instanceof emedia.event.SubFail){ //推送成功\n            } else if(evt instanceof emedia.event.ShareDesktopExtensionNotFound){ //共享桌面插件未找到\n            } else if(evt instanceof emedia.event.RemoteControlFail){ //远程控制失败，仅能web端控制sdk端\n            }\n        }\n    }\n});\n```\n\n\n# 初始化\n加入会议的凭证 是 tkt，只要获取到tkt，便能工作\n```javascript\nservice.setup(tkt_string, {role: 'admin'}/*扩展字段*/);\n```\n\n# member\n```javascript\n...\nonAddMember: function (member) {\n},\nonRemoveMember: function (member) {\n},\n...\n```\n\n```json\n{\n    \"ext\":{ //service.setup(tkt_string, {role: 'admin'}/*扩展字段*/);\n        \"identity\":\"visitor\",\n        \"nickname\":\"webim-visitor-9F72MEK793H97XQGFBKM\",\n        \"avatarUrl\":\"\"\n    },\n    \"nickName\":\"webim-visitor-9F72MEK793H97XQGFBKM\",\n    \"id\":\"MS_X197721744293023744C19M197756407719972865VISITOR\",\n    \"name\":\"a63ceeb6-64c2-426d-9803-a40dd5557d7c\",\n    \"vcodes\":[\n        \"VP8\",\n        \"H264\"\n    ]\n}\n```\n# stream\n```javascript\n...\n//收到一个业务流\nonAddStream: function (stream) {\n},\n//移除一个业务流\nonRemoveStream: function (stream) {\n},\n//业务流更新\nonUpdateStream: function (stream, update) {\n    update.ifMediaStream(function (mediaStream) { //媒体数据发生变化\n        video.srcObject = null;\n        video.srcObject = mediaStream;\n    });\n    update.ifVoff(function (voff) { //对方 开启/关闭 视频\n    });\n    update.ifAoff(function (aoff) { //对方 开启/关闭 音频\n    });\n},\n...\n```\n```json\n{\n    \"memId\":\"MS_X197721744293023744C19M197756407719972865VISITOR\",\n    \"id\":\"RTC2__Of_C19M197756407719972865VISITOR\",\n    \"voff\":0, //1 视频关闭 \n    \"aoff\":0, //1 音频关闭 \n    \"vcodes\":[\n        \"VP8\",\n        \"H264\"\n    ],\n    \"owner\": member ,//member对象\n    \"rtcId\":\"RTC1\",\n    \"subArgs\":{\n        \"subSVideo\":true,\n        \"subSAudio\":true\n    }\n}\n```\n\n# 打开媒体设备：麦克风、摄像头\n```javascript\n //创建一个音视频流\nvar pubS = new service.AVPubstream({\n    constaints: { //可缺省，麦克风 摄像头均打开；若设置，audio video 至少有一个为true\n        audio: true|false, //默认true, 打开 麦克风\n        video: true|false, //默认true, 打开 摄像头\n    },\n    aoff: 0, // 指定给对方 是否 关闭了音频, 默认0\n    voff: 0, // 指定给对方 是否 关闭了视频, 默认0\n    name: \"video\", // 视频名称（根据业务情况设定），可缺省\n    ext: { //支持 媒体流 扩展描述，根据业务情况设定。此参数广播到其他人\n        browser: app.appname\n    }\n});\n\n//Chrome 浏览器\n//桌面共享流，选装插件\n//插件地址 https://turn2.easemob.com/simonweb/confr-http/rtc-share-desktop.crx\nvar pubS = new service.ShareDesktopPubstream({name: \"共享桌面\"}); \n\n//混音通话\nvar pubS = new service.AudioMixerPubstream({\n    constaints: {\n        video : \"false\" !== __video__,\n    },\n    aoff: 0\n});\n\nservice.openUserMedia(pubS).then(function () {\n    //打开媒体流成功\n}, function fail(evt) { //打开媒体流失败\n    //共享桌面抄件未找到\n    if(evt instanceof emedia.event.ShareDesktopExtensionNotFound){ \n    }\n    //设备可能不支持，比如 没有摄像头，或 被禁止访问摄像头\n    if(evt instanceof emedia.event.OpenMediaError){ \n    }\n});\n```\n\n# 加入会议\n```javascript\n//在此之前 应该 service.setup(tkt_string, {role: 'admin'}/*扩展字段*/);\nservice.join(function onSuccess() {\n});\n```\n\n# 加入会议，并推送媒体流\n```javascript\nservice.withpublish(pubS).join();\n//在此之前应该openUserMedia。例如：\nservice.openUserMedia(pubS).then(\n    function success(_user, stream) { //成功 video.srcObject = stream\n        service.withpublish(pubS).join();\n    },\n    function fail(evt) {\n        \n    }\n);\n```\n\n# 手动推送媒体流\n```javascript\nservice.push(pubS);\n\n//在此之前应该openUserMedia 并且 join 成功。例如：\nservice.join(function onSuccess() {\n});\n\nservice.openUserMedia(pubS).then(\n    function success(_user, stream) { //成功 video.srcObject = stream\n        service.push(pubS);\n    },\n    function fail(evt) {\n        \n    }\n);\n```\n\n# 手动订阅对方媒体流\n如果配置为自动订阅，可忽略，sdk会自动订阅 stream\n```javascript\nonAddStream: function (stream) {\n    service.subscribe(stream.id, function (_evt) {\n        //订阅失败\n    }, {subSVideo: true|false}); //true:订阅视频，false:订阅音频\n},\n```\n\n# 开启/关闭自己摄像头\n```javascript\nservice.voff(stream, true|false, function fail(evt) {\n});\n```\n\n# 开启/关闭自己麦克风\n```javascript\nservice.aoff(stream, true|false, function fail(evt) {\n});\n```\n\n# 控制手机SDK摄像头，放大缩小\n```javascript\nservice.zoomRemote(stream.id, 2|0.5, function fail(evt){// 放大2倍，缩小0.5\n});\n```\n\n# 抓拍手机SDK摄像头\n```javascript\nservice.capturePictureRemote(stream.id, false, \n    function success(base64Pic) {\n    }, \n    function fail(evt) {\n    }\n);\n```\n\n# 控制手机SDK摄像头 聚焦；在video标签上添加点击事件\n```javascript\nvideo.onclick = function (event) {\n    if (document.all) { // for IE\n        window.event.returnValue = false;\n    } else {\n        event.preventDefault();\n    }\n\n    if(stream.located()){\n        displayEvent(\"Web本地摄像头不支持聚焦\");\n        return;\n    }\n    service.focusExpoRemote(stream.id, video, event, function fail(evt) {\n        _logger.error(\"Oh,no.\", evt.message())\n    });\n}\n```\n\n# 控制手机SDK摄像头 图像定格/恢复。\n```javascript\n//freezeFramed true：图像定格\nservice.freezeFrameRemote(stream.id, function success(freezeFramed) {\n}, function fail(evt, freezeFramed) {\n});\n```\n\n# SDK增强，开启支持远程控制\n```javascript\nemedia.ctrl.support(service,\n    function onHasRemoteControl(stream, controler, controlRequest){\n        var rtn = confirm(\"同意 来自<\" + controler.memName + \">对流:\" + stream.id + \"控制申请吗？\")\n        if(rtn){ //同意被控制\n            var htmlId = stream.getHtmlDOMID();\n            var $div = $('#' + htmlId);\n\n            var $video = $div.find(\"#videoTag\");\n            var $videoTrack = $div.find(\"#video_box #track\");\n            var $canvas = $div.find(\"#video_box canvas\");\n\n            $videoTrack.show();\n            $canvas.show();\n\n            controlRequest.accept($video[0], new MouseTrack({\n                _target: $videoTrack[0],\n                _canvas: $canvas[0],\n                _video: $video[0]\n            }), new KeyboardTrack());\n        }else{ //拒绝\n            controlRequest.reject();\n        }\n    },\n\n    function onRemoteFreeControl(stream, controler, cId) {\n    \t...    \n    }\n);\n```\n# SDK增强，发起控制\n```javascript\nfunction onReject(stream) { //被控端拒绝\n}\n\nfunction onBusy(stream) { //被控端忙\n}\n\nfunction onNotAllowRemoteControl(stream){ //被控端忙\n}\n\nfunction onRemoteControlTimeout(stream){ //被控端超时\n}\n\nfunction onAccept(stream){ //被控端接受\n}\n\nfunction onDisControlled(stream){ //断开控制链接\n}\n    \nif($(videoObj).hasClass('mirror')){\n    emedia.ctrl.mirrorControlled(service, stream.id, videoObj, targetDiv,\n        onDisControlled, onAccept, onNotAllowRemoteControl, onRemoteControlTimeout, onReject, onBusy);\n}else{\n    emedia.ctrl.controlled(service, stream.id, videoObj, targetDiv,\n        onDisControlled, onAccept, onNotAllowRemoteControl, onRemoteControlTimeout, onReject, onBusy);\n}\n\n```\n\n\n\n# 退出会议\n```javascript\n//退出会议，会回调onMeExit\n//退出会议后，可再次setup ticket.\n//setup生命周期 起， exit生命周期止\nservice.exit();\n```\n\n# 配置emedia\n\n```javascript\nemedia.config({\n    logLevel: 0, //日志级别，>5 关闭SDK，日志。默认级别 0       \n        // TRACE: 0,\n        // DEBUG: 1,\n        // INFO: 2,\n        // WARN: 3,\n        // ERROR: 4,\n        // FATAL: 5\n    autoSub: true, //当收到对方媒体流时，自动订阅, 默认值：true\n    enterTimeout: 20000, //单位ms，join 20秒内未返回 join失败，默认值20000\n});\n\n//重要常量\nemedia.config.version //sdk版本\nemedia.LOG_LEVEL //sdk日志级别，可在运行时通过控制台命令行 手动设置，可实时打开日志\nemedia.isFirefox //true 火狐\nemedia.isChrome  //true Chrome\nemedia.isSafari  //true Safari\nemedia.isWebRTC //true支持webrtc false不支持webrtc\n```\n","readmeFilename":"readme.md","_id":"easemob-emedia@3.1.5-beta","_nodeVersion":"8.16.2","_npmVersion":"6.14.4","dist":{"integrity":"sha512-La63oUq0A1VxUc1To/Y5KzJfWZTYyG93rGxtLfwHBjqAe6lRtvpxxX8MZSxYgum1a0BBKrhCKqTKOwvrEJm4ig==","shasum":"7e3b6a81147adb8380121867a6ab98e266836510","tarball":"https://registry.npmjs.org/easemob-emedia/-/easemob-emedia-3.1.5-beta.tgz","fileCount":3,"unpackedSize":1602514,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe8ansCRA9TVsSAnZWagAAA9cP+weHplF5TFJrVgWNrUo8\nCnjCpuw6A333xU+ClqRRlQJ2RnZjW38thOms847X8BBNrbz6HVgxAuNiX1CB\nUaPA5zWmZPGiXSChfrefA9lnsVDTW936Vjl5CJT/+JQrpC3adhrWLoOTosRB\nlsjHMsZrWWGTrjO/ZxJiZtc2KhC8r6OEJ8LrGMvw4/VnsmwJ/cD3/dZj+Bs/\n/ei5qFu9KRX69NIruFmc16+lS82FfInKRd0YpJ/HzWhy0lWkygw6cYfKAUpY\nKM6pjQdWBVNb3zg7lnpSb4syFKJGtzXFCBMryArhFTa1bB+/KMKUrnSGXpnC\nG8cPhRBoVKj3nJHGqfIbnMRRQ/ZKyBw2zwAs+8SX3qakLfPrkRGBf+C8DAa8\njhE6HMPLcPU4ISXIYZfsv5hZKpEztMEPSxfZ/v41GX80U/pnEe+hCkP9+ij4\njWVmzWnWt3oY3AeFU316DarQehLYRHu2JX738rAA/3DENf8SLRFvGrQ1VQT3\nbHRVxN+B+VcTGOENOlotDf4ZpGaNiwC7bDGAzgvUrnXL/idmq7rF9m2lzMTu\nfCYSxYfNywEbgMKCLUFzFx/cu4icsFHuTR5Y9m2rZNbDUi+2ushU6jZsTxlj\n2MYb6gihC4TYBaJujX3kIkUXbmmqJ+ayKL3sFd5XpcUiyN4VZFVeKmfHR19k\nbTXi\r\n=1JCN\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICjmSNix3C7euBz8aMX7APb+eXlm3mVYnjcIkUiMf785AiAoNwgSg+5ZFfUO/XUBwJjhp3gwIVFl3hp71ZWHM9Dd4Q=="}]},"maintainers":[{"name":"easemob","email":"npm@easemob.com"}],"_npmUser":{"name":"easemob","email":"npm@easemob.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/easemob-emedia_3.1.5-beta_1592895980496_0.47535505361260255"},"_hasShrinkwrap":false},"3.1.5":{"name":"easemob-emedia","version":"3.1.5","description":"webrtc","main":"EMedia_sdk-dev.js","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"author":{"name":"easemob"},"license":"ISC","_id":"easemob-emedia@3.1.5","_nodeVersion":"8.16.2","_npmVersion":"6.14.4","dist":{"integrity":"sha512-OCQSaVs/Q20eqrXIzajjJeiOXmjUptT8KTGyy0SZCJjaGx0e/6Nqlt4NWAggaB2zbzCvFoXmXyT+nx9RPZs7MQ==","shasum":"3e764003bf14a6fba3f1ee7232398384c42ef003","tarball":"https://registry.npmjs.org/easemob-emedia/-/easemob-emedia-3.1.5.tgz","fileCount":3,"unpackedSize":1602509,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe8blnCRA9TVsSAnZWagAAU78P/3mnPoVMfQGFqy9kCyMB\nqYhNzjBRCgR4W6HW4Bsu4Mv/XuhVNwqUOS/Tkue1oo/Edh6ED0DoDjyeGPFe\nh4Uvyz1Eu2B/EAIl9mKbFu+6irnPKewLzFvCr1XMoNzy8ecPVV6K6CIyaazl\nJLrHDKnBBFYMjRkzNaqJ5TlEFlfA//3qhnobDAlnWBnFo+/AdsEnNlKNnzvq\n6eJD88500m3fcAc9sQzvby9xjKoXIV55y5iU0CB1Vo0sGVlwg0S2ZTJ6HfkV\ntM8VQaEJr9pXsQ+DT9UCh/oEFlQve/pOs5L/DdR4JSU7sSU1Ba2nm0CUUn8H\nP+RnLK+nyGrA7ueboi19NG0mo6YWeQS+yIgOkkKhLXVohPCrhJHf2ov1aOaD\nx/Ckp1wMHGOXWKZhn4whFXhnuBmWOmCVqHzyclF0xXoHnhtKcQRDK3Vf31Kx\nwYcMfOyscucDCA70vnc4O/I9Ut8upJHNILqb4GD1tXvSbxXfJU0B4L4qJ8mt\nZWNDteseMuZp2VdGDWrGo3HDxSYr408Q2HFj2+o4Ub1CwHDglqL7SPif++TZ\nbuD6SyX8+lPQXnFWOr4nKJCzvbeRhIen8axds/DSXId+hBQd++gBJql1xNaW\nXHRV2Eu2JvdTE9FbTAb9ZPNLcWkTIrCUM/oh5112P/QdnlpS6SOywlMN5/jg\n6fvL\r\n=x9U0\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDxZ0HrRZrMJY26tf1EMMk/n7kwyWmGcv9iyVRLo3JpkQIhAPsqfDh1Y628YOemtHmoGXuhAnZs22fPZuaY0c4LMXw0"}]},"maintainers":[{"name":"easemob","email":"npm@easemob.com"}],"_npmUser":{"name":"easemob","email":"npm@easemob.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/easemob-emedia_3.1.5_1592899942587_0.152770108708008"},"_hasShrinkwrap":false},"3.2.0":{"name":"easemob-emedia","version":"3.2.0","description":"webrtc","main":"EMedia_sdk-dev.js","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"author":{"name":"easemob"},"license":"ISC","_id":"easemob-emedia@3.2.0","_nodeVersion":"8.16.2","_npmVersion":"6.14.4","dist":{"integrity":"sha512-9rDUl4LVfTjrdWRWpjhlqaPwZIklxoZqOeKsoXhnGZE639ifyFnxRuDcEzlcu/m4SL0fjT1YrkANRHwGAaagqQ==","shasum":"0c1c5d8e8683a8da43f7b746677d9c18079ad7f2","tarball":"https://registry.npmjs.org/easemob-emedia/-/easemob-emedia-3.2.0.tgz","fileCount":3,"unpackedSize":1603018,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfBs+jCRA9TVsSAnZWagAAfjEP/22SdI+oobAIipuQS6A9\nGhXrZdOHifKt6VO6qzfyZy820R2QbF3zg1aoG6ngdCZ8roV14OviDnvHlCxH\n31ZbvBzqz+0lr4IE0bAvjUwGfHLbPNAkYanQ+4vaijCInXZF8UatO+TTlWOH\nBUfmJUQpj8KpczvsP7P2g1flenv9dWbhBUG4tC8pfQgUwMR0HYh/C7OV4UBR\nCXzlPvu+1+J05C08J8ZaQ3urbTch1JYiEkxyVvNifmvfonfn+epfEKiOpVkN\n86OuVRFCPRmr2roHMVb8o0NBilGremEA2jYp5ypDc2j1AmVEHHS47xcUaZpH\nRWIyZlVWd561NYEqZPIIPtmZv08xCVlWyfBbFXRDOxmaq74tEHE9VYd6iZ2C\nA/cBfoAiePcwFp0CvV36REQ+5BvqmtCOm6ChVvlHwKuDUP/J4CUrg+fRfaCA\nQonAh6thdoukH9u3QSg/rJDum2DAZ/tykwFINYEBZ6s3RvlncfiAIGgafgiH\nYwejdMK/v5u07PSxnTkosz4AbhBpxTp6pKzostKQSrbe/FVv3NL5DDmqJ4Tq\nVPfa7Yk+LoPE+BiXpT0Cb5VJTlmcDVIM8fm2VnWzkclpY2k3qnIY8osa854q\nLqcsobZbZ8gNX2p5O7ylyr93Dly1mRocbv5X4H4E60pWfjwljoiCOmn4LJEO\nvSS6\r\n=WnfY\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIH55+qcVAUSBS8ziqTDApWV1zfMbMPBoTmf8jrXps4Y2AiA9VfLP4XA+HNdIU0HjBQA9rqNEAU7uk7D4OCJ1N3Y+zw=="}]},"maintainers":[{"name":"easemob","email":"npm@easemob.com"}],"_npmUser":{"name":"easemob","email":"npm@easemob.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/easemob-emedia_3.2.0_1594281891117_0.6840633593923386"},"_hasShrinkwrap":false},"3.2.1-beta":{"name":"easemob-emedia","version":"3.2.1-beta","description":"webrtc","main":"EMedia_sdk-dev.js","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"author":{"name":"easemob"},"license":"ISC","readme":"# 集成文档\n\n[简介|功能说明|接入]\n\n**多人音视频Web SDK**是以Websocket为通讯基础，WebRTC为协议，支持多种浏览器 即时多媒体通话功能。通过SDK可快速完成即时视频通话功能。特点概述：\n\n- **浏览器支持** ：Chrome/50, Safari/11, Edge, Firefox；\n- **功能** ：视频通话，音频通话，远程抓拍，远程聚焦、镜头缩放；桌面共享（仅支持Chrome浏览器）；\n- **实现** ：H5，原生JS, 支持require；\n- **限制** ：https\n- **线上DEMO** ：__confr_id__随意定制，相同的为同一个会议<https://turn2.easemob.com/rtc-ws/EMedia/?__log_level___=0&__only_enter__=false&__auto_sub__=true&__url__=wss://turn2.easemob.com/ws&__confr_id__=HelloGod001&__member_name__=God001>\n\n-------------------\n\n# 接入\n\n下载**EMedia-3.0.0.x.zip**并解压后。添加script标签引用。\n\n# 集成\n```javascript\n<script src=\"./webrtc/dist/EMedia_sdk-dev.js\"></script>\n```\n# 创建\n同一个标签页可支持创建多个Service。但几乎没有这种场景。所以不建议在销毁前创建多个service，尽管这是没有问题的。\n\n```javascript\nvar service = new emedia.Service({\n    listeners: { //以下监听，this object == me == service.current\n        //退出\n        onMeExit: function (reason, failed) {\n            reason = (reason || 0);\n            switch (reason){\n                case 0:\n                    reason = \"正常挂断\";\n                    break;\n                case 1:\n                    reason = \"没响应\";\n                    break;\n                case 2:\n                    reason = \"服务器拒绝\";\n                    break;\n                case 3:\n                    reason = \"对方忙\";\n                    break;\n                case 4:\n                    reason = \"失败,可能是网络或服务器拒绝\";\n                    if(failed === -9527){\n                        reason = \"失败,网络原因\";\n                    }\n                    if(failed === -500){\n                        reason = \"Ticket失效\";\n                    }\n                    if(failed === -502){\n                        reason = \"Ticket过期\";\n                    }\n                    if(failed === -504){\n                        reason = \"链接已失效\";\n                    }\n                    if(failed === -508){\n                        reason = \"会议无效\";\n                    }\n                    if(failed === -510){\n                        reason = \"服务端限制\";\n                    }\n                    break;\n                case 5:\n                    reason = \"不支持\";\n                    break;\n                case 10:\n                    reason = \"其他设备登录\";\n                    break;\n                case 11:\n                    reason = \"会议关闭\";\n                    break;\n            }\n        },\n        //member加入会议\n        onAddMember: function (member) {\n        },\n        //member离开会议\n        onRemoveMember: function (member) {\n        },\n        //收到一个业务流\n        onAddStream: function (stream) {\n        },\n        //移除一个业务流\n        onRemoveStream: function (stream) {\n        },\n        //业务流更新\n        onUpdateStream: function (stream, update) {\n        },\n        //当前通话连接质量不佳\n        onNetworkWeak: function () {\n        },\n        //各类事件\n        onNotifyEvent: function (evt) {\n            if(evt instanceof emedia.event.ServerRefuseEnter){ //服务端拒绝进入\n            } else if(evt instanceof emedia.event.EnterSuccess){ //进入会议成功\n            } else if(evt instanceof emedia.event.EnterFail){ //进入会议失败\n            } else if(evt instanceof emedia.event.ICERemoteMediaStream) { //成功获取对方媒体数据 如：视频\n            } else if(evt instanceof emedia.event.PushSuccess){ //推流成功。本地打开摄像头并将数据成功发送\n            } else if(evt instanceof emedia.event.SubSuccess){ //订阅成功，可以看到对方了\n            } else if(evt instanceof emedia.event.PushFail){ //推送失败\n            } else if(evt instanceof emedia.event.SubFail){ //推送成功\n            } else if(evt instanceof emedia.event.ShareDesktopExtensionNotFound){ //共享桌面插件未找到\n            } else if(evt instanceof emedia.event.RemoteControlFail){ //远程控制失败，仅能web端控制sdk端\n            }\n        }\n    }\n});\n```\n\n\n# 初始化\n加入会议的凭证 是 tkt，只要获取到tkt，便能工作\n```javascript\nservice.setup(tkt_string, {role: 'admin'}/*扩展字段*/);\n```\n\n# member\n```javascript\n...\nonAddMember: function (member) {\n},\nonRemoveMember: function (member) {\n},\n...\n```\n\n```json\n{\n    \"ext\":{ //service.setup(tkt_string, {role: 'admin'}/*扩展字段*/);\n        \"identity\":\"visitor\",\n        \"nickname\":\"webim-visitor-9F72MEK793H97XQGFBKM\",\n        \"avatarUrl\":\"\"\n    },\n    \"nickName\":\"webim-visitor-9F72MEK793H97XQGFBKM\",\n    \"id\":\"MS_X197721744293023744C19M197756407719972865VISITOR\",\n    \"name\":\"a63ceeb6-64c2-426d-9803-a40dd5557d7c\",\n    \"vcodes\":[\n        \"VP8\",\n        \"H264\"\n    ]\n}\n```\n# stream\n```javascript\n...\n//收到一个业务流\nonAddStream: function (stream) {\n},\n//移除一个业务流\nonRemoveStream: function (stream) {\n},\n//业务流更新\nonUpdateStream: function (stream, update) {\n    update.ifMediaStream(function (mediaStream) { //媒体数据发生变化\n        video.srcObject = null;\n        video.srcObject = mediaStream;\n    });\n    update.ifVoff(function (voff) { //对方 开启/关闭 视频\n    });\n    update.ifAoff(function (aoff) { //对方 开启/关闭 音频\n    });\n},\n...\n```\n```json\n{\n    \"memId\":\"MS_X197721744293023744C19M197756407719972865VISITOR\",\n    \"id\":\"RTC2__Of_C19M197756407719972865VISITOR\",\n    \"voff\":0, //1 视频关闭 \n    \"aoff\":0, //1 音频关闭 \n    \"vcodes\":[\n        \"VP8\",\n        \"H264\"\n    ],\n    \"owner\": member ,//member对象\n    \"rtcId\":\"RTC1\",\n    \"subArgs\":{\n        \"subSVideo\":true,\n        \"subSAudio\":true\n    }\n}\n```\n\n# 打开媒体设备：麦克风、摄像头\n```javascript\n //创建一个音视频流\nvar pubS = new service.AVPubstream({\n    constaints: { //可缺省，麦克风 摄像头均打开；若设置，audio video 至少有一个为true\n        audio: true|false, //默认true, 打开 麦克风\n        video: true|false, //默认true, 打开 摄像头\n    },\n    aoff: 0, // 指定给对方 是否 关闭了音频, 默认0\n    voff: 0, // 指定给对方 是否 关闭了视频, 默认0\n    name: \"video\", // 视频名称（根据业务情况设定），可缺省\n    ext: { //支持 媒体流 扩展描述，根据业务情况设定。此参数广播到其他人\n        browser: app.appname\n    }\n});\n\n//Chrome 浏览器\n//桌面共享流，选装插件\n//插件地址 https://turn2.easemob.com/simonweb/confr-http/rtc-share-desktop.crx\nvar pubS = new service.ShareDesktopPubstream({name: \"共享桌面\"}); \n\n//混音通话\nvar pubS = new service.AudioMixerPubstream({\n    constaints: {\n        video : \"false\" !== __video__,\n    },\n    aoff: 0\n});\n\nservice.openUserMedia(pubS).then(function () {\n    //打开媒体流成功\n}, function fail(evt) { //打开媒体流失败\n    //共享桌面抄件未找到\n    if(evt instanceof emedia.event.ShareDesktopExtensionNotFound){ \n    }\n    //设备可能不支持，比如 没有摄像头，或 被禁止访问摄像头\n    if(evt instanceof emedia.event.OpenMediaError){ \n    }\n});\n```\n\n# 加入会议\n```javascript\n//在此之前 应该 service.setup(tkt_string, {role: 'admin'}/*扩展字段*/);\nservice.join(function onSuccess() {\n});\n```\n\n# 加入会议，并推送媒体流\n```javascript\nservice.withpublish(pubS).join();\n//在此之前应该openUserMedia。例如：\nservice.openUserMedia(pubS).then(\n    function success(_user, stream) { //成功 video.srcObject = stream\n        service.withpublish(pubS).join();\n    },\n    function fail(evt) {\n        \n    }\n);\n```\n\n# 手动推送媒体流\n```javascript\nservice.push(pubS);\n\n//在此之前应该openUserMedia 并且 join 成功。例如：\nservice.join(function onSuccess() {\n});\n\nservice.openUserMedia(pubS).then(\n    function success(_user, stream) { //成功 video.srcObject = stream\n        service.push(pubS);\n    },\n    function fail(evt) {\n        \n    }\n);\n```\n\n# 手动订阅对方媒体流\n如果配置为自动订阅，可忽略，sdk会自动订阅 stream\n```javascript\nonAddStream: function (stream) {\n    service.subscribe(stream.id, function (_evt) {\n        //订阅失败\n    }, {subSVideo: true|false}); //true:订阅视频，false:订阅音频\n},\n```\n\n# 开启/关闭自己摄像头\n```javascript\nservice.voff(stream, true|false, function fail(evt) {\n});\n```\n\n# 开启/关闭自己麦克风\n```javascript\nservice.aoff(stream, true|false, function fail(evt) {\n});\n```\n\n# 控制手机SDK摄像头，放大缩小\n```javascript\nservice.zoomRemote(stream.id, 2|0.5, function fail(evt){// 放大2倍，缩小0.5\n});\n```\n\n# 抓拍手机SDK摄像头\n```javascript\nservice.capturePictureRemote(stream.id, false, \n    function success(base64Pic) {\n    }, \n    function fail(evt) {\n    }\n);\n```\n\n# 控制手机SDK摄像头 聚焦；在video标签上添加点击事件\n```javascript\nvideo.onclick = function (event) {\n    if (document.all) { // for IE\n        window.event.returnValue = false;\n    } else {\n        event.preventDefault();\n    }\n\n    if(stream.located()){\n        displayEvent(\"Web本地摄像头不支持聚焦\");\n        return;\n    }\n    service.focusExpoRemote(stream.id, video, event, function fail(evt) {\n        _logger.error(\"Oh,no.\", evt.message())\n    });\n}\n```\n\n# 控制手机SDK摄像头 图像定格/恢复。\n```javascript\n//freezeFramed true：图像定格\nservice.freezeFrameRemote(stream.id, function success(freezeFramed) {\n}, function fail(evt, freezeFramed) {\n});\n```\n\n# SDK增强，开启支持远程控制\n```javascript\nemedia.ctrl.support(service,\n    function onHasRemoteControl(stream, controler, controlRequest){\n        var rtn = confirm(\"同意 来自<\" + controler.memName + \">对流:\" + stream.id + \"控制申请吗？\")\n        if(rtn){ //同意被控制\n            var htmlId = stream.getHtmlDOMID();\n            var $div = $('#' + htmlId);\n\n            var $video = $div.find(\"#videoTag\");\n            var $videoTrack = $div.find(\"#video_box #track\");\n            var $canvas = $div.find(\"#video_box canvas\");\n\n            $videoTrack.show();\n            $canvas.show();\n\n            controlRequest.accept($video[0], new MouseTrack({\n                _target: $videoTrack[0],\n                _canvas: $canvas[0],\n                _video: $video[0]\n            }), new KeyboardTrack());\n        }else{ //拒绝\n            controlRequest.reject();\n        }\n    },\n\n    function onRemoteFreeControl(stream, controler, cId) {\n    \t...    \n    }\n);\n```\n# SDK增强，发起控制\n```javascript\nfunction onReject(stream) { //被控端拒绝\n}\n\nfunction onBusy(stream) { //被控端忙\n}\n\nfunction onNotAllowRemoteControl(stream){ //被控端忙\n}\n\nfunction onRemoteControlTimeout(stream){ //被控端超时\n}\n\nfunction onAccept(stream){ //被控端接受\n}\n\nfunction onDisControlled(stream){ //断开控制链接\n}\n    \nif($(videoObj).hasClass('mirror')){\n    emedia.ctrl.mirrorControlled(service, stream.id, videoObj, targetDiv,\n        onDisControlled, onAccept, onNotAllowRemoteControl, onRemoteControlTimeout, onReject, onBusy);\n}else{\n    emedia.ctrl.controlled(service, stream.id, videoObj, targetDiv,\n        onDisControlled, onAccept, onNotAllowRemoteControl, onRemoteControlTimeout, onReject, onBusy);\n}\n\n```\n\n\n\n# 退出会议\n```javascript\n//退出会议，会回调onMeExit\n//退出会议后，可再次setup ticket.\n//setup生命周期 起， exit生命周期止\nservice.exit();\n```\n\n# 配置emedia\n\n```javascript\nemedia.config({\n    logLevel: 0, //日志级别，>5 关闭SDK，日志。默认级别 0       \n        // TRACE: 0,\n        // DEBUG: 1,\n        // INFO: 2,\n        // WARN: 3,\n        // ERROR: 4,\n        // FATAL: 5\n    autoSub: true, //当收到对方媒体流时，自动订阅, 默认值：true\n    enterTimeout: 20000, //单位ms，join 20秒内未返回 join失败，默认值20000\n});\n\n//重要常量\nemedia.config.version //sdk版本\nemedia.LOG_LEVEL //sdk日志级别，可在运行时通过控制台命令行 手动设置，可实时打开日志\nemedia.isFirefox //true 火狐\nemedia.isChrome  //true Chrome\nemedia.isSafari  //true Safari\nemedia.isWebRTC //true支持webrtc false不支持webrtc\n```\n","readmeFilename":"readme.md","_id":"easemob-emedia@3.2.1-beta","_nodeVersion":"8.16.2","_npmVersion":"6.14.4","dist":{"integrity":"sha512-tvfCg+5Vf4ndFR/yMJkelieG9femUTxZN7r/1EeTnLNzGXx6jjBDXNlvm40hSNYFRV4CkTkpzVbabkQfTKdhww==","shasum":"16475023be8013109981e6c5f344b5bf05eea660","tarball":"https://registry.npmjs.org/easemob-emedia/-/easemob-emedia-3.2.1-beta.tgz","fileCount":3,"unpackedSize":1603132,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfH9ivCRA9TVsSAnZWagAAYvsP/RRLIs+fWEf+0QSrivLq\nva7tC2LzPo49uVh/+hl/jr/42iwYutfxRDzly02knwSriAC98pTN1hPos0tP\nuyGHo+TpR+kL03bIR16j0JgxkrUO22iVSJ0jywOESyprZwrJd97vRZOjKgZy\nOYNJ5YwnyBXLIkqQkqx/cVpwt9fm9R0IYHBPEPK6MAWJxtYvKbUnWMZ4iV49\nBg8NpkoTGjimTiuMiTJss3zX2DblCXTHRJMFWExGtfPWq4GtAdiqjyhdlP6l\nnwAKhFztRMsdjt5Ccw1oHqcyxYCbEzgf+V8cJCD0TURjO5soTnbuNdTSxyW7\neXnLonUMzIYcInJL1nihXl4xLxRT0/PsCn4++a9BiQsRWU3HJSnyHZLHEWfJ\n6rlZSkLNb4lYuRrKNUI9qCrcxlKjQZvqRl9tIqrntmdsFcsu3CFVGJxNlVFy\n0RKAhVejnNu8ckVJxJp2Hif48RNuO/ftN3MT7L2Db4Rkykq7xc3TwINql5Cn\npE4mqqExJxusij7p7yJmP3QSU4jf0O2Wv1q81GxrB4/K9y2CQNMAVRljRF16\n+hECZVqtWb+EiA6RITT3/lQTHNlm+ERqFkFI3KvuomTbVvzFtt4auiF6E5/L\nIe1p3xwD8IUh+CTThzMEE3PzvHVCn6WYl3eyPQCBTP7TP3vf+D3at8IRIgl/\nWWZf\r\n=mPwq\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAc6w6/DO5PLeXJJy9xZVOS9/eJ/MWyOTOfgY+VEbai0AiEAp4WqNsJZRtd1Pr8DUn4mNNUfiTJHIVwbw90ORJdxpTE="}]},"maintainers":[{"name":"easemob","email":"npm@easemob.com"}],"_npmUser":{"name":"easemob","email":"npm@easemob.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/easemob-emedia_3.2.1-beta_1595922606972_0.6801375208841229"},"_hasShrinkwrap":false},"3.2.1-beta2":{"name":"easemob-emedia","version":"3.2.1-beta2","description":"webrtc","main":"EMedia_sdk-dev.js","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"author":{"name":"easemob"},"license":"ISC","readme":"# 集成文档\n\n[简介|功能说明|接入]\n\n**多人音视频Web SDK**是以Websocket为通讯基础，WebRTC为协议，支持多种浏览器 即时多媒体通话功能。通过SDK可快速完成即时视频通话功能。特点概述：\n\n- **浏览器支持** ：Chrome/50, Safari/11, Edge, Firefox；\n- **功能** ：视频通话，音频通话，远程抓拍，远程聚焦、镜头缩放；桌面共享（仅支持Chrome浏览器）；\n- **实现** ：H5，原生JS, 支持require；\n- **限制** ：https\n- **线上DEMO** ：__confr_id__随意定制，相同的为同一个会议<https://turn2.easemob.com/rtc-ws/EMedia/?__log_level___=0&__only_enter__=false&__auto_sub__=true&__url__=wss://turn2.easemob.com/ws&__confr_id__=HelloGod001&__member_name__=God001>\n\n-------------------\n\n# 接入\n\n下载**EMedia-3.0.0.x.zip**并解压后。添加script标签引用。\n\n# 集成\n```javascript\n<script src=\"./webrtc/dist/EMedia_sdk-dev.js\"></script>\n```\n# 创建\n同一个标签页可支持创建多个Service。但几乎没有这种场景。所以不建议在销毁前创建多个service，尽管这是没有问题的。\n\n```javascript\nvar service = new emedia.Service({\n    listeners: { //以下监听，this object == me == service.current\n        //退出\n        onMeExit: function (reason, failed) {\n            reason = (reason || 0);\n            switch (reason){\n                case 0:\n                    reason = \"正常挂断\";\n                    break;\n                case 1:\n                    reason = \"没响应\";\n                    break;\n                case 2:\n                    reason = \"服务器拒绝\";\n                    break;\n                case 3:\n                    reason = \"对方忙\";\n                    break;\n                case 4:\n                    reason = \"失败,可能是网络或服务器拒绝\";\n                    if(failed === -9527){\n                        reason = \"失败,网络原因\";\n                    }\n                    if(failed === -500){\n                        reason = \"Ticket失效\";\n                    }\n                    if(failed === -502){\n                        reason = \"Ticket过期\";\n                    }\n                    if(failed === -504){\n                        reason = \"链接已失效\";\n                    }\n                    if(failed === -508){\n                        reason = \"会议无效\";\n                    }\n                    if(failed === -510){\n                        reason = \"服务端限制\";\n                    }\n                    break;\n                case 5:\n                    reason = \"不支持\";\n                    break;\n                case 10:\n                    reason = \"其他设备登录\";\n                    break;\n                case 11:\n                    reason = \"会议关闭\";\n                    break;\n            }\n        },\n        //member加入会议\n        onAddMember: function (member) {\n        },\n        //member离开会议\n        onRemoveMember: function (member) {\n        },\n        //收到一个业务流\n        onAddStream: function (stream) {\n        },\n        //移除一个业务流\n        onRemoveStream: function (stream) {\n        },\n        //业务流更新\n        onUpdateStream: function (stream, update) {\n        },\n        //当前通话连接质量不佳\n        onNetworkWeak: function () {\n        },\n        //各类事件\n        onNotifyEvent: function (evt) {\n            if(evt instanceof emedia.event.ServerRefuseEnter){ //服务端拒绝进入\n            } else if(evt instanceof emedia.event.EnterSuccess){ //进入会议成功\n            } else if(evt instanceof emedia.event.EnterFail){ //进入会议失败\n            } else if(evt instanceof emedia.event.ICERemoteMediaStream) { //成功获取对方媒体数据 如：视频\n            } else if(evt instanceof emedia.event.PushSuccess){ //推流成功。本地打开摄像头并将数据成功发送\n            } else if(evt instanceof emedia.event.SubSuccess){ //订阅成功，可以看到对方了\n            } else if(evt instanceof emedia.event.PushFail){ //推送失败\n            } else if(evt instanceof emedia.event.SubFail){ //推送成功\n            } else if(evt instanceof emedia.event.ShareDesktopExtensionNotFound){ //共享桌面插件未找到\n            } else if(evt instanceof emedia.event.RemoteControlFail){ //远程控制失败，仅能web端控制sdk端\n            }\n        }\n    }\n});\n```\n\n\n# 初始化\n加入会议的凭证 是 tkt，只要获取到tkt，便能工作\n```javascript\nservice.setup(tkt_string, {role: 'admin'}/*扩展字段*/);\n```\n\n# member\n```javascript\n...\nonAddMember: function (member) {\n},\nonRemoveMember: function (member) {\n},\n...\n```\n\n```json\n{\n    \"ext\":{ //service.setup(tkt_string, {role: 'admin'}/*扩展字段*/);\n        \"identity\":\"visitor\",\n        \"nickname\":\"webim-visitor-9F72MEK793H97XQGFBKM\",\n        \"avatarUrl\":\"\"\n    },\n    \"nickName\":\"webim-visitor-9F72MEK793H97XQGFBKM\",\n    \"id\":\"MS_X197721744293023744C19M197756407719972865VISITOR\",\n    \"name\":\"a63ceeb6-64c2-426d-9803-a40dd5557d7c\",\n    \"vcodes\":[\n        \"VP8\",\n        \"H264\"\n    ]\n}\n```\n# stream\n```javascript\n...\n//收到一个业务流\nonAddStream: function (stream) {\n},\n//移除一个业务流\nonRemoveStream: function (stream) {\n},\n//业务流更新\nonUpdateStream: function (stream, update) {\n    update.ifMediaStream(function (mediaStream) { //媒体数据发生变化\n        video.srcObject = null;\n        video.srcObject = mediaStream;\n    });\n    update.ifVoff(function (voff) { //对方 开启/关闭 视频\n    });\n    update.ifAoff(function (aoff) { //对方 开启/关闭 音频\n    });\n},\n...\n```\n```json\n{\n    \"memId\":\"MS_X197721744293023744C19M197756407719972865VISITOR\",\n    \"id\":\"RTC2__Of_C19M197756407719972865VISITOR\",\n    \"voff\":0, //1 视频关闭 \n    \"aoff\":0, //1 音频关闭 \n    \"vcodes\":[\n        \"VP8\",\n        \"H264\"\n    ],\n    \"owner\": member ,//member对象\n    \"rtcId\":\"RTC1\",\n    \"subArgs\":{\n        \"subSVideo\":true,\n        \"subSAudio\":true\n    }\n}\n```\n\n# 打开媒体设备：麦克风、摄像头\n```javascript\n //创建一个音视频流\nvar pubS = new service.AVPubstream({\n    constaints: { //可缺省，麦克风 摄像头均打开；若设置，audio video 至少有一个为true\n        audio: true|false, //默认true, 打开 麦克风\n        video: true|false, //默认true, 打开 摄像头\n    },\n    aoff: 0, // 指定给对方 是否 关闭了音频, 默认0\n    voff: 0, // 指定给对方 是否 关闭了视频, 默认0\n    name: \"video\", // 视频名称（根据业务情况设定），可缺省\n    ext: { //支持 媒体流 扩展描述，根据业务情况设定。此参数广播到其他人\n        browser: app.appname\n    }\n});\n\n//Chrome 浏览器\n//桌面共享流，选装插件\n//插件地址 https://turn2.easemob.com/simonweb/confr-http/rtc-share-desktop.crx\nvar pubS = new service.ShareDesktopPubstream({name: \"共享桌面\"}); \n\n//混音通话\nvar pubS = new service.AudioMixerPubstream({\n    constaints: {\n        video : \"false\" !== __video__,\n    },\n    aoff: 0\n});\n\nservice.openUserMedia(pubS).then(function () {\n    //打开媒体流成功\n}, function fail(evt) { //打开媒体流失败\n    //共享桌面抄件未找到\n    if(evt instanceof emedia.event.ShareDesktopExtensionNotFound){ \n    }\n    //设备可能不支持，比如 没有摄像头，或 被禁止访问摄像头\n    if(evt instanceof emedia.event.OpenMediaError){ \n    }\n});\n```\n\n# 加入会议\n```javascript\n//在此之前 应该 service.setup(tkt_string, {role: 'admin'}/*扩展字段*/);\nservice.join(function onSuccess() {\n});\n```\n\n# 加入会议，并推送媒体流\n```javascript\nservice.withpublish(pubS).join();\n//在此之前应该openUserMedia。例如：\nservice.openUserMedia(pubS).then(\n    function success(_user, stream) { //成功 video.srcObject = stream\n        service.withpublish(pubS).join();\n    },\n    function fail(evt) {\n        \n    }\n);\n```\n\n# 手动推送媒体流\n```javascript\nservice.push(pubS);\n\n//在此之前应该openUserMedia 并且 join 成功。例如：\nservice.join(function onSuccess() {\n});\n\nservice.openUserMedia(pubS).then(\n    function success(_user, stream) { //成功 video.srcObject = stream\n        service.push(pubS);\n    },\n    function fail(evt) {\n        \n    }\n);\n```\n\n# 手动订阅对方媒体流\n如果配置为自动订阅，可忽略，sdk会自动订阅 stream\n```javascript\nonAddStream: function (stream) {\n    service.subscribe(stream.id, function (_evt) {\n        //订阅失败\n    }, {subSVideo: true|false}); //true:订阅视频，false:订阅音频\n},\n```\n\n# 开启/关闭自己摄像头\n```javascript\nservice.voff(stream, true|false, function fail(evt) {\n});\n```\n\n# 开启/关闭自己麦克风\n```javascript\nservice.aoff(stream, true|false, function fail(evt) {\n});\n```\n\n# 控制手机SDK摄像头，放大缩小\n```javascript\nservice.zoomRemote(stream.id, 2|0.5, function fail(evt){// 放大2倍，缩小0.5\n});\n```\n\n# 抓拍手机SDK摄像头\n```javascript\nservice.capturePictureRemote(stream.id, false, \n    function success(base64Pic) {\n    }, \n    function fail(evt) {\n    }\n);\n```\n\n# 控制手机SDK摄像头 聚焦；在video标签上添加点击事件\n```javascript\nvideo.onclick = function (event) {\n    if (document.all) { // for IE\n        window.event.returnValue = false;\n    } else {\n        event.preventDefault();\n    }\n\n    if(stream.located()){\n        displayEvent(\"Web本地摄像头不支持聚焦\");\n        return;\n    }\n    service.focusExpoRemote(stream.id, video, event, function fail(evt) {\n        _logger.error(\"Oh,no.\", evt.message())\n    });\n}\n```\n\n# 控制手机SDK摄像头 图像定格/恢复。\n```javascript\n//freezeFramed true：图像定格\nservice.freezeFrameRemote(stream.id, function success(freezeFramed) {\n}, function fail(evt, freezeFramed) {\n});\n```\n\n# SDK增强，开启支持远程控制\n```javascript\nemedia.ctrl.support(service,\n    function onHasRemoteControl(stream, controler, controlRequest){\n        var rtn = confirm(\"同意 来自<\" + controler.memName + \">对流:\" + stream.id + \"控制申请吗？\")\n        if(rtn){ //同意被控制\n            var htmlId = stream.getHtmlDOMID();\n            var $div = $('#' + htmlId);\n\n            var $video = $div.find(\"#videoTag\");\n            var $videoTrack = $div.find(\"#video_box #track\");\n            var $canvas = $div.find(\"#video_box canvas\");\n\n            $videoTrack.show();\n            $canvas.show();\n\n            controlRequest.accept($video[0], new MouseTrack({\n                _target: $videoTrack[0],\n                _canvas: $canvas[0],\n                _video: $video[0]\n            }), new KeyboardTrack());\n        }else{ //拒绝\n            controlRequest.reject();\n        }\n    },\n\n    function onRemoteFreeControl(stream, controler, cId) {\n    \t...    \n    }\n);\n```\n# SDK增强，发起控制\n```javascript\nfunction onReject(stream) { //被控端拒绝\n}\n\nfunction onBusy(stream) { //被控端忙\n}\n\nfunction onNotAllowRemoteControl(stream){ //被控端忙\n}\n\nfunction onRemoteControlTimeout(stream){ //被控端超时\n}\n\nfunction onAccept(stream){ //被控端接受\n}\n\nfunction onDisControlled(stream){ //断开控制链接\n}\n    \nif($(videoObj).hasClass('mirror')){\n    emedia.ctrl.mirrorControlled(service, stream.id, videoObj, targetDiv,\n        onDisControlled, onAccept, onNotAllowRemoteControl, onRemoteControlTimeout, onReject, onBusy);\n}else{\n    emedia.ctrl.controlled(service, stream.id, videoObj, targetDiv,\n        onDisControlled, onAccept, onNotAllowRemoteControl, onRemoteControlTimeout, onReject, onBusy);\n}\n\n```\n\n\n\n# 退出会议\n```javascript\n//退出会议，会回调onMeExit\n//退出会议后，可再次setup ticket.\n//setup生命周期 起， exit生命周期止\nservice.exit();\n```\n\n# 配置emedia\n\n```javascript\nemedia.config({\n    logLevel: 0, //日志级别，>5 关闭SDK，日志。默认级别 0       \n        // TRACE: 0,\n        // DEBUG: 1,\n        // INFO: 2,\n        // WARN: 3,\n        // ERROR: 4,\n        // FATAL: 5\n    autoSub: true, //当收到对方媒体流时，自动订阅, 默认值：true\n    enterTimeout: 20000, //单位ms，join 20秒内未返回 join失败，默认值20000\n});\n\n//重要常量\nemedia.config.version //sdk版本\nemedia.LOG_LEVEL //sdk日志级别，可在运行时通过控制台命令行 手动设置，可实时打开日志\nemedia.isFirefox //true 火狐\nemedia.isChrome  //true Chrome\nemedia.isSafari  //true Safari\nemedia.isWebRTC //true支持webrtc false不支持webrtc\n```\n","readmeFilename":"readme.md","_id":"easemob-emedia@3.2.1-beta2","_nodeVersion":"8.16.2","_npmVersion":"6.14.4","dist":{"integrity":"sha512-CK1xQAxBV0akdhk16f3ekbvZ0v3G0w9qTCLu4mtSFuvfyEa8zGof8YP9jr+fyanpC0oLInZwWOHaEHGcDJCHGw==","shasum":"0e681071dc22e107eb404f954566f1beba053caa","tarball":"https://registry.npmjs.org/easemob-emedia/-/easemob-emedia-3.2.1-beta2.tgz","fileCount":3,"unpackedSize":1604635,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfH/aFCRA9TVsSAnZWagAAKa4P/2iXfoh9oLwJqhXEMDqH\ncIqdFMUkkJa15V2E1izhYBU61z/Hqje9nR777TA7Hg6ByUQo8E1BdDRaCNqS\nVoqiG2VpJQ67KbDuIKmzWvmIUypMubhXp6CEanJGM5Cm42om0oXCgGDHoSJN\nh2iEVF5FXNH55IJsauEYXSFJS8Jor4xedi+Du/uVGkIxTF//9idkIh5UFRdA\nllMGEKm4rHQRvP+H20qA2bbJ0KeSZ3tZHhBvdwaVv2P2rRXKHDwylI1fWKci\n6X1gNHAogKwanivoWr0fKDoJlMNPwSBxyTuZiv+CWxqkTm71eX3UAf4inJA5\nHPBZ6NJxQiyJlcpIjNnLlI7W6wJBbkeKUML1eNZgHwspumVzyAFN00L0m5G5\nG6Ol90mHWyY8QvOr79+mG1KdUz/pAVCyOxEh1PF3Wn5hxhQijKVjPecYLIAN\nJuZa0gTfMUKUbRbUsY5wBpxVyQeT1+xGTL19couc7U5W4u77DA1N8vEMM0jC\nMF+N/68w541PPP0lRiibxO+31KgoFZRtk1UMMM/JOJYYSKgPngHNlaknpmei\nFIfu7X0o7pK30BQyh1eAP/NlBOAwl6+m0TntuyCxzbAyJ/dfZoqqfOO6hJ0s\nLPZ+ywyOLRQVamgBIMAVZ6wSPrPh7HIX7rmJLmW3+/lMbvEkNluCXj7V19k6\n1YAI\r\n=qCF/\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCU3pJZzOLYuvMXttkLL4BXhMGK3LefK5oApypAbjV4CwIhAOotk7ITxmzjNVIYEYYR8xZKqO/sWClfur/CcafKrIye"}]},"maintainers":[{"name":"easemob","email":"npm@easemob.com"}],"_npmUser":{"name":"easemob","email":"npm@easemob.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/easemob-emedia_3.2.1-beta2_1595930245031_0.922930470220845"},"_hasShrinkwrap":false},"3.2.1":{"name":"easemob-emedia","version":"3.2.1","description":"webrtc","main":"EMedia_sdk-dev.js","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"author":{"name":"easemob"},"license":"ISC","_id":"easemob-emedia@3.2.1","_nodeVersion":"8.16.2","_npmVersion":"6.14.4","dist":{"integrity":"sha512-/iBTxn2fxMtKBZQH7Wl3oOY8eQ8ryT1/COkh27ZLpGw1PDKo/6hOBRyYbTzSfl4e3C88ipT4LCi8SSMLInqFvA==","shasum":"6c6b2baaff68c4787fe8c6a765608dc47cb6fe0e","tarball":"https://registry.npmjs.org/easemob-emedia/-/easemob-emedia-3.2.1.tgz","fileCount":3,"unpackedSize":1604629,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfH/s7CRA9TVsSAnZWagAASXAP/iWr3O2b92yC4EDleTLK\nADF1505kY4N67mgBTq2yiL+SbXk7q0zddHmL1eAK9G9fV3x9SBzaKfHcXByg\n30CHUeWtgTMJAlj8txmf6R47toVYaK8PJbfQRgEzthxz/uIDcqekW5fd/MFe\njJ/vvDSZk7w/0qmopYW9vWtJRMSmj5JTCfkQ5UjVHzTpTHGQrXtxtBIdO16r\n6FxXf8xLCRfYfpjjkHUa+NwrZAtpZbJqYUqvj8iC/xFJyR0qT7t8kivcMF0o\nAI7l5cbMZz/2MDqJFcNSU5diIGUbuV6WHE9nWEYMSBq6MU/Z2x4nK2q77ELi\nFt53kfmm5uJG2MQkc6ooz7bYhjc896f2rEP1OXGghlCWZTRXRhD7QyETXgEH\njJ9ikBolFkfYmi0E+jRLVwkFZWVHxIYzrTUm3vzxpPmZNC4AwnoAXa68ORwL\nirBstfQ8Nyjaj+zSgOpgT904DrCfltpDvwtFaMTzcOn9YAVuupfZxHcWeR53\nDibCGr+yIupw5e9HIXH5R5/yJQJwcS82cVWw2NldEZW2IK1hj6Ir1sCvLAaS\neluhYj4rwkR7v7Dz3W1dl/rk2UPxjSLnPyY+n2GCFa/fml7sFJVBJl6p7BZZ\nSwUIp10iB7zTXW85AnfbYXya95so6hDfb9IimiOR62jXVEUMleMXZ+TFUXy9\nMB38\r\n=mGnX\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD9oWKOCdhEn1eotGoNU3yM/eq1xb4N0UR3ZOO8af7k2AIgNzzDiHmCQ6v06JyZKO4jqM0cwx/rAQgj3jfSECIarG0="}]},"maintainers":[{"name":"easemob","email":"npm@easemob.com"}],"_npmUser":{"name":"easemob","email":"npm@easemob.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/easemob-emedia_3.2.1_1595931450735_0.053551800362632296"},"_hasShrinkwrap":false},"3.2.2-beta":{"name":"easemob-emedia","version":"3.2.2-beta","description":"webrtc","main":"EMedia_sdk-dev.js","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"author":{"name":"easemob"},"license":"ISC","readme":"# 集成文档\n\n[简介|功能说明|接入]\n\n**多人音视频Web SDK**是以Websocket为通讯基础，WebRTC为协议，支持多种浏览器 即时多媒体通话功能。通过SDK可快速完成即时视频通话功能。特点概述：\n\n- **浏览器支持** ：Chrome/50, Safari/11, Edge, Firefox；\n- **功能** ：视频通话，音频通话，远程抓拍，远程聚焦、镜头缩放；桌面共享（仅支持Chrome浏览器）；\n- **实现** ：H5，原生JS, 支持require；\n- **限制** ：https\n- **线上DEMO** ：__confr_id__随意定制，相同的为同一个会议<https://turn2.easemob.com/rtc-ws/EMedia/?__log_level___=0&__only_enter__=false&__auto_sub__=true&__url__=wss://turn2.easemob.com/ws&__confr_id__=HelloGod001&__member_name__=God001>\n\n-------------------\n\n# 接入\n\n下载**EMedia-3.0.0.x.zip**并解压后。添加script标签引用。\n\n# 集成\n```javascript\n<script src=\"./webrtc/dist/EMedia_sdk-dev.js\"></script>\n```\n# 创建\n同一个标签页可支持创建多个Service。但几乎没有这种场景。所以不建议在销毁前创建多个service，尽管这是没有问题的。\n\n```javascript\nvar service = new emedia.Service({\n    listeners: { //以下监听，this object == me == service.current\n        //退出\n        onMeExit: function (reason, failed) {\n            reason = (reason || 0);\n            switch (reason){\n                case 0:\n                    reason = \"正常挂断\";\n                    break;\n                case 1:\n                    reason = \"没响应\";\n                    break;\n                case 2:\n                    reason = \"服务器拒绝\";\n                    break;\n                case 3:\n                    reason = \"对方忙\";\n                    break;\n                case 4:\n                    reason = \"失败,可能是网络或服务器拒绝\";\n                    if(failed === -9527){\n                        reason = \"失败,网络原因\";\n                    }\n                    if(failed === -500){\n                        reason = \"Ticket失效\";\n                    }\n                    if(failed === -502){\n                        reason = \"Ticket过期\";\n                    }\n                    if(failed === -504){\n                        reason = \"链接已失效\";\n                    }\n                    if(failed === -508){\n                        reason = \"会议无效\";\n                    }\n                    if(failed === -510){\n                        reason = \"服务端限制\";\n                    }\n                    break;\n                case 5:\n                    reason = \"不支持\";\n                    break;\n                case 10:\n                    reason = \"其他设备登录\";\n                    break;\n                case 11:\n                    reason = \"会议关闭\";\n                    break;\n            }\n        },\n        //member加入会议\n        onAddMember: function (member) {\n        },\n        //member离开会议\n        onRemoveMember: function (member) {\n        },\n        //收到一个业务流\n        onAddStream: function (stream) {\n        },\n        //移除一个业务流\n        onRemoveStream: function (stream) {\n        },\n        //业务流更新\n        onUpdateStream: function (stream, update) {\n        },\n        //当前通话连接质量不佳\n        onNetworkWeak: function () {\n        },\n        //各类事件\n        onNotifyEvent: function (evt) {\n            if(evt instanceof emedia.event.ServerRefuseEnter){ //服务端拒绝进入\n            } else if(evt instanceof emedia.event.EnterSuccess){ //进入会议成功\n            } else if(evt instanceof emedia.event.EnterFail){ //进入会议失败\n            } else if(evt instanceof emedia.event.ICERemoteMediaStream) { //成功获取对方媒体数据 如：视频\n            } else if(evt instanceof emedia.event.PushSuccess){ //推流成功。本地打开摄像头并将数据成功发送\n            } else if(evt instanceof emedia.event.SubSuccess){ //订阅成功，可以看到对方了\n            } else if(evt instanceof emedia.event.PushFail){ //推送失败\n            } else if(evt instanceof emedia.event.SubFail){ //推送成功\n            } else if(evt instanceof emedia.event.ShareDesktopExtensionNotFound){ //共享桌面插件未找到\n            } else if(evt instanceof emedia.event.RemoteControlFail){ //远程控制失败，仅能web端控制sdk端\n            }\n        }\n    }\n});\n```\n\n\n# 初始化\n加入会议的凭证 是 tkt，只要获取到tkt，便能工作\n```javascript\nservice.setup(tkt_string, {role: 'admin'}/*扩展字段*/);\n```\n\n# member\n```javascript\n...\nonAddMember: function (member) {\n},\nonRemoveMember: function (member) {\n},\n...\n```\n\n```json\n{\n    \"ext\":{ //service.setup(tkt_string, {role: 'admin'}/*扩展字段*/);\n        \"identity\":\"visitor\",\n        \"nickname\":\"webim-visitor-9F72MEK793H97XQGFBKM\",\n        \"avatarUrl\":\"\"\n    },\n    \"nickName\":\"webim-visitor-9F72MEK793H97XQGFBKM\",\n    \"id\":\"MS_X197721744293023744C19M197756407719972865VISITOR\",\n    \"name\":\"a63ceeb6-64c2-426d-9803-a40dd5557d7c\",\n    \"vcodes\":[\n        \"VP8\",\n        \"H264\"\n    ]\n}\n```\n# stream\n```javascript\n...\n//收到一个业务流\nonAddStream: function (stream) {\n},\n//移除一个业务流\nonRemoveStream: function (stream) {\n},\n//业务流更新\nonUpdateStream: function (stream, update) {\n    update.ifMediaStream(function (mediaStream) { //媒体数据发生变化\n        video.srcObject = null;\n        video.srcObject = mediaStream;\n    });\n    update.ifVoff(function (voff) { //对方 开启/关闭 视频\n    });\n    update.ifAoff(function (aoff) { //对方 开启/关闭 音频\n    });\n},\n...\n```\n```json\n{\n    \"memId\":\"MS_X197721744293023744C19M197756407719972865VISITOR\",\n    \"id\":\"RTC2__Of_C19M197756407719972865VISITOR\",\n    \"voff\":0, //1 视频关闭 \n    \"aoff\":0, //1 音频关闭 \n    \"vcodes\":[\n        \"VP8\",\n        \"H264\"\n    ],\n    \"owner\": member ,//member对象\n    \"rtcId\":\"RTC1\",\n    \"subArgs\":{\n        \"subSVideo\":true,\n        \"subSAudio\":true\n    }\n}\n```\n\n# 打开媒体设备：麦克风、摄像头\n```javascript\n //创建一个音视频流\nvar pubS = new service.AVPubstream({\n    constaints: { //可缺省，麦克风 摄像头均打开；若设置，audio video 至少有一个为true\n        audio: true|false, //默认true, 打开 麦克风\n        video: true|false, //默认true, 打开 摄像头\n    },\n    aoff: 0, // 指定给对方 是否 关闭了音频, 默认0\n    voff: 0, // 指定给对方 是否 关闭了视频, 默认0\n    name: \"video\", // 视频名称（根据业务情况设定），可缺省\n    ext: { //支持 媒体流 扩展描述，根据业务情况设定。此参数广播到其他人\n        browser: app.appname\n    }\n});\n\n//Chrome 浏览器\n//桌面共享流，选装插件\n//插件地址 https://turn2.easemob.com/simonweb/confr-http/rtc-share-desktop.crx\nvar pubS = new service.ShareDesktopPubstream({name: \"共享桌面\"}); \n\n//混音通话\nvar pubS = new service.AudioMixerPubstream({\n    constaints: {\n        video : \"false\" !== __video__,\n    },\n    aoff: 0\n});\n\nservice.openUserMedia(pubS).then(function () {\n    //打开媒体流成功\n}, function fail(evt) { //打开媒体流失败\n    //共享桌面抄件未找到\n    if(evt instanceof emedia.event.ShareDesktopExtensionNotFound){ \n    }\n    //设备可能不支持，比如 没有摄像头，或 被禁止访问摄像头\n    if(evt instanceof emedia.event.OpenMediaError){ \n    }\n});\n```\n\n# 加入会议\n```javascript\n//在此之前 应该 service.setup(tkt_string, {role: 'admin'}/*扩展字段*/);\nservice.join(function onSuccess() {\n});\n```\n\n# 加入会议，并推送媒体流\n```javascript\nservice.withpublish(pubS).join();\n//在此之前应该openUserMedia。例如：\nservice.openUserMedia(pubS).then(\n    function success(_user, stream) { //成功 video.srcObject = stream\n        service.withpublish(pubS).join();\n    },\n    function fail(evt) {\n        \n    }\n);\n```\n\n# 手动推送媒体流\n```javascript\nservice.push(pubS);\n\n//在此之前应该openUserMedia 并且 join 成功。例如：\nservice.join(function onSuccess() {\n});\n\nservice.openUserMedia(pubS).then(\n    function success(_user, stream) { //成功 video.srcObject = stream\n        service.push(pubS);\n    },\n    function fail(evt) {\n        \n    }\n);\n```\n\n# 手动订阅对方媒体流\n如果配置为自动订阅，可忽略，sdk会自动订阅 stream\n```javascript\nonAddStream: function (stream) {\n    service.subscribe(stream.id, function (_evt) {\n        //订阅失败\n    }, {subSVideo: true|false}); //true:订阅视频，false:订阅音频\n},\n```\n\n# 开启/关闭自己摄像头\n```javascript\nservice.voff(stream, true|false, function fail(evt) {\n});\n```\n\n# 开启/关闭自己麦克风\n```javascript\nservice.aoff(stream, true|false, function fail(evt) {\n});\n```\n\n# 控制手机SDK摄像头，放大缩小\n```javascript\nservice.zoomRemote(stream.id, 2|0.5, function fail(evt){// 放大2倍，缩小0.5\n});\n```\n\n# 抓拍手机SDK摄像头\n```javascript\nservice.capturePictureRemote(stream.id, false, \n    function success(base64Pic) {\n    }, \n    function fail(evt) {\n    }\n);\n```\n\n# 控制手机SDK摄像头 聚焦；在video标签上添加点击事件\n```javascript\nvideo.onclick = function (event) {\n    if (document.all) { // for IE\n        window.event.returnValue = false;\n    } else {\n        event.preventDefault();\n    }\n\n    if(stream.located()){\n        displayEvent(\"Web本地摄像头不支持聚焦\");\n        return;\n    }\n    service.focusExpoRemote(stream.id, video, event, function fail(evt) {\n        _logger.error(\"Oh,no.\", evt.message())\n    });\n}\n```\n\n# 控制手机SDK摄像头 图像定格/恢复。\n```javascript\n//freezeFramed true：图像定格\nservice.freezeFrameRemote(stream.id, function success(freezeFramed) {\n}, function fail(evt, freezeFramed) {\n});\n```\n\n# SDK增强，开启支持远程控制\n```javascript\nemedia.ctrl.support(service,\n    function onHasRemoteControl(stream, controler, controlRequest){\n        var rtn = confirm(\"同意 来自<\" + controler.memName + \">对流:\" + stream.id + \"控制申请吗？\")\n        if(rtn){ //同意被控制\n            var htmlId = stream.getHtmlDOMID();\n            var $div = $('#' + htmlId);\n\n            var $video = $div.find(\"#videoTag\");\n            var $videoTrack = $div.find(\"#video_box #track\");\n            var $canvas = $div.find(\"#video_box canvas\");\n\n            $videoTrack.show();\n            $canvas.show();\n\n            controlRequest.accept($video[0], new MouseTrack({\n                _target: $videoTrack[0],\n                _canvas: $canvas[0],\n                _video: $video[0]\n            }), new KeyboardTrack());\n        }else{ //拒绝\n            controlRequest.reject();\n        }\n    },\n\n    function onRemoteFreeControl(stream, controler, cId) {\n    \t...    \n    }\n);\n```\n# SDK增强，发起控制\n```javascript\nfunction onReject(stream) { //被控端拒绝\n}\n\nfunction onBusy(stream) { //被控端忙\n}\n\nfunction onNotAllowRemoteControl(stream){ //被控端忙\n}\n\nfunction onRemoteControlTimeout(stream){ //被控端超时\n}\n\nfunction onAccept(stream){ //被控端接受\n}\n\nfunction onDisControlled(stream){ //断开控制链接\n}\n    \nif($(videoObj).hasClass('mirror')){\n    emedia.ctrl.mirrorControlled(service, stream.id, videoObj, targetDiv,\n        onDisControlled, onAccept, onNotAllowRemoteControl, onRemoteControlTimeout, onReject, onBusy);\n}else{\n    emedia.ctrl.controlled(service, stream.id, videoObj, targetDiv,\n        onDisControlled, onAccept, onNotAllowRemoteControl, onRemoteControlTimeout, onReject, onBusy);\n}\n\n```\n\n\n\n# 退出会议\n```javascript\n//退出会议，会回调onMeExit\n//退出会议后，可再次setup ticket.\n//setup生命周期 起， exit生命周期止\nservice.exit();\n```\n\n# 配置emedia\n\n```javascript\nemedia.config({\n    logLevel: 0, //日志级别，>5 关闭SDK，日志。默认级别 0       \n        // TRACE: 0,\n        // DEBUG: 1,\n        // INFO: 2,\n        // WARN: 3,\n        // ERROR: 4,\n        // FATAL: 5\n    autoSub: true, //当收到对方媒体流时，自动订阅, 默认值：true\n    enterTimeout: 20000, //单位ms，join 20秒内未返回 join失败，默认值20000\n});\n\n//重要常量\nemedia.config.version //sdk版本\nemedia.LOG_LEVEL //sdk日志级别，可在运行时通过控制台命令行 手动设置，可实时打开日志\nemedia.isFirefox //true 火狐\nemedia.isChrome  //true Chrome\nemedia.isSafari  //true Safari\nemedia.isWebRTC //true支持webrtc false不支持webrtc\n```\n","readmeFilename":"readme.md","_id":"easemob-emedia@3.2.2-beta","_nodeVersion":"12.16.3","_npmVersion":"6.14.4","dist":{"integrity":"sha512-fi1MRk8u/31HTKyRVUGO/uZO2WKfiJx2qvp9BtCSiCOILpdSfLn1C2bBDee6CcOa+EqzbA3l2aaf6pIpGumQzQ==","shasum":"d5fdb0cdcd55bbb861ad19e2b082e0e5dc0d6411","tarball":"https://registry.npmjs.org/easemob-emedia/-/easemob-emedia-3.2.2-beta.tgz","fileCount":3,"unpackedSize":1648596,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfRH/4CRA9TVsSAnZWagAA7QkP/3SgLqOCyjN9N3LT3wbQ\n1Tp1sOeh27OhDlYEbpRvqFiFW2/x2IdWN32fEeOaKBSpZawo1XSfbL7shlO3\nhNfydqylqGcqlmPcehWgepvV5qmjJatgZ1ceqkaXTurKRnFRCXsWv/7frFKe\n0nS6z3mQU/Ply0d4pKhqSAMt9OqLi9Qn0YyeS0cKjey3wVCvZWBMKUxjzugu\neb53WWQlFN4H7Jr4RHsaSHoSBFeBiT0YzAMPBMgwX0LFhiKZGDvM0CoE6LGt\nQsrNCGvmhOzwocZdy1i4c/+l4TxCPCHB7pMXxiWa/JX5teZ6zGNLMCHdSUuH\nPx9GMRj/vdXyApOHfnl4KoClz8QXApTsP/IxExGoFUf9sGqH7GE39/hwpDms\n80n3fA/03r0yf7GAkczCFOut0qSM2W8BzJrieHvyByufjWn1PdQ2naiFuE0F\nLJwd+QV91SyzFzmcNnSwczJi2+eN/eBA+hpa5m+rGpZrZYKsM/4nyO51fOmr\nk173Ux8pD1NyJ0MbEBPgT9JTHc4RTeyGqMJU3s26zrr7pJ9xFsPvYVps689g\nr4+l0yckN8Jqxg1UH2cxMZkp62+2jm43ZkvPz+2T9FPD3gy41jjGWRwDuB4a\n9+KRFoMiODRXj4u1reZlNBAXRnPIEmdqmSi3Fpt8jp4P5WcmjE9qJnUlI42I\nAyVD\r\n=jgtw\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIG3+Zb2oPbweZ/Au7Ati/JqRYg8A4OkRApV7FBp1tqKwAiACDWjDic566krSSCjakG6CoxIb1gf2KOGhUEKK4NrRtg=="}]},"maintainers":[{"name":"easemob","email":"npm@easemob.com"}],"_npmUser":{"name":"easemob","email":"npm@easemob.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/easemob-emedia_3.2.2-beta_1598324728365_0.11623192283017691"},"_hasShrinkwrap":false},"3.2.2":{"name":"easemob-emedia","version":"3.2.2","description":"webrtc","main":"EMedia_sdk-dev.js","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"author":{"name":"easemob"},"license":"ISC","_id":"easemob-emedia@3.2.2","_nodeVersion":"12.16.3","_npmVersion":"6.14.4","dist":{"integrity":"sha512-YD1ZwZ1zuLOlLpl2E5n/FWTL96rBsiAZncfeqVpu0DCymAKaYdD9d9xN9u3u1Zk5tOojfmCFUPVrVrD/EPcRLg==","shasum":"8ed8f6b08adf4d0d36c2c3a6ae8541968af83ffc","tarball":"https://registry.npmjs.org/easemob-emedia/-/easemob-emedia-3.2.2.tgz","fileCount":3,"unpackedSize":1648591,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfRJOECRA9TVsSAnZWagAASUAP/jfR8mrkdqohQdpNLhaL\nEgPtEjsnVVeGo2ChxBdXTHTfnATU0bbaj6Zx1z41UTi1+juzFN06hyOs7UQU\nEpjvn/69BmB/pp5dCclYvUV7ZvK9DzJfNA5rFIqH83y91ZHf14CF859zSoME\njGTe84Y+lMakeSSpkyXtevQy6E3/TG+00Hc7Wt8Qr7qRHFO9ZBCq7Bg9dDZf\n5/bm34kXI9Xl2hmKA6Z3mP7f60KiQnSdB4OYO6yEvex2e4c+YN/ltJdxNK8J\n5Bgy+/LbnlenSCCxjFE1rH7LM42fccORYALSJboUn8uf0Y/eSgSBNVf+f/G9\n3xU+o7IvnWXi19n1vu58cSOL+XU0Y6t4Nij6w4BQgzaLecckJx4QpYijwwmg\nAg54evxE/on5mClHkzeZgxtA2sl6mALk/TMbLKvFf2iEoWeMeKRWpoN3QM6m\ndnOnuqh4/iKLRwzylu+KFh/XcVJhXFBQeHMRDl+m1EN3M9VZYS4oth/UWj1W\nOkcJ/u5kZtk6vq+t7CTDzv7Yxq8SvSgyH9KdhMRVeCBJJgXMin4Dn3Nkk/1D\nhaX7EyfBf+hcZyZwRw/wG1m8EdPjCPBTxhLoJAFCFy2hAsb+7fBE307puosA\ncandmkb5OeWnaMhW+OmRS5AoK3cSutkyev2O4AhuPYzoozQohW27HYWJSRdx\nmc6q\r\n=ytXg\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDJyc0KXz7CyN53YtFyZpb2bA7YKC/oKHvh35A3oVs4LAiBH8M84KRN2Mpd4DkYF645EGyzGWR/dn2S8NFGQprhaPg=="}]},"maintainers":[{"name":"easemob","email":"npm@easemob.com"}],"_npmUser":{"name":"easemob","email":"npm@easemob.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/easemob-emedia_3.2.2_1598329731809_0.15507789235494407"},"_hasShrinkwrap":false},"3.4.1-beta":{"name":"easemob-emedia","version":"3.4.1-beta","description":"webrtc","main":"EMedia_sdk-dev.js","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"author":{"name":"easemob"},"license":"ISC","readme":"# 集成文档\n\n[简介|功能说明|接入]\n\n**多人音视频Web SDK**是以Websocket为通讯基础，WebRTC为协议，支持多种浏览器 即时多媒体通话功能。通过SDK可快速完成即时视频通话功能。特点概述：\n\n- **浏览器支持** ：Chrome/50, Safari/11, Edge, Firefox；\n- **功能** ：视频通话，音频通话，远程抓拍，远程聚焦、镜头缩放；桌面共享（仅支持Chrome浏览器）；\n- **实现** ：H5，原生JS, 支持require；\n- **限制** ：https\n- **线上DEMO** ：__confr_id__随意定制，相同的为同一个会议<https://turn2.easemob.com/rtc-ws/EMedia/?__log_level___=0&__only_enter__=false&__auto_sub__=true&__url__=wss://turn2.easemob.com/ws&__confr_id__=HelloGod001&__member_name__=God001>\n\n-------------------\n\n# 接入\n\n下载**EMedia-3.0.0.x.zip**并解压后。添加script标签引用。\n\n# 集成\n```javascript\n<script src=\"./webrtc/dist/EMedia_sdk-dev.js\"></script>\n```\n# 创建\n同一个标签页可支持创建多个Service。但几乎没有这种场景。所以不建议在销毁前创建多个service，尽管这是没有问题的。\n\n```javascript\nvar service = new emedia.Service({\n    listeners: { //以下监听，this object == me == service.current\n        //退出\n        onMeExit: function (reason, failed) {\n            reason = (reason || 0);\n            switch (reason){\n                case 0:\n                    reason = \"正常挂断\";\n                    break;\n                case 1:\n                    reason = \"没响应\";\n                    break;\n                case 2:\n                    reason = \"服务器拒绝\";\n                    break;\n                case 3:\n                    reason = \"对方忙\";\n                    break;\n                case 4:\n                    reason = \"失败,可能是网络或服务器拒绝\";\n                    if(failed === -9527){\n                        reason = \"失败,网络原因\";\n                    }\n                    if(failed === -500){\n                        reason = \"Ticket失效\";\n                    }\n                    if(failed === -502){\n                        reason = \"Ticket过期\";\n                    }\n                    if(failed === -504){\n                        reason = \"链接已失效\";\n                    }\n                    if(failed === -508){\n                        reason = \"会议无效\";\n                    }\n                    if(failed === -510){\n                        reason = \"服务端限制\";\n                    }\n                    break;\n                case 5:\n                    reason = \"不支持\";\n                    break;\n                case 10:\n                    reason = \"其他设备登录\";\n                    break;\n                case 11:\n                    reason = \"会议关闭\";\n                    break;\n            }\n        },\n        //member加入会议\n        onAddMember: function (member) {\n        },\n        //member离开会议\n        onRemoveMember: function (member) {\n        },\n        //收到一个业务流\n        onAddStream: function (stream) {\n        },\n        //移除一个业务流\n        onRemoveStream: function (stream) {\n        },\n        //业务流更新\n        onUpdateStream: function (stream, update) {\n        },\n        //当前通话连接质量不佳\n        onNetworkWeak: function () {\n        },\n        //各类事件\n        onNotifyEvent: function (evt) {\n            if(evt instanceof emedia.event.ServerRefuseEnter){ //服务端拒绝进入\n            } else if(evt instanceof emedia.event.EnterSuccess){ //进入会议成功\n            } else if(evt instanceof emedia.event.EnterFail){ //进入会议失败\n            } else if(evt instanceof emedia.event.ICERemoteMediaStream) { //成功获取对方媒体数据 如：视频\n            } else if(evt instanceof emedia.event.PushSuccess){ //推流成功。本地打开摄像头并将数据成功发送\n            } else if(evt instanceof emedia.event.SubSuccess){ //订阅成功，可以看到对方了\n            } else if(evt instanceof emedia.event.PushFail){ //推送失败\n            } else if(evt instanceof emedia.event.SubFail){ //推送成功\n            } else if(evt instanceof emedia.event.ShareDesktopExtensionNotFound){ //共享桌面插件未找到\n            } else if(evt instanceof emedia.event.RemoteControlFail){ //远程控制失败，仅能web端控制sdk端\n            }\n        }\n    }\n});\n```\n\n\n# 初始化\n加入会议的凭证 是 tkt，只要获取到tkt，便能工作\n```javascript\nservice.setup(tkt_string, {role: 'admin'}/*扩展字段*/);\n```\n\n# member\n```javascript\n...\nonAddMember: function (member) {\n},\nonRemoveMember: function (member) {\n},\n...\n```\n\n```json\n{\n    \"ext\":{ //service.setup(tkt_string, {role: 'admin'}/*扩展字段*/);\n        \"identity\":\"visitor\",\n        \"nickname\":\"webim-visitor-9F72MEK793H97XQGFBKM\",\n        \"avatarUrl\":\"\"\n    },\n    \"nickName\":\"webim-visitor-9F72MEK793H97XQGFBKM\",\n    \"id\":\"MS_X197721744293023744C19M197756407719972865VISITOR\",\n    \"name\":\"a63ceeb6-64c2-426d-9803-a40dd5557d7c\",\n    \"vcodes\":[\n        \"VP8\",\n        \"H264\"\n    ]\n}\n```\n# stream\n```javascript\n...\n//收到一个业务流\nonAddStream: function (stream) {\n},\n//移除一个业务流\nonRemoveStream: function (stream) {\n},\n//业务流更新\nonUpdateStream: function (stream, update) {\n    update.ifMediaStream(function (mediaStream) { //媒体数据发生变化\n        video.srcObject = null;\n        video.srcObject = mediaStream;\n    });\n    update.ifVoff(function (voff) { //对方 开启/关闭 视频\n    });\n    update.ifAoff(function (aoff) { //对方 开启/关闭 音频\n    });\n},\n...\n```\n```json\n{\n    \"memId\":\"MS_X197721744293023744C19M197756407719972865VISITOR\",\n    \"id\":\"RTC2__Of_C19M197756407719972865VISITOR\",\n    \"voff\":0, //1 视频关闭 \n    \"aoff\":0, //1 音频关闭 \n    \"vcodes\":[\n        \"VP8\",\n        \"H264\"\n    ],\n    \"owner\": member ,//member对象\n    \"rtcId\":\"RTC1\",\n    \"subArgs\":{\n        \"subSVideo\":true,\n        \"subSAudio\":true\n    }\n}\n```\n\n# 打开媒体设备：麦克风、摄像头\n```javascript\n //创建一个音视频流\nvar pubS = new service.AVPubstream({\n    constaints: { //可缺省，麦克风 摄像头均打开；若设置，audio video 至少有一个为true\n        audio: true|false, //默认true, 打开 麦克风\n        video: true|false, //默认true, 打开 摄像头\n    },\n    aoff: 0, // 指定给对方 是否 关闭了音频, 默认0\n    voff: 0, // 指定给对方 是否 关闭了视频, 默认0\n    name: \"video\", // 视频名称（根据业务情况设定），可缺省\n    ext: { //支持 媒体流 扩展描述，根据业务情况设定。此参数广播到其他人\n        browser: app.appname\n    }\n});\n\n//Chrome 浏览器\n//桌面共享流，选装插件\n//插件地址 https://turn2.easemob.com/simonweb/confr-http/rtc-share-desktop.crx\nvar pubS = new service.ShareDesktopPubstream({name: \"共享桌面\"}); \n\n//混音通话\nvar pubS = new service.AudioMixerPubstream({\n    constaints: {\n        video : \"false\" !== __video__,\n    },\n    aoff: 0\n});\n\nservice.openUserMedia(pubS).then(function () {\n    //打开媒体流成功\n}, function fail(evt) { //打开媒体流失败\n    //共享桌面抄件未找到\n    if(evt instanceof emedia.event.ShareDesktopExtensionNotFound){ \n    }\n    //设备可能不支持，比如 没有摄像头，或 被禁止访问摄像头\n    if(evt instanceof emedia.event.OpenMediaError){ \n    }\n});\n```\n\n# 加入会议\n```javascript\n//在此之前 应该 service.setup(tkt_string, {role: 'admin'}/*扩展字段*/);\nservice.join(function onSuccess() {\n});\n```\n\n# 加入会议，并推送媒体流\n```javascript\nservice.withpublish(pubS).join();\n//在此之前应该openUserMedia。例如：\nservice.openUserMedia(pubS).then(\n    function success(_user, stream) { //成功 video.srcObject = stream\n        service.withpublish(pubS).join();\n    },\n    function fail(evt) {\n        \n    }\n);\n```\n\n# 手动推送媒体流\n```javascript\nservice.push(pubS);\n\n//在此之前应该openUserMedia 并且 join 成功。例如：\nservice.join(function onSuccess() {\n});\n\nservice.openUserMedia(pubS).then(\n    function success(_user, stream) { //成功 video.srcObject = stream\n        service.push(pubS);\n    },\n    function fail(evt) {\n        \n    }\n);\n```\n\n# 手动订阅对方媒体流\n如果配置为自动订阅，可忽略，sdk会自动订阅 stream\n```javascript\nonAddStream: function (stream) {\n    service.subscribe(stream.id, function (_evt) {\n        //订阅失败\n    }, {subSVideo: true|false}); //true:订阅视频，false:订阅音频\n},\n```\n\n# 开启/关闭自己摄像头\n```javascript\nservice.voff(stream, true|false, function fail(evt) {\n});\n```\n\n# 开启/关闭自己麦克风\n```javascript\nservice.aoff(stream, true|false, function fail(evt) {\n});\n```\n\n# 控制手机SDK摄像头，放大缩小\n```javascript\nservice.zoomRemote(stream.id, 2|0.5, function fail(evt){// 放大2倍，缩小0.5\n});\n```\n\n# 抓拍手机SDK摄像头\n```javascript\nservice.capturePictureRemote(stream.id, false, \n    function success(base64Pic) {\n    }, \n    function fail(evt) {\n    }\n);\n```\n\n# 控制手机SDK摄像头 聚焦；在video标签上添加点击事件\n```javascript\nvideo.onclick = function (event) {\n    if (document.all) { // for IE\n        window.event.returnValue = false;\n    } else {\n        event.preventDefault();\n    }\n\n    if(stream.located()){\n        displayEvent(\"Web本地摄像头不支持聚焦\");\n        return;\n    }\n    service.focusExpoRemote(stream.id, video, event, function fail(evt) {\n        _logger.error(\"Oh,no.\", evt.message())\n    });\n}\n```\n\n# 控制手机SDK摄像头 图像定格/恢复。\n```javascript\n//freezeFramed true：图像定格\nservice.freezeFrameRemote(stream.id, function success(freezeFramed) {\n}, function fail(evt, freezeFramed) {\n});\n```\n\n# SDK增强，开启支持远程控制\n```javascript\nemedia.ctrl.support(service,\n    function onHasRemoteControl(stream, controler, controlRequest){\n        var rtn = confirm(\"同意 来自<\" + controler.memName + \">对流:\" + stream.id + \"控制申请吗？\")\n        if(rtn){ //同意被控制\n            var htmlId = stream.getHtmlDOMID();\n            var $div = $('#' + htmlId);\n\n            var $video = $div.find(\"#videoTag\");\n            var $videoTrack = $div.find(\"#video_box #track\");\n            var $canvas = $div.find(\"#video_box canvas\");\n\n            $videoTrack.show();\n            $canvas.show();\n\n            controlRequest.accept($video[0], new MouseTrack({\n                _target: $videoTrack[0],\n                _canvas: $canvas[0],\n                _video: $video[0]\n            }), new KeyboardTrack());\n        }else{ //拒绝\n            controlRequest.reject();\n        }\n    },\n\n    function onRemoteFreeControl(stream, controler, cId) {\n    \t...    \n    }\n);\n```\n# SDK增强，发起控制\n```javascript\nfunction onReject(stream) { //被控端拒绝\n}\n\nfunction onBusy(stream) { //被控端忙\n}\n\nfunction onNotAllowRemoteControl(stream){ //被控端忙\n}\n\nfunction onRemoteControlTimeout(stream){ //被控端超时\n}\n\nfunction onAccept(stream){ //被控端接受\n}\n\nfunction onDisControlled(stream){ //断开控制链接\n}\n    \nif($(videoObj).hasClass('mirror')){\n    emedia.ctrl.mirrorControlled(service, stream.id, videoObj, targetDiv,\n        onDisControlled, onAccept, onNotAllowRemoteControl, onRemoteControlTimeout, onReject, onBusy);\n}else{\n    emedia.ctrl.controlled(service, stream.id, videoObj, targetDiv,\n        onDisControlled, onAccept, onNotAllowRemoteControl, onRemoteControlTimeout, onReject, onBusy);\n}\n\n```\n\n\n\n# 退出会议\n```javascript\n//退出会议，会回调onMeExit\n//退出会议后，可再次setup ticket.\n//setup生命周期 起， exit生命周期止\nservice.exit();\n```\n\n# 配置emedia\n\n```javascript\nemedia.config({\n    logLevel: 0, //日志级别，>5 关闭SDK，日志。默认级别 0       \n        // TRACE: 0,\n        // DEBUG: 1,\n        // INFO: 2,\n        // WARN: 3,\n        // ERROR: 4,\n        // FATAL: 5\n    autoSub: true, //当收到对方媒体流时，自动订阅, 默认值：true\n    enterTimeout: 20000, //单位ms，join 20秒内未返回 join失败，默认值20000\n});\n\n//重要常量\nemedia.config.version //sdk版本\nemedia.LOG_LEVEL //sdk日志级别，可在运行时通过控制台命令行 手动设置，可实时打开日志\nemedia.isFirefox //true 火狐\nemedia.isChrome  //true Chrome\nemedia.isSafari  //true Safari\nemedia.isWebRTC //true支持webrtc false不支持webrtc\n```\n","readmeFilename":"readme.md","_id":"easemob-emedia@3.4.1-beta","_nodeVersion":"12.16.3","_npmVersion":"6.14.4","dist":{"integrity":"sha512-zvSK6ZWqGAojCrtUS9euBYVQy+loT6PhrmhffIkT8C7WVSkCR7MmLcx9jDXfA0PbEbqJSFX5bqMtgTbSt/aoVw==","shasum":"2d8b0906c009a9e206a33c67169baa71edfd686b","tarball":"https://registry.npmjs.org/easemob-emedia/-/easemob-emedia-3.4.1-beta.tgz","fileCount":3,"unpackedSize":1658679,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf5DxwCRA9TVsSAnZWagAAlWQP/2RC4aBhDc7/WDhqsAql\nbOtJeOuND3m32GdBvMiWE07VpzRY6XaAS4AnF5mTj8VLcj+uPrHKHbjSf5Iv\n+8LWpn4vBX38DlGQjlWxXLSxUptetmbtbZGX3xa2qPHhMiYAzBMZh70uk+R5\n0Gdx4ehVAqudCQgy60P8ZgJV2a56Df6WLzlwMq6H/PlEfWrQIIVs+4Ovi/IN\nKSkJTCDecsn/wBTAGlHHtb93qStp5p+F0U+hxwhx4hsWYP7aURbNBJDAxRHA\ndH80FBv5qB/LGRDdgZDfuDjs6q6dekjkd6zAKwYBgv+JgV+/1+thGHjjMjqX\nBs5LYGHfRtapWUigjNZe1CoN1Y9pabeyIAgXExEdjPDohV7m7xTVqrqNtYhz\nSS6xBcnXfqbzOOK3lzVkAyqB8PTktBx5B6nrzwQfyv6Sylv1A+YcRVd3agts\nc0zBSjE8CPWxozzq/tKfGT7JGy+TNwgnmJmZ3jTAnlOg36ZehkkAXMkwE88u\n+sJz6eMrZTldEs50eBxImTNqWNrLCJQp8oBDO/yBci3wrJiS7nsHPugFWRQ3\nQR/+q8L50t4fj7Q4MxS9hd+Wp7lhyxyzAZu1MlLQirqGd8mIDIP+xSnoiHlu\nHymPkFOH54whUzZybQN8rephOuti1OoyXslkDZpNeAfMGm+zk17I//iXRRTQ\nzvf3\r\n=z1ky\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCD4jnQ7lMtrLFE2LSvLZKySTjVUYG5h7UW9XuD4UtdEgIgV7/D4RBwt3bDgnG3QvJNcxwc/04Yq/jqi+nqtIUtcZc="}]},"_npmUser":{"name":"easemob","email":"npm@easemob.com"},"directories":{},"maintainers":[{"name":"easemob","email":"npm@easemob.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/easemob-emedia_3.4.1-beta_1608793199732_0.5029381331162945"},"_hasShrinkwrap":false},"3.4.1":{"name":"easemob-emedia","version":"3.4.1","description":"webrtc","main":"EMedia_sdk-dev.js","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"author":{"name":"easemob"},"license":"ISC","_id":"easemob-emedia@3.4.1","_nodeVersion":"12.16.3","_npmVersion":"6.14.4","dist":{"integrity":"sha512-nfZ+YHOyNFdYRQMlotHl8T04lsN2CtwKCbTqR0gKHJNEYIEFEgqYx2sTLlcVUjb+UwDrrttVB9gGUgHFYJtWHw==","shasum":"3270b7ef9d11e7646b4e4fa9022ae35ae06f60ca","tarball":"https://registry.npmjs.org/easemob-emedia/-/easemob-emedia-3.4.1.tgz","fileCount":3,"unpackedSize":1658674,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf5EB5CRA9TVsSAnZWagAAGYAP/R1Idh4Jg4BfVKwaKam7\nENpooLk9xtNvVpYb20POKd0zmSsHobLnAc08aQ4TdnO2xK8KCLuK4O33pxUe\n32iG32H4YseogV0H57jULpAQibKx1KeyTftAOo7OYiFM4zCXlrX48MkWFAl3\nzuN1ydZFlc8d8cf1Wdsqtbl5ZBpNaXKlvlXHJDv3mY4Jti1SMJY8qKd1Cneb\ntp7XHGTNrJFbVl1wcjOZZENTczI0BSm9aAc59xUb7L084zqHD4k2dO4uCOLg\nyfWg8ZoY/czZVro42LNoyTAsoyjuWIdU7IMUu0tykwLUHrpDYtJDf9mRe9UN\nfqOShBtp2qQmnNIKEyjovrIcGIzGJMf1bzEJ7L3q7HCcsfvECX8MKoxMTbZ1\nJ/b3oO8O+JcsHpmTtlfouLtKWjlR4Fk8zSxDM4vtTTocORcvPZ8/gV6qAz+g\nEYKYea/254DwPfGT4EqL9Jhe+i2qoPVhxOjA+lGIdbvj7h11QRUiGlK7CjJN\nrSb3nKe3W2pebKPT+QX+HN0GWK/9yRKPZfkrKy1XbKwOEEuqSalXOcojZNZs\nD8n1RqZ4GnTeC8j+KqanO90PneiusPxFOIqTtKbfX3FnCxHKdeRNCrK0JNuG\nD1WRUy/loUcKjcEaziARFHDXFk+wk2Jtg7ShZNKc2SqSf2+5n6G+GvUwj9AZ\nYkvn\r\n=ZtXM\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCkpMfs5gK6YSn4zoOz2TZ3OiAhhYZgLIxY73r/QaEaQAIgbJ6EOunXg0kKmyhKLH5xnua1GN3KQb2FZpQWTwfArHA="}]},"_npmUser":{"name":"easemob","email":"npm@easemob.com"},"directories":{},"maintainers":[{"name":"easemob","email":"npm@easemob.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/easemob-emedia_3.4.1_1608794232603_0.344652225865687"},"_hasShrinkwrap":false}},"time":{"created":"2019-06-27T08:13:39.056Z","2.0.1":"2019-06-27T08:13:39.276Z","modified":"2022-04-30T18:32:08.251Z","2.1.1":"2019-07-09T09:45:08.929Z","2.0.2":"2019-09-20T10:37:20.407Z","2.1.2":"2019-09-20T10:41:07.056Z","2.1.3-beta":"2019-12-03T09:15:05.919Z","2.1.3-beta2":"2019-12-05T06:38:59.504Z","2.1.3-beta4":"2019-12-26T03:28:38.928Z","2.1.3":"2020-02-19T03:34:13.903Z","3.0.10-beta":"2020-04-08T09:57:09.551Z","3.0.10-beta2":"2020-04-08T10:24:43.869Z","3.0.10":"2020-04-09T04:56:33.977Z","3.1.0-beta":"2020-04-20T11:09:49.224Z","3.1.0":"2020-04-20T12:12:39.258Z","3.1.2-beta":"2020-05-13T08:50:28.133Z","3.1.2":"2020-05-13T09:27:42.469Z","3.1.5-beta":"2020-06-23T07:06:20.680Z","3.1.5":"2020-06-23T08:12:22.780Z","3.2.0":"2020-07-09T08:04:51.233Z","3.2.1-beta":"2020-07-28T07:50:07.141Z","3.2.1-beta2":"2020-07-28T09:57:25.175Z","3.2.1":"2020-07-28T10:17:30.863Z","3.2.2-beta":"2020-08-25T03:05:28.634Z","3.2.2":"2020-08-25T04:28:52.029Z","3.4.1-beta":"2020-12-24T06:59:59.940Z","3.4.1":"2020-12-24T07:17:12.801Z"},"maintainers":[{"name":"easemob","email":"npm@easemob.com"}],"description":"webrtc","author":{"name":"easemob"},"license":"ISC","readme":"# 集成文档\n\n[简介|功能说明|接入]\n\n**多人音视频Web SDK**是以Websocket为通讯基础，WebRTC为协议，支持多种浏览器 即时多媒体通话功能。通过SDK可快速完成即时视频通话功能。特点概述：\n\n- **浏览器支持** ：Chrome/50, Safari/11, Edge, Firefox；\n- **功能** ：视频通话，音频通话，远程抓拍，远程聚焦、镜头缩放；桌面共享（仅支持Chrome浏览器）；\n- **实现** ：H5，原生JS, 支持require；\n- **限制** ：https\n- **线上DEMO** ：__confr_id__随意定制，相同的为同一个会议<https://turn2.easemob.com/rtc-ws/EMedia/?__log_level___=0&__only_enter__=false&__auto_sub__=true&__url__=wss://turn2.easemob.com/ws&__confr_id__=HelloGod001&__member_name__=God001>\n\n-------------------\n\n# 接入\n\n下载**EMedia-3.0.0.x.zip**并解压后。添加script标签引用。\n\n# 集成\n```javascript\n<script src=\"./webrtc/dist/EMedia_sdk-dev.js\"></script>\n```\n# 创建\n同一个标签页可支持创建多个Service。但几乎没有这种场景。所以不建议在销毁前创建多个service，尽管这是没有问题的。\n\n```javascript\nvar service = new emedia.Service({\n    listeners: { //以下监听，this object == me == service.current\n        //退出\n        onMeExit: function (reason, failed) {\n            reason = (reason || 0);\n            switch (reason){\n                case 0:\n                    reason = \"正常挂断\";\n                    break;\n                case 1:\n                    reason = \"没响应\";\n                    break;\n                case 2:\n                    reason = \"服务器拒绝\";\n                    break;\n                case 3:\n                    reason = \"对方忙\";\n                    break;\n                case 4:\n                    reason = \"失败,可能是网络或服务器拒绝\";\n                    if(failed === -9527){\n                        reason = \"失败,网络原因\";\n                    }\n                    if(failed === -500){\n                        reason = \"Ticket失效\";\n                    }\n                    if(failed === -502){\n                        reason = \"Ticket过期\";\n                    }\n                    if(failed === -504){\n                        reason = \"链接已失效\";\n                    }\n                    if(failed === -508){\n                        reason = \"会议无效\";\n                    }\n                    if(failed === -510){\n                        reason = \"服务端限制\";\n                    }\n                    break;\n                case 5:\n                    reason = \"不支持\";\n                    break;\n                case 10:\n                    reason = \"其他设备登录\";\n                    break;\n                case 11:\n                    reason = \"会议关闭\";\n                    break;\n            }\n        },\n        //member加入会议\n        onAddMember: function (member) {\n        },\n        //member离开会议\n        onRemoveMember: function (member) {\n        },\n        //收到一个业务流\n        onAddStream: function (stream) {\n        },\n        //移除一个业务流\n        onRemoveStream: function (stream) {\n        },\n        //业务流更新\n        onUpdateStream: function (stream, update) {\n        },\n        //当前通话连接质量不佳\n        onNetworkWeak: function () {\n        },\n        //各类事件\n        onNotifyEvent: function (evt) {\n            if(evt instanceof emedia.event.ServerRefuseEnter){ //服务端拒绝进入\n            } else if(evt instanceof emedia.event.EnterSuccess){ //进入会议成功\n            } else if(evt instanceof emedia.event.EnterFail){ //进入会议失败\n            } else if(evt instanceof emedia.event.ICERemoteMediaStream) { //成功获取对方媒体数据 如：视频\n            } else if(evt instanceof emedia.event.PushSuccess){ //推流成功。本地打开摄像头并将数据成功发送\n            } else if(evt instanceof emedia.event.SubSuccess){ //订阅成功，可以看到对方了\n            } else if(evt instanceof emedia.event.PushFail){ //推送失败\n            } else if(evt instanceof emedia.event.SubFail){ //推送成功\n            } else if(evt instanceof emedia.event.ShareDesktopExtensionNotFound){ //共享桌面插件未找到\n            } else if(evt instanceof emedia.event.RemoteControlFail){ //远程控制失败，仅能web端控制sdk端\n            }\n        }\n    }\n});\n```\n\n\n# 初始化\n加入会议的凭证 是 tkt，只要获取到tkt，便能工作\n```javascript\nservice.setup(tkt_string, {role: 'admin'}/*扩展字段*/);\n```\n\n# member\n```javascript\n...\nonAddMember: function (member) {\n},\nonRemoveMember: function (member) {\n},\n...\n```\n\n```json\n{\n    \"ext\":{ //service.setup(tkt_string, {role: 'admin'}/*扩展字段*/);\n        \"identity\":\"visitor\",\n        \"nickname\":\"webim-visitor-9F72MEK793H97XQGFBKM\",\n        \"avatarUrl\":\"\"\n    },\n    \"nickName\":\"webim-visitor-9F72MEK793H97XQGFBKM\",\n    \"id\":\"MS_X197721744293023744C19M197756407719972865VISITOR\",\n    \"name\":\"a63ceeb6-64c2-426d-9803-a40dd5557d7c\",\n    \"vcodes\":[\n        \"VP8\",\n        \"H264\"\n    ]\n}\n```\n# stream\n```javascript\n...\n//收到一个业务流\nonAddStream: function (stream) {\n},\n//移除一个业务流\nonRemoveStream: function (stream) {\n},\n//业务流更新\nonUpdateStream: function (stream, update) {\n    update.ifMediaStream(function (mediaStream) { //媒体数据发生变化\n        video.srcObject = null;\n        video.srcObject = mediaStream;\n    });\n    update.ifVoff(function (voff) { //对方 开启/关闭 视频\n    });\n    update.ifAoff(function (aoff) { //对方 开启/关闭 音频\n    });\n},\n...\n```\n```json\n{\n    \"memId\":\"MS_X197721744293023744C19M197756407719972865VISITOR\",\n    \"id\":\"RTC2__Of_C19M197756407719972865VISITOR\",\n    \"voff\":0, //1 视频关闭 \n    \"aoff\":0, //1 音频关闭 \n    \"vcodes\":[\n        \"VP8\",\n        \"H264\"\n    ],\n    \"owner\": member ,//member对象\n    \"rtcId\":\"RTC1\",\n    \"subArgs\":{\n        \"subSVideo\":true,\n        \"subSAudio\":true\n    }\n}\n```\n\n# 打开媒体设备：麦克风、摄像头\n```javascript\n //创建一个音视频流\nvar pubS = new service.AVPubstream({\n    constaints: { //可缺省，麦克风 摄像头均打开；若设置，audio video 至少有一个为true\n        audio: true|false, //默认true, 打开 麦克风\n        video: true|false, //默认true, 打开 摄像头\n    },\n    aoff: 0, // 指定给对方 是否 关闭了音频, 默认0\n    voff: 0, // 指定给对方 是否 关闭了视频, 默认0\n    name: \"video\", // 视频名称（根据业务情况设定），可缺省\n    ext: { //支持 媒体流 扩展描述，根据业务情况设定。此参数广播到其他人\n        browser: app.appname\n    }\n});\n\n//Chrome 浏览器\n//桌面共享流，选装插件\n//插件地址 https://turn2.easemob.com/simonweb/confr-http/rtc-share-desktop.crx\nvar pubS = new service.ShareDesktopPubstream({name: \"共享桌面\"}); \n\n//混音通话\nvar pubS = new service.AudioMixerPubstream({\n    constaints: {\n        video : \"false\" !== __video__,\n    },\n    aoff: 0\n});\n\nservice.openUserMedia(pubS).then(function () {\n    //打开媒体流成功\n}, function fail(evt) { //打开媒体流失败\n    //共享桌面抄件未找到\n    if(evt instanceof emedia.event.ShareDesktopExtensionNotFound){ \n    }\n    //设备可能不支持，比如 没有摄像头，或 被禁止访问摄像头\n    if(evt instanceof emedia.event.OpenMediaError){ \n    }\n});\n```\n\n# 加入会议\n```javascript\n//在此之前 应该 service.setup(tkt_string, {role: 'admin'}/*扩展字段*/);\nservice.join(function onSuccess() {\n});\n```\n\n# 加入会议，并推送媒体流\n```javascript\nservice.withpublish(pubS).join();\n//在此之前应该openUserMedia。例如：\nservice.openUserMedia(pubS).then(\n    function success(_user, stream) { //成功 video.srcObject = stream\n        service.withpublish(pubS).join();\n    },\n    function fail(evt) {\n        \n    }\n);\n```\n\n# 手动推送媒体流\n```javascript\nservice.push(pubS);\n\n//在此之前应该openUserMedia 并且 join 成功。例如：\nservice.join(function onSuccess() {\n});\n\nservice.openUserMedia(pubS).then(\n    function success(_user, stream) { //成功 video.srcObject = stream\n        service.push(pubS);\n    },\n    function fail(evt) {\n        \n    }\n);\n```\n\n# 手动订阅对方媒体流\n如果配置为自动订阅，可忽略，sdk会自动订阅 stream\n```javascript\nonAddStream: function (stream) {\n    service.subscribe(stream.id, function (_evt) {\n        //订阅失败\n    }, {subSVideo: true|false}); //true:订阅视频，false:订阅音频\n},\n```\n\n# 开启/关闭自己摄像头\n```javascript\nservice.voff(stream, true|false, function fail(evt) {\n});\n```\n\n# 开启/关闭自己麦克风\n```javascript\nservice.aoff(stream, true|false, function fail(evt) {\n});\n```\n\n# 控制手机SDK摄像头，放大缩小\n```javascript\nservice.zoomRemote(stream.id, 2|0.5, function fail(evt){// 放大2倍，缩小0.5\n});\n```\n\n# 抓拍手机SDK摄像头\n```javascript\nservice.capturePictureRemote(stream.id, false, \n    function success(base64Pic) {\n    }, \n    function fail(evt) {\n    }\n);\n```\n\n# 控制手机SDK摄像头 聚焦；在video标签上添加点击事件\n```javascript\nvideo.onclick = function (event) {\n    if (document.all) { // for IE\n        window.event.returnValue = false;\n    } else {\n        event.preventDefault();\n    }\n\n    if(stream.located()){\n        displayEvent(\"Web本地摄像头不支持聚焦\");\n        return;\n    }\n    service.focusExpoRemote(stream.id, video, event, function fail(evt) {\n        _logger.error(\"Oh,no.\", evt.message())\n    });\n}\n```\n\n# 控制手机SDK摄像头 图像定格/恢复。\n```javascript\n//freezeFramed true：图像定格\nservice.freezeFrameRemote(stream.id, function success(freezeFramed) {\n}, function fail(evt, freezeFramed) {\n});\n```\n\n# SDK增强，开启支持远程控制\n```javascript\nemedia.ctrl.support(service,\n    function onHasRemoteControl(stream, controler, controlRequest){\n        var rtn = confirm(\"同意 来自<\" + controler.memName + \">对流:\" + stream.id + \"控制申请吗？\")\n        if(rtn){ //同意被控制\n            var htmlId = stream.getHtmlDOMID();\n            var $div = $('#' + htmlId);\n\n            var $video = $div.find(\"#videoTag\");\n            var $videoTrack = $div.find(\"#video_box #track\");\n            var $canvas = $div.find(\"#video_box canvas\");\n\n            $videoTrack.show();\n            $canvas.show();\n\n            controlRequest.accept($video[0], new MouseTrack({\n                _target: $videoTrack[0],\n                _canvas: $canvas[0],\n                _video: $video[0]\n            }), new KeyboardTrack());\n        }else{ //拒绝\n            controlRequest.reject();\n        }\n    },\n\n    function onRemoteFreeControl(stream, controler, cId) {\n    \t...    \n    }\n);\n```\n# SDK增强，发起控制\n```javascript\nfunction onReject(stream) { //被控端拒绝\n}\n\nfunction onBusy(stream) { //被控端忙\n}\n\nfunction onNotAllowRemoteControl(stream){ //被控端忙\n}\n\nfunction onRemoteControlTimeout(stream){ //被控端超时\n}\n\nfunction onAccept(stream){ //被控端接受\n}\n\nfunction onDisControlled(stream){ //断开控制链接\n}\n    \nif($(videoObj).hasClass('mirror')){\n    emedia.ctrl.mirrorControlled(service, stream.id, videoObj, targetDiv,\n        onDisControlled, onAccept, onNotAllowRemoteControl, onRemoteControlTimeout, onReject, onBusy);\n}else{\n    emedia.ctrl.controlled(service, stream.id, videoObj, targetDiv,\n        onDisControlled, onAccept, onNotAllowRemoteControl, onRemoteControlTimeout, onReject, onBusy);\n}\n\n```\n\n\n\n# 退出会议\n```javascript\n//退出会议，会回调onMeExit\n//退出会议后，可再次setup ticket.\n//setup生命周期 起， exit生命周期止\nservice.exit();\n```\n\n# 配置emedia\n\n```javascript\nemedia.config({\n    logLevel: 0, //日志级别，>5 关闭SDK，日志。默认级别 0       \n        // TRACE: 0,\n        // DEBUG: 1,\n        // INFO: 2,\n        // WARN: 3,\n        // ERROR: 4,\n        // FATAL: 5\n    autoSub: true, //当收到对方媒体流时，自动订阅, 默认值：true\n    enterTimeout: 20000, //单位ms，join 20秒内未返回 join失败，默认值20000\n});\n\n//重要常量\nemedia.config.version //sdk版本\nemedia.LOG_LEVEL //sdk日志级别，可在运行时通过控制台命令行 手动设置，可实时打开日志\nemedia.isFirefox //true 火狐\nemedia.isChrome  //true Chrome\nemedia.isSafari  //true Safari\nemedia.isWebRTC //true支持webrtc false不支持webrtc\n```\n","readmeFilename":"readme.md"}