{"id":333539,"date":"2022-05-23T15:01:10","date_gmt":"2022-05-23T15:01:10","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=333539"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=333539","title":{"rendered":"<span>\u0428\u043f\u0430\u0440\u0433\u0430\u043b\u043a\u0430 \u043f\u043e \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 \u043c\u0435\u0434\u0438\u0430 \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435<\/span>"},"content":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/webt\/vn\/tg\/pz\/vntgpzpgemeytutve-gevcpoq0e.jpeg\" data-src=\"https:\/\/habrastorage.org\/webt\/vn\/tg\/pz\/vntgpzpgemeytutve-gevcpoq0e.jpeg\" data-blurred=\"true\"\/>  <\/p>\n<p>  <\/p>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u0432\u0435\u0442, \u0434\u0440\u0443\u0437\u044c\u044f!<\/p>\n<p>  <\/p>\n<p>\u0412 \u0434\u0430\u043d\u043d\u043e\u0439 \u0448\u043f\u0430\u0440\u0433\u0430\u043b\u043a\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b \u0432\u0441\u0435 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b \u0438 \u043c\u0435\u0442\u043e\u0434\u044b \u043f\u043e \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 \u043c\u0435\u0434\u0438\u0430 \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435, \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c\u044b\u0435 \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f\u0445:<\/p>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/w3c.github.io\/mediacapture-main\/\">Media Capture and Streams<\/a><\/li>\n<li><a href=\"https:\/\/w3c.github.io\/mediacapture-screen-share\/\">Screen Capture<\/a><\/li>\n<li><a href=\"https:\/\/www.w3.org\/TR\/mediacapture-fromelement\/\">Media Capture from DOM Elements<\/a><\/li>\n<li><a href=\"https:\/\/www.w3.org\/TR\/image-capture\/\">MediaStream Image Capture<\/a><\/li>\n<li><a href=\"https:\/\/www.w3.org\/TR\/mediastream-recording\/\">MediaStream Recording<\/a><\/li>\n<li><a href=\"https:\/\/wicg.github.io\/speech-api\/\">Web Speech API<\/a><\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0428\u043f\u0430\u0440\u0433\u0430\u043b\u043a\u0430 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0430 \u0432 \u0444\u043e\u0440\u043c\u0435 \u0432\u043e\u043f\u0440\u043e\u0441-\u043e\u0442\u0432\u0435\u0442.<\/p>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/harryheman\/Blog-Posts\/tree\/master\/web-media\">\u0420\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0441 \u043a\u043e\u0434\u043e\u043c \u0432\u0441\u0435\u0445 \u0441\u043d\u0438\u043f\u043f\u0435\u0442\u043e\u0432<\/a><\/li>\n<li><a href=\"https:\/\/stackblitz.com\/edit\/js-pfyter?file=index.html\">\u041f\u0435\u0441\u043e\u0447\u043d\u0438\u0446\u0430<\/a><\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0422\u0443\u0442\u043e\u0440\u0438\u0430\u043b\u044b \u043f\u043e \u0442\u0435\u043c\u0435:<\/p>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/habr.com\/ru\/company\/timeweb\/blog\/581086\/\">JavaScript: \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438 \u0437\u0432\u0443\u043a\u0430<\/a><\/li>\n<li><a href=\"https:\/\/habr.com\/ru\/company\/timeweb\/blog\/591417\/\">JavaScript: \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438 \u044d\u043a\u0440\u0430\u043d\u0430<\/a><\/li>\n<li><a href=\"https:\/\/habr.com\/ru\/company\/timeweb\/blog\/646831\/\">JavaScript: \u0437\u0430\u0445\u0432\u0430\u0442 \u043c\u0435\u0434\u0438\u0430\u043f\u043e\u0442\u043e\u043a\u0430 \u0438\u0437 DOM \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432<\/a><\/li>\n<li><a href=\"https:\/\/habr.com\/ru\/company\/timeweb\/blog\/650233\/\">JavaScript: \u0434\u0435\u043b\u0430\u0435\u043c \u0441\u0435\u043b\u0444\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430<\/a><\/li>\n<li><a href=\"https:\/\/habr.com\/ru\/company\/timeweb\/blog\/655143\/\">JavaScript: \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u0447\u0430\u0442 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Socket.io, Express \u0438 React \u0441 \u0430\u043a\u0446\u0435\u043d\u0442\u043e\u043c \u043d\u0430 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 \u043c\u0435\u0434\u0438\u0430<\/a><\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0415\u0441\u043b\u0438 \u0432\u0430\u043c \u044d\u0442\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e, \u043f\u0440\u043e\u0448\u0443 \u043f\u043e\u0434 \u043a\u0430\u0442.<\/p>\n<p><a name=\"habracut\"><\/a>  <\/p>\n<p>\u0421\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435:<\/p>\n<p>  <\/p>\n<ul>\n<li><a href=\"#1-%D0%BA%D0%B0%D0%BA-%D0%BF%D0%BE%D0%BB%D1%83%D1%87%D0%B8%D1%82%D1%8C-%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA-%D0%BC%D0%B5%D0%B4%D0%B8%D0%B0%D1%83%D1%81%D1%82%D1%80%D0%BE%D0%B9%D1%81%D1%82%D0%B2-%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8F\">1. \u041a\u0430\u043a \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u043c\u0435\u0434\u0438\u0430\u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f?<\/a><\/li>\n<li><a href=\"#2-%D0%BA%D0%B0%D0%BA-%D0%BF%D0%BE%D0%BB%D1%83%D1%87%D0%B8%D1%82%D1%8C-%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA-%D1%82%D1%80%D0%B5%D0%B1%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B9-%D0%BA-%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D1%83-%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B6%D0%B8%D0%B2%D0%B0%D0%B5%D0%BC%D1%8B%D1%85-%D0%B1%D1%80%D0%B0%D1%83%D0%B7%D0%B5%D1%80%D0%BE%D0%BC\">2. \u041a\u0430\u043a \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439 \u043a \u043f\u043e\u0442\u043e\u043a\u0443, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u044b\u0445 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c?<\/a><\/li>\n<li><a href=\"#3-%D0%BA%D0%B0%D0%BA-%D0%B7%D0%B0%D1%85%D0%B2%D0%B0%D1%82%D0%B8%D1%82%D1%8C-%D0%BF%D0%BE%D1%82%D0%BE%D0%BA-%D1%81-%D1%83%D1%81%D1%82%D1%80%D0%BE%D0%B9%D1%81%D1%82%D0%B2-%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8F\">3. \u041a\u0430\u043a \u0437\u0430\u0445\u0432\u0430\u0442\u0438\u0442\u044c \u043f\u043e\u0442\u043e\u043a \u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f?<\/a><\/li>\n<li><a href=\"#4-%D0%BA%D0%B0%D0%BA-%D0%B7%D0%B0%D1%85%D0%B2%D0%B0%D1%82%D0%B8%D1%82%D1%8C-%D0%BF%D0%BE%D1%82%D0%BE%D0%BA-%D1%81-%D1%8D%D0%BA%D1%80%D0%B0%D0%BD%D0%B0-%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8F\">4. \u041a\u0430\u043a \u0437\u0430\u0445\u0432\u0430\u0442\u0438\u0442\u044c \u043f\u043e\u0442\u043e\u043a \u0441 \u044d\u043a\u0440\u0430\u043d\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f?<\/a><\/li>\n<li><a href=\"#5-%D0%BA%D0%B0%D0%BA-%D0%B7%D0%B0%D1%85%D0%B2%D0%B0%D1%82%D0%B8%D1%82%D1%8C-%D0%BF%D0%BE%D1%82%D0%BE%D0%BA-%D0%B8%D0%B7-dom-%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%B0\">5. \u041a\u0430\u043a \u0437\u0430\u0445\u0432\u0430\u0442\u0438\u0442\u044c \u043f\u043e\u0442\u043e\u043a \u0438\u0437 DOM-\u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430?<\/a><\/li>\n<li><a href=\"#6-%D0%BA%D0%B0%D0%BA-%D0%BE%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%B8%D1%82%D1%8C-%D0%B7%D0%B0%D1%85%D0%B2%D0%B0%D1%82-%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0\">6. \u041a\u0430\u043a \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0437\u0430\u0445\u0432\u0430\u0442 \u043f\u043e\u0442\u043e\u043a\u0430?<\/a><\/li>\n<li><a href=\"#7-%D0%BA%D0%B0%D0%BA-%D0%B7%D0%B0%D1%85%D0%B2%D0%B0%D1%82%D0%B8%D1%82%D1%8C-%D0%B8%D0%B7%D0%BE%D0%B1%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B8%D0%B7-%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE%D1%82%D1%80%D0%B5%D0%BA%D0%B0\">7. \u041a\u0430\u043a \u0437\u0430\u0445\u0432\u0430\u0442\u0438\u0442\u044c \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0438\u0437 \u0432\u0438\u0434\u0435\u043e\u0442\u0440\u0435\u043a\u0430?<\/a><\/li>\n<li><a href=\"#8-%D0%BA%D0%B0%D0%BA-%D0%B7%D0%B0%D0%BF%D0%B8%D1%81%D0%B0%D1%82%D1%8C-%D0%BF%D0%BE%D1%82%D0%BE%D0%BA\">8. \u041a\u0430\u043a \u0437\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043f\u043e\u0442\u043e\u043a?<\/a><\/li>\n<li><a href=\"#9-%D0%BA%D0%B0%D0%BA-%D0%BF%D1%80%D0%B5%D0%BE%D0%B1%D1%80%D0%B0%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D1%8C-%D1%82%D0%B5%D0%BA%D1%81%D1%82-%D0%B2-%D1%80%D0%B5%D1%87%D1%8C\">9. \u041a\u0430\u043a \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u0435\u043a\u0441\u0442 \u0432 \u0440\u0435\u0447\u044c?<\/a><\/li>\n<li><a href=\"#10-%D0%BA%D0%B0%D0%BA-%D0%BF%D1%80%D0%B5%D0%BE%D0%B1%D1%80%D0%B0%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D1%8C-%D1%80%D0%B5%D1%87%D1%8C-%D0%B2-%D1%82%D0%B5%D0%BA%D1%81%D1%82\">10. \u041a\u0430\u043a \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0442\u044c \u0440\u0435\u0447\u044c \u0432 \u0442\u0435\u043a\u0441\u0442?<\/a><\/li>\n<li><a href=\"#11-%D0%BA%D0%B0%D0%BA-%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B8%D1%82%D1%8C-%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B6%D0%BA%D1%83-%D0%B2%D0%BE%D0%B7%D0%BC%D0%BE%D0%B6%D0%BD%D0%BE%D1%81%D1%82%D0%B5%D0%B9-%D0%BF%D0%BE-%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B5-%D1%81-%D0%BC%D0%B5%D0%B4%D0%B8%D0%B0-%D0%B1%D1%80%D0%B0%D1%83%D0%B7%D0%B5%D1%80%D0%BE%D0%BC\">11. \u041a\u0430\u043a \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 \u043f\u043e \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 \u043c\u0435\u0434\u0438\u0430 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c?<\/a><\/li>\n<\/ul>\n<p>  <\/p>\n<h2 id=\"1-kak-poluchit-spisok-mediaustroystv-polzovatelya\">1. \u041a\u0430\u043a \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u043c\u0435\u0434\u0438\u0430\u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f?<\/h2>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u043c\u0435\u0434\u0438\u0430\u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d \u043c\u0435\u0442\u043e\u0434 <em>enumerateDevices<\/em> \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 <em>MediaDevices<\/em> \u043e\u0431\u044a\u0435\u043a\u0442\u0430 <em>Navigator<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">const devices = await navigator.mediaDevices.enumerateDevices()<\/code><\/pre>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/w3c.github.io\/mediacapture-main\/#dom-mediadevices-enumeratedevices\">\u0421\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f<\/a><\/li>\n<li><a href=\"https:\/\/developer.mozilla.org\/ru\/docs\/Web\/API\/MediaDevices\/enumerateDevices\">MDN<\/a><\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0421\u043f\u0438\u0441\u043e\u043a \u043c\u043e\u0438\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/sa\/y6\/yk\/say6yk_xediierhmflqtjj6f7rk.png\" data-src=\"https:\/\/habrastorage.org\/webt\/sa\/y6\/yk\/say6yk_xediierhmflqtjj6f7rk.png\"\/>  <\/p>\n<p>  <\/p>\n<p>  <\/p>\n<p>\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u043e <em>kind<\/em> \u043c\u043e\u0436\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439 (constraints) \u043a \u043c\u0435\u0434\u0438\u0430\u043f\u043e\u0442\u043e\u043a\u0443 (MediaStream) (\u0434\u0430\u043b\u0435\u0435 \u2014 \u043f\u043e\u0442\u043e\u043a) (\u0441\u043c. \u043d\u0438\u0436\u0435), \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0438\u043c\u0435\u0435\u0442 \u0441\u043c\u044b\u0441\u043b \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">const STORAGE_KEY = 'user_media_devices'  export async function enumerateDevices() {   try {     const devices = sessionStorage.getItem(STORAGE_KEY)       ? JSON.parse(sessionStorage.getItem(STORAGE_KEY))       : await navigator.mediaDevices.enumerateDevices()      if (!sessionStorage.getItem(STORAGE_KEY)) {       sessionStorage.setItem(STORAGE_KEY, JSON.stringify(devices))     }      return { devices }   } catch (error) {     return { error }   } }<\/code><\/pre>\n<p>  <\/p>\n<p><em>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">const stringify = (data) => JSON.stringify(data, null, 2)  const handleError = (e) => {   console.error(e) }  \/\/ &lt;button id=\"enumerateDevicesBtn\">Enumerate devices&lt;\/button> enumerateDevicesBtn.onclick = async () => {   const { devices, error } = await enumerateDevices()   if (error) return handleError(error)    \/\/ &lt;pre id=\"logBox\">&lt;\/pre>   logBox.textContent = stringify(devices) }<\/code><\/pre>\n<p>  <\/p>\n<h2 id=\"2-kak-poluchit-spisok-trebovaniy-k-potoku-podderzhivaemyh-brauzerom\">2. \u041a\u0430\u043a \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439 \u043a \u043f\u043e\u0442\u043e\u043a\u0443, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u044b\u0445 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c?<\/h2>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439 \u043a \u043f\u043e\u0442\u043e\u043a\u0443, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u044b\u0445 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c, \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d \u043c\u0435\u0442\u043e\u0434 <em>getSupportedConstraints<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">const constraints = await navigator.mediaDevices.getSupportedConstraints()<\/code><\/pre>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/w3c.github.io\/mediacapture-main\/#dom-mediadevices-getsupportedconstraints\">\u0421\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f<\/a><\/li>\n<li><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/MediaDevices\/getSupportedConstraints\">MDN<\/a><\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0421\u043f\u0438\u0441\u043e\u043a \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u044b\u0445 \u043c\u043e\u0438\u043c \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c (\u043f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f \u0432\u0435\u0440\u0441\u0438\u044f Chrome):<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/u6\/j9\/oc\/u6j9oc4bqjpwkajeinhkb6qpobc.png\" data-src=\"https:\/\/habrastorage.org\/webt\/u6\/j9\/oc\/u6j9oc4bqjpwkajeinhkb6qpobc.png\"\/>  <\/p>\n<p>  <\/p>\n<p>  <\/p>\n<p><em>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435<\/em>: \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043f\u0438\u0441\u043a\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b \u043d\u0435 \u0432\u0441\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u044c \u043a \u043f\u043e\u0442\u043e\u043a\u0443. \u041d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430 \u043e\u0442\u043d\u043e\u0441\u044f\u0442\u0441\u044f \u043a \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0438 &#171;\u043f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0445&#187; (advanced) \u0438 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0438\u043d\u0430\u0447\u0435, \u0447\u0435\u043c \u043e\u0431\u044b\u0447\u043d\u044b\u0435. \u041c\u043d\u043e\u0433\u0438\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0438 \u043d\u0430 \u0441\u0435\u0433\u043e\u0434\u043d\u044f\u0448\u043d\u0438\u0439 \u0434\u0435\u043d\u044c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u043d\u0435 \u0432 \u043f\u043e\u043b\u043d\u043e\u0439 \u043c\u0435\u0440\u0435.<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">export async function getSupportedConstraints() {   try {     const constraints = await navigator.mediaDevices.getSupportedConstraints()     return { constraints }   } catch (error) {     return { error }   } }<\/code><\/pre>\n<p>  <\/p>\n<p><em>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ &lt;button id=\"getSupportedConstraintsBtn\">Get supported constraints&lt;\/button> getSupportedConstraintsBtn.onclick = async () => {   const { constraints, error } = await getSupportedConstraints()   if (error) return handleError(error)    logBox.textContent = stringify(constraints) }<\/code><\/pre>\n<p>  <\/p>\n<h2 id=\"3-kak-zahvatit-potok-s-ustroystv-polzovatelya\">3. \u041a\u0430\u043a \u0437\u0430\u0445\u0432\u0430\u0442\u0438\u0442\u044c \u043f\u043e\u0442\u043e\u043a \u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f?<\/h2>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u0437\u0430\u0445\u0432\u0430\u0442\u0430 \u043f\u043e\u0442\u043e\u043a\u0430 \u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043c\u0435\u0442\u043e\u0434 <em>getUserMedia<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">const stream = await navigator.mediaDevices.getUserMedia(constraints?)<\/code><\/pre>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/w3c.github.io\/mediacapture-main\/#dom-mediadevices-getusermedia\">\u0421\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u2014 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c<\/a><\/li>\n<li><a href=\"https:\/\/developer.mozilla.org\/ru\/docs\/Web\/API\/MediaDevices\/getUserMedia\">MDN<\/a><\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0414\u0430\u043d\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0435 <em>\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u043a \u043f\u043e\u0442\u043e\u043a\u0443<\/em>:<\/p>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/w3c.github.io\/mediacapture-main\/#constrainable-interface\">\u0421\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u2014 \u0448\u0430\u0431\u043b\u043e\u043d \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439<\/a><\/li>\n<li><a href=\"https:\/\/w3c.github.io\/mediacapture-main\/#dom-mediatracksupportedconstraints\">\u0421\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u2014 \u0441\u043b\u043e\u0432\u0430\u0440\u044c \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439<\/a><\/li>\n<li><a href=\"https:\/\/developer.mozilla.org\/ru\/docs\/Web\/API\/MediaDevices\/getUserMedia#%D0%BF%D0%B0%D1%80%D0%B0%D0%BC%D0%B5%D1%82%D1%80%D1%8B\">MDN<\/a><\/li>\n<\/ul>\n<p>  <\/p>\n<p><em>\u0414\u0435\u0444\u043e\u043b\u0442\u043d\u044b\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">{ audio: true, video: true }<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 <em>\u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0445 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">export const DEFAULT_AUDIO_CONSTRAINTS = {   echoCancellation: true,   autoGainControl: true,   noiseSuppression: true }  export const DEFAULT_VIDEO_CONSTRAINTS = {   width: 1920,   height: 1080,   frameRate: 60 }<\/code><\/pre>\n<p>  <\/p>\n<p><em>getUserMedia<\/em> \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043f\u043e\u0442\u043e\u043a \u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f:<\/p>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/w3c.github.io\/mediacapture-main\/#webidl-1647796506\">\u0421\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f<\/a><\/li>\n<li><a href=\"https:\/\/developer.mozilla.org\/ru\/docs\/Web\/API\/MediaStream\">MDN<\/a><\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u041f\u043e\u0442\u043e\u043a \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044e \u043c\u0435\u0434\u0438\u0430\u0442\u0440\u0435\u043a\u043e\u0432 (MediaStreamTrack) (\u0434\u0430\u043b\u0435\u0435 \u2014 \u0442\u0440\u0435\u043a):<\/p>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/w3c.github.io\/mediacapture-main\/#media-stream-track-interface-definition\">\u0421\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f<\/a><\/li>\n<li><a href=\"https:\/\/developer.mozilla.org\/ru\/docs\/Web\/API\/MediaStreamTrack\">MDN<\/a><\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u041f\u043e\u0442\u043e\u043a \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e <em>\u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0442\u0440\u0435\u043a\u0430\u043c\u0438<\/em>:<\/p>\n<p>  <\/p>\n<ul>\n<li><em>getTracks<\/em> \u2014 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u043c\u0435\u0434\u0438\u0430\u0442\u0440\u0435\u043a\u043e\u0432;<\/li>\n<li><em>getAudioTracks<\/em> \u2014 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u0430\u0443\u0434\u0438\u043e\u0442\u0440\u0435\u043a\u043e\u0432;<\/li>\n<li><em>getVideoTracks<\/em> \u2014 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u0432\u0438\u0434\u0435\u043e\u0442\u0440\u0435\u043a\u043e\u0432;<\/li>\n<li><em>addTrack<\/em> \u2014 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0442\u0440\u0435\u043a \u0432 \u043f\u043e\u0442\u043e\u043a;<\/li>\n<li><em>removeTrack<\/em> \u2014 \u0443\u0434\u0430\u043b\u044f\u0435\u0442 \u0442\u0440\u0435\u043a \u0438\u0437 \u043f\u043e\u0442\u043e\u043a\u0430 \u0438 \u0434\u0440.<\/li>\n<\/ul>\n<p>  <\/p>\n<p><em>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435<\/em>: \u0437\u0430\u0445\u0432\u0430\u0447\u0435\u043d\u043d\u044b\u0439 \u043f\u043e\u0442\u043e\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c &#171;\u043e\u0434\u0438\u043d\u043e\u0447\u043a\u043e\u0439&#187; (singleton). \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u0433\u043e \u0437\u0430\u0445\u0432\u0430\u0442\u0430 \u0438 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c \u0437\u0430\u0445\u0432\u0430\u0442.<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">let mediaStream  export async function getUserMedia(   constraints = {     audio: DEFAULT_AUDIO_CONSTRAINTS,     video: DEFAULT_VIDEO_CONSTRAINTS   } ) {   try {     const stream = mediaStream       ? mediaStream       : (mediaStream = await navigator.mediaDevices.getUserMedia(constraints))      const tracks = stream.getTracks()     const audioTracks = stream.getAudioTracks()     const videoTracks = stream.getVideoTracks()      return { stream, tracks, audioTracks, videoTracks }   } catch (error) {     return { error }   } }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u043f\u0440\u044f\u043c\u043e\u0439 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u043f\u043e\u0442\u043e\u043a\u0430 \u0432 \u043f\u0440\u0438\u0435\u043c\u043d\u0438\u043a (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, DOM-\u044d\u043b\u0435\u043c\u0435\u043d\u0442 <em>video<\/em>) \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e <em>srcObject<\/em>. \u041f\u0440\u0438\u0435\u043c\u043d\u0438\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u0438\u043c\u0435\u0442\u044c \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b <em>autoplay<\/em> \u0438 <em>muted<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ &lt;video id=\"streamReceiver\" controls autoplay muted>&lt;\/video> streamReceiver.srcObject = stream<\/code><\/pre>\n<p>  <\/p>\n<p>\u0422\u0440\u0435\u043a \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0442\u0430\u043a\u0438\u0435 <em>\u043c\u0435\u0442\u043e\u0434\u044b<\/em>, \u043a\u0430\u043a:<\/p>\n<p>  <\/p>\n<ul>\n<li><em>getCapabilities<\/em> \u2014 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 (\u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a), \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u044b\u0445 \u0442\u0440\u0435\u043a\u043e\u043c;<\/li>\n<li><em>getConstraints<\/em> \u2014 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439, \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u043d\u044b\u0445 \u043a \u0442\u0440\u0435\u043a\u0443;<\/li>\n<li><em>getSettings<\/em> \u2014 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a, \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u043d\u044b\u0445 \u043a \u0442\u0440\u0435\u043a\u0443;<\/li>\n<li><em>applyConstraints<\/em> \u2014 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u043a \u0442\u0440\u0435\u043a\u0443;<\/li>\n<li><em>stop<\/em> \u2014 \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 \u0442\u0440\u0435\u043a\u0430 \u0438 \u0434\u0440.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043f\u043e\u0442\u043e\u043a\u0430 \u0438 \u0442\u0440\u0435\u043a\u043e\u0432 \u0441 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435\u043c \u043a \u043f\u043e\u0442\u043e\u043a\u0443 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u044b\u0445 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439, \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0435\u0439 \u043f\u043e\u0442\u043e\u043a\u0430 \u0432 \u043f\u0440\u0438\u0435\u043c\u043d\u0438\u043a, \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435\u043c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u043f\u0435\u0440\u0432\u043e\u043c \u0442\u0440\u0435\u043a\u0435 \u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435\u043c \u044d\u0442\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ &lt;button id=\"getUserMediaBtn\">Get user media&lt;\/button> getUserMediaBtn.onclick = async () => {   const { devices, error: devicesError } = await enumerateDevices()   if (devicesError) return handleError(devicesError)    let constraints   if (devices.some((device) => device.kind === 'audioinput')) {     constraints = { audio: DEFAULT_AUDIO_CONSTRAINTS }   }   if (devices.some((device) => device.kind === 'videoinput')) {     constraints = { ...constraints, video: DEFAULT_VIDEO_CONSTRAINTS }   }   if (!constraints) {     return handleError('User has no devices to capture.')   }    const { stream, tracks, error: mediaError } = await getUserMedia(constraints)   if (mediaError) return handleError(mediaError)   console.log('@stream', stream)    streamReceiver.srcObject = stream    const [firstTrack] = tracks   console.log('@first track', firstTrack)    const trackCapabilities = firstTrack.getCapabilities()   const trackConstraints = firstTrack.getConstraints()   const trackSettings = firstTrack.getSettings()    logBox.textContent = stringify({     trackCapabilities,     trackConstraints,     trackSettings   }) }<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 <em>\u0437\u0430\u0445\u0432\u0430\u0447\u0435\u043d\u043d\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430 \u0438 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0442\u0440\u0435\u043a\u0430<\/em>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/kp\/l7\/dw\/kpl7dwiw4hpw5bosgg-y0c1mfye.png\" data-src=\"https:\/\/habrastorage.org\/webt\/kp\/l7\/dw\/kpl7dwiw4hpw5bosgg-y0c1mfye.png\"\/>  <\/p>\n<p>  <\/p>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 <em>\u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u0442\u0440\u0435\u043a\u0435<\/em>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/nz\/fb\/ot\/nzfbotkrlsf01w7d_b2y4psldng.png\" data-src=\"https:\/\/habrastorage.org\/webt\/nz\/fb\/ot\/nzfbotkrlsf01w7d_b2y4psldng.png\"\/>  <\/p>\n<p>  <\/p>\n<p>  <\/p>\n<h2 id=\"4-kak-zahvatit-potok-s-ekrana-polzovatelya\">4. \u041a\u0430\u043a \u0437\u0430\u0445\u0432\u0430\u0442\u0438\u0442\u044c \u043f\u043e\u0442\u043e\u043a \u0441 \u044d\u043a\u0440\u0430\u043d\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f?<\/h2>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u0437\u0430\u0445\u0432\u0430\u0442\u0430 \u043f\u043e\u0442\u043e\u043a\u0430 \u0441 \u044d\u043a\u0440\u0430\u043d\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d \u043c\u0435\u0442\u043e\u0434 <em>getDisplayMedia<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">const stream = await navigator.mediaDevices.getDisplayMedia(constraints?)<\/code><\/pre>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/w3c.github.io\/mediacapture-screen-share\/#dom-mediadevices-getdisplaymedia\">\u0421\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u2014 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c<\/a><\/li>\n<li><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/MediaDevices\/getDisplayMedia\">MDN<\/a><\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0412 \u0446\u0435\u043b\u043e\u043c, \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u0435\u043d \u043c\u0435\u0442\u043e\u0434\u0443 <em>getUserMedia<\/em>, \u043d\u043e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439 \u043a \u043f\u043e\u0442\u043e\u043a\u0443:<\/p>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/w3c.github.io\/mediacapture-screen-share\/#webidl-210984315\">\u0421\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f<\/a><\/li>\n<li><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/MediaDevices\/getDisplayMedia#parameters\">MDN<\/a><\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 <em>\u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">export const ADDITIONAL_VIDEO_CONSTRAINTS = {   displaySurface: 'window',   cursor: 'motion' }<\/code><\/pre>\n<p>  <\/p>\n<p><em>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435<\/em>: \u043d\u0430 \u0441\u0435\u0433\u043e\u0434\u043d\u044f\u0448\u043d\u0438\u0439 \u0434\u0435\u043d\u044c \u0430\u0443\u0434\u0438\u043e \u043f\u0440\u0438 \u0437\u0430\u0445\u0432\u0430\u0442\u0435 \u044d\u043a\u0440\u0430\u043d\u0430 \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f.<\/p>\n<p>  <\/p>\n<p><em>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u0437\u0430\u0445\u0432\u0430\u0442\u0430 \u044d\u043a\u0440\u0430\u043d\u0430<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ \u043f\u043e\u0442\u043e\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u043e\u0434\u0438\u043d\u043e\u0447\u043a\u043e\u0439 let displayStream  export async function getDisplayMedia(   constraints = {     video: { ...DEFAULT_VIDEO_CONSTRAINTS, ...ADDITIONAL_VIDEO_CONSTRAINTS }   } ) {   try {     const stream = displayStream       ? displayStream       : (displayStream = await navigator.mediaDevices.getDisplayMedia(constraints))      const [tracks, audioTracks, videoTracks] = [       stream.getTracks(),       stream.getAudioTracks(),       stream.getVideoTracks()     ]      return { stream, tracks, audioTracks, videoTracks }   } catch (error) {     return { error }   } }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 <em>\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ &lt;button id=\"getDisplayMediaBtn\">Get display media&lt;\/button> getDisplayMediaBtn.onclick = async () => {   const { stream, tracks, error } = await getDisplayMedia()   if (error) return handleError(error)   console.log('@display stream', stream)    streamReceiver.srcObject = stream    const [firstTrack] = tracks   console.log('@display first track', firstTrack)    const [trackCapabilities, trackConstraints, trackSettings] = [     firstTrack.getCapabilities(),     firstTrack.getConstraints(),     firstTrack.getSettings()   ]    logBox.textContent = stringify({     trackCapabilities,     trackConstraints,     trackSettings   }) }<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 <em>\u0437\u0430\u0445\u0432\u0430\u0447\u0435\u043d\u043d\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430 \u0438 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0442\u0440\u0435\u043a\u0430<\/em>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/6u\/ub\/cv\/6uubcvtdnlzy0xo9ke5qhju5o8s.png\" data-src=\"https:\/\/habrastorage.org\/webt\/6u\/ub\/cv\/6uubcvtdnlzy0xo9ke5qhju5o8s.png\"\/>  <\/p>\n<p>  <\/p>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 <em>\u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u0442\u0440\u0435\u043a\u0435<\/em>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/hv\/aw\/1n\/hvaw1nrxikc-ndyrhyz0495ho6e.png\" data-src=\"https:\/\/habrastorage.org\/webt\/hv\/aw\/1n\/hvaw1nrxikc-ndyrhyz0495ho6e.png\"\/>  <\/p>\n<p>  <\/p>\n<p>  <\/p>\n<h2 id=\"5-kak-zahvatit-potok-iz-dom-elementa\">5. \u041a\u0430\u043a \u0437\u0430\u0445\u0432\u0430\u0442\u0438\u0442\u044c \u043f\u043e\u0442\u043e\u043a \u0438\u0437 DOM-\u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430?<\/h2>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u0437\u0430\u0445\u0432\u0430\u0442\u0430 \u043f\u043e\u0442\u043e\u043a\u0430 \u0438\u0437 \u0442\u0430\u043a\u0438\u0445 DOM-\u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432, \u043a\u0430\u043a <em>audio<\/em>, <em>video<\/em> \u0438 <em>canvas<\/em> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043c\u0435\u0442\u043e\u0434 <em>captureStream<\/em> \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 <em>HTMLMediaElement<\/em> \u0438\u043b\u0438, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e, <em>HTMLCanvasElement<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">const stream = await mediaElement.captureStream()<\/code><\/pre>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/www.w3.org\/TR\/mediacapture-fromelement\/#dom-htmlmediaelement-capturestream\">\u0421\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f<\/a><\/li>\n<li><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/HTMLMediaElement\/captureStream\">MDN \u2014 HTMLMediaElement<\/a><\/li>\n<li><a href=\"https:\/\/developer.mozilla.org\/ru\/docs\/Web\/API\/HTMLCanvasElement\/captureStream\">MDN \u2014 HTMLCanvasElement<\/a><\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u041f\u0440\u0438 \u0437\u0430\u0445\u0432\u0430\u0442\u0435 \u043f\u043e\u0442\u043e\u043a\u0430 \u0438\u0437 \u043c\u0435\u0434\u0438\u0430\u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u0438\u043c\u0435\u0435\u0442 \u0441\u043c\u044b\u0441\u043b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c, \u0432\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u0447\u0442\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u044b\u0439 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043c\u0435\u0434\u0438\u0430\u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u043c, \u0432\u043e-\u0432\u0442\u043e\u0440\u044b\u0445, \u0433\u043e\u0442\u043e\u0432\u043d\u043e\u0441\u0442\u044c \u043c\u0435\u0434\u0438\u0430 \u043a \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044e \u0434\u043e \u043a\u043e\u043d\u0446\u0430 \u0431\u0435\u0437 \u043f\u0440\u0435\u0440\u044b\u0432\u0430\u043d\u0438\u0439 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/HTMLMediaElement\/readyState\">readyState<\/a>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">if (!(mediaElement instanceof HTMLMediaElement)) {   throw new Error('Argument must be an instance of HTMLMediaElement.') } if (mediaElement.readyState !== 4) {   throw new Error(     'Media element has not enough data to be played through the end without interruption.'   ) }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u0441 DOM-\u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u043c\u043e\u0436\u0435\u0442 \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0437\u0430\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0442\u043e\u043a\u043e\u0432.<\/p>\n<p>  <\/p>\n<p><em>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u0437\u0430\u0445\u0432\u0430\u0442\u0430 \u043f\u043e\u0442\u043e\u043a\u0430 \u0438\u0437 \u043c\u0435\u0434\u0438\u0430\u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">let mediaElementStreams = []  export async function captureStreamFromMediaElement(mediaElement) {   if (!(mediaElement instanceof HTMLMediaElement)) {     throw new Error('Argument must be an instance of HTMLMediaElement.')   }   if (mediaElement.readyState !== 4) {     throw new Error(       'Media element has not enough data to be played through the end without interruption.'     )   }   try {     const stream = await mediaElement.captureStream()     mediaElementStreams.push(stream)      const [tracks, audioTracks, videoTracks] = [       stream.getTracks(),       stream.getAudioTracks(),       stream.getVideoTracks()     ]      return { stream, tracks, audioTracks, videoTracks }   } catch (error) {     return { error }   } }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 <em>\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ &lt;button id=\"getStreamFromMediaElementBtn\">Get stream from media element&lt;\/button> getStreamFromMediaElementBtn.onclick = async () => {   \/\/ &lt;video id=\"videoEl\" src=\".\/assets\/forest.mp4\" controls>&lt;\/video>   const { stream, tracks, error } = await captureStreamFromMediaElement(videoEl)   if (error) return handleError(error)   console.log('@media element stream', stream)    streamReceiver.srcObject = stream    const [firstTrack] = tracks   console.log('@media element first track', firstTrack)    const [trackCapabilities, trackConstraints, trackSettings] = [     firstTrack.getCapabilities(),     firstTrack.getConstraints(),     firstTrack.getSettings()   ]    logBox.textContent = stringify({     trackCapabilities,     trackConstraints,     trackSettings   }) }<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 <em>\u0437\u0430\u0445\u0432\u0430\u0447\u0435\u043d\u043d\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430 \u0438 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0442\u0440\u0435\u043a\u0430<\/em>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/zk\/7f\/w9\/zk7fw9cczceej78p4tbrq_tnjaa.png\" data-src=\"https:\/\/habrastorage.org\/webt\/zk\/7f\/w9\/zk7fw9cczceej78p4tbrq_tnjaa.png\"\/>  <\/p>\n<p>  <\/p>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 <em>\u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u0442\u0440\u0435\u043a\u0435<\/em>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/xe\/tt\/wl\/xettwlikawowe5jbsp36ajlg85e.png\" data-src=\"https:\/\/habrastorage.org\/webt\/xe\/tt\/wl\/xettwlikawowe5jbsp36ajlg85e.png\"\/>  <\/p>\n<p>  <\/p>\n<p>  <\/p>\n<h2 id=\"6-kak-ostanovit-zahvat-potoka\">6. \u041a\u0430\u043a \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0437\u0430\u0445\u0432\u0430\u0442 \u043f\u043e\u0442\u043e\u043a\u0430?<\/h2>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0437\u0430\u0445\u0432\u0430\u0442\u0430 \u043f\u043e\u0442\u043e\u043a\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u0440\u0435\u043a\u0440\u0430\u0442\u0438\u0442\u044c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0435\u0433\u043e \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430, \u0442.\u0435. \u0442\u0440\u0435\u043a\u0430. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434 <em>stop<\/em> \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0442\u0440\u0435\u043a\u0430:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">export function stopTracks() {   mediaStream?.getTracks().forEach((track) => {     track.stop()   })   displayStream?.getTracks().forEach((track) => {     track.stop()   })   for (const stream of mediaElementStreams) {     stream?.getTracks().forEach((track) => {       track.stop()     })   }   mediaStream = null   displayStream = null   mediaElementStreams = [] }<\/code><\/pre>\n<p>  <\/p>\n<h2 id=\"7-kak-zahvatit-izobrazhenie-iz-videotreka\">7. \u041a\u0430\u043a \u0437\u0430\u0445\u0432\u0430\u0442\u0438\u0442\u044c \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0438\u0437 \u0432\u0438\u0434\u0435\u043e\u0442\u0440\u0435\u043a\u0430?<\/h2>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u0437\u0430\u0445\u0432\u0430\u0442\u0430 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0438\u0437 \u0432\u0438\u0434\u0435\u043e\u0442\u0440\u0435\u043a\u0430 (\u0438\u043b\u0438 \u043a\u0430\u0434\u0440\u0430 \u0438\u0437 \u0445\u043e\u043b\u0441\u0442\u0430) \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d \u043c\u0435\u0442\u043e\u0434 <em>takePhoto<\/em> \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 <em>ImageCapture<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">const imageCapture = new ImageCapture(videoTrack) const blob = await imageCapture.takePhoto(photoSettings?)<\/code><\/pre>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/www.w3.org\/TR\/image-capture\/#imagecaptureapi\">\u0421\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u2014 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 ImageCapture<\/a><\/li>\n<li><a href=\"https:\/\/www.w3.org\/TR\/image-capture\/#dom-imagecapture-takephoto\">\u0421\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u2014 \u043c\u0435\u0442\u043e\u0434 takePhoto<\/a><\/li>\n<li><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/ImageCapture\">MDN<\/a><\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0414\u0430\u043d\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0435 <em>\u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0434\u043b\u044f \u0444\u043e\u0442\u043e<\/em>:<\/p>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/www.w3.org\/TR\/image-capture\/#dictdef-photosettings\">\u0421\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f<\/a><\/li>\n<li><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/ImageCapture\/takePhoto#parameters\">MDN<\/a><\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 <em>\u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0434\u043b\u044f \u0444\u043e\u0442\u043e<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">export const DEFAULT_PHOTO_SETTINGS = {   imageHeight: 480,   imageWidth: 640 }<\/code><\/pre>\n<p>  <\/p>\n<p>\u041a \u0432\u0438\u0434\u0435\u043e\u0442\u0440\u0435\u043a\u0443 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f, \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0435 \u0441 \u0437\u0430\u0445\u0432\u0430\u0442\u043e\u043c \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f:<\/p>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/www.w3.org\/TR\/image-capture\/#mediatracksupportedconstraints-section\">\u0421\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f<\/a><\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u042d\u0442\u0438 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u043c\u0438 \u0438 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u0435\u0442\u043e\u0434\u0430 <em>applyConstraints<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">const advancedConstraints = {   name: value } await videoTrack.applyConstraints({   advanced: [advancedConstraints] })<\/code><\/pre>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u044c \u043a \u0432\u0438\u0434\u0435\u043e\u0442\u0440\u0435\u043a\u0443 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u0438 \u0437\u0430\u0445\u0432\u0430\u0442\u0435 \u043f\u043e\u0442\u043e\u043a\u0430 \u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043a \u043f\u043e\u0442\u043e\u043a\u0443 \u0434\u043e\u043b\u0436\u043d\u044b \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ \u044d\u0442\u0438 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u043e\u0442\u043d\u043e\u0441\u044f\u0442\u0441\u044f \u043a \u0432\u0438\u0434\u0435\u043e export const DEFAULT_PHOTO_CONSTRAINTS = {   pan: true,   tilt: true,   zoom: true }<\/code><\/pre>\n<p>  <\/p>\n<p>\u041c\u0435\u0442\u043e\u0434 <em>takePhoto<\/em> \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 <em>Blob<\/em>:<\/p>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/w3c.github.io\/FileAPI\/#dfn-Blob\">\u0421\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f<\/a><\/li>\n<li><a href=\"https:\/\/developer.mozilla.org\/ru\/docs\/Web\/API\/Blob\">MDN<\/a><\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u042d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 <em>ImageCapture<\/em> \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 <em>\u043c\u0435\u0442\u043e\u0434\u044b \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0434\u043b\u044f \u0444\u043e\u0442\u043e<\/em>:<\/p>\n<p>  <\/p>\n<ul>\n<li><em>getPhotoCapabilities<\/em> \u2014 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 \u0434\u043b\u044f \u0444\u043e\u0442\u043e;<\/li>\n<li><em>getPhotoSettings<\/em> \u2014 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0434\u043b\u044f \u0444\u043e\u0442\u043e.<\/li>\n<\/ul>\n<p>  <\/p>\n<p><em>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0434\u043b\u044f \u0444\u043e\u0442\u043e<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">export async function getPhotoCapabilitiesAndSettings(videoTrack) {   const imageCapture = new ImageCapture(videoTrack)   console.log('@image capture', imageCapture)    try {     const [photoCapabilities, photoSettings] = await Promise.all([       imageCapture.getPhotoCapabilities(),       imageCapture.getPhotoSettings()     ])      return { photoCapabilities, photoSettings }   } catch (error) {     return { error }   } }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 <em>\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ &lt;button id=\"getPhotoCapabilitiesAndSettingsBtn\">Get photo capabilities and settings&lt;\/button> getPhotoCapabilitiesAndSettingsBtn.onclick = async () => {   const { videoTracks, error: mediaError } = await getUserMedia()   if (mediaError) return handleError(mediaError)    const [firstVideoTrack] = videoTracks    const {     photoCapabilities,     photoSettings,     error: photoError   } = await getPhotoCapabilitiesAndSettings(firstVideoTrack)   if (photoError) return handleError(photoError)    logBox.textContent = stringify({     photoCapabilities,     photoSettings   }) }<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 <em>\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0434\u043b\u044f \u0444\u043e\u0442\u043e<\/em>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/g3\/ot\/b5\/g3otb5flov6foc18vsfkb3nyaow.png\" data-src=\"https:\/\/habrastorage.org\/webt\/g3\/ot\/b5\/g3otb5flov6foc18vsfkb3nyaow.png\"\/>  <\/p>\n<p>  <\/p>\n<p>  <\/p>\n<p><em>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u0437\u0430\u0445\u0432\u0430\u0442\u0430 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0438\u0437 \u0432\u0438\u0434\u0435\u043e\u0442\u0440\u0435\u043a\u0430<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">export async function takePhoto({   videoTrack,   photoSettings = DEFAULT_PHOTO_SETTINGS }) {   const imageCapture = new ImageCapture(videoTrack)    try {     const blob = await imageCapture.takePhoto(photoSettings)     return { blob }   } catch (error) {     return { error }   } }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 <em>\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ &lt;button id=\"takePhotoBtn\">Take photo&lt;\/button> takePhotoBtn.onclick = async () => {   const { videoTracks, error: mediaError } = await getUserMedia({     video: { ...DEFAULT_VIDEO_CONSTRAINTS, ...DEFAULT_PHOTO_CONSTRAINTS }   })   if (mediaError) return handleError(mediaError)    const [videoTrack] = videoTracks    \/\/ \u0437\u0434\u0435\u0441\u044c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u044c \u043a \u0442\u0440\u0435\u043a\u0443 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f   \/\/ await videoTrack.applyConstraints({   \/\/   advanced: [advancedConstraints]   \/\/ })    const { blob, error: photoError } = await takePhoto({ videoTrack })   if (photoError) return handleError(photoError)    \/\/ &lt;img id=\"imgBox\" alt=\"\" \/>   const imgSrc = URL.createObjectURL(blob)   imgBox.src = imgSrc   \/\/ imgBox.addEventListener(   \/\/   'load',   \/\/   () => {   \/\/     URL.revokeObjectURL(imgSrc)   \/\/   },   \/\/   { once: true }   \/\/ ) }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u0435\u0442\u043e\u0434\u0430 <em>URL.createObjectURL<\/em>. \u041c\u0435\u0442\u043e\u0434 <em>URL.revokeObjectURL<\/em> \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0432\u043e \u0438\u0437\u0431\u0435\u0436\u0430\u043d\u0438\u0435 \u0443\u0442\u0435\u0447\u0435\u043a \u043f\u0430\u043c\u044f\u0442\u0438, \u043d\u043e \u043f\u0440\u0438 \u0435\u0433\u043e \u0432\u044b\u0437\u043e\u0432\u0435 \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f, \u043a\u0430\u043a \u0432 \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u043d\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435, \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0441\u043a\u0430\u0447\u0430\u0442\u044c.<\/p>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/w3c.github.io\/FileAPI\/#creating-revoking\">\u0421\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f<\/a><\/li>\n<li><a href=\"https:\/\/developer.mozilla.org\/ru\/docs\/Web\/API\/URL\/createObjectURL\">MDN \u2014 \u043c\u0435\u0442\u043e\u0434 createObjectURL<\/a><\/li>\n<li><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/URL\/revokeObjectURL\">MDN \u2014 \u043c\u0435\u0442\u043e\u0434 revokeObjectURL<\/a><\/li>\n<\/ul>\n<p>  <\/p>\n<h2 id=\"8-kak-zapisat-potok\">8. \u041a\u0430\u043a \u0437\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043f\u043e\u0442\u043e\u043a?<\/h2>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438 \u043f\u043e\u0442\u043e\u043a\u0430 \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 <em>MediaRecorder<\/em>:<\/p>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/www.w3.org\/TR\/mediastream-recording\/#mediarecorder-api\">\u0421\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f<\/a><\/li>\n<li><a href=\"https:\/\/developer.mozilla.org\/ru\/docs\/Web\/API\/MediaRecorder\">MDN<\/a><\/li>\n<\/ul>\n<p>  <\/p>\n<pre><code class=\"javascript\">const mediaRecorder = new MediaRecorder(mediaStream, options?)<\/code><\/pre>\n<p>  <\/p>\n<p>\u041a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 <em>MediaRecorder<\/em> \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u043f\u043e\u0442\u043e\u043a \u0438 \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c\u0438, \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0432\u0430\u0436\u043d\u043e\u0439 \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 <em>mimeType<\/em> \u2014 \u0442\u0438\u043f \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0435\u043c\u043e\u0439 \u0437\u0430\u043f\u0438\u0441\u0438.<\/p>\n<p>  <\/p>\n<p>\u042d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 <em>MediaRecorder<\/em> \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 <em>\u043c\u0435\u0442\u043e\u0434\u044b \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u044c\u044e<\/em>:<\/p>\n<p>  <\/p>\n<ul>\n<li><em>start(timeslice?)<\/em> \u2014 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0437\u0430\u043f\u0438\u0441\u044c. \u0414\u0430\u043d\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 <em>timeslice<\/em> \u2014 \u0432\u0440\u0435\u043c\u044f \u0432\u044b\u0437\u043e\u0432\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u044f <em>dataavailable<\/em> (\u0441\u043c. \u043d\u0438\u0436\u0435);<\/li>\n<li><em>pause<\/em> \u2014 \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u0437\u0430\u043f\u0438\u0441\u044c;<\/li>\n<li><em>resume<\/em> \u2014 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u0442 \u0437\u0430\u043f\u0438\u0441\u044c;<\/li>\n<li><em>stop<\/em> \u2014 \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u0437\u0430\u043f\u0438\u0441\u044c.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0412 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u0440\u044f\u0434 \u0441\u043e\u0431\u044b\u0442\u0438\u0439, \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0432\u0430\u0436\u043d\u044b\u043c \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f <em>dataavailable<\/em>. \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u044d\u0442\u043e\u0433\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u043e\u0431\u044a\u0435\u043a\u0442, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0439 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e <em>data<\/em>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0447\u0430\u0441\u0442\u0438 (chunks) \u0437\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0432\u0438\u0434\u0435 <em>Blob<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">let mediaDataChunks = []  mediaRecorder.ondatavailable = ({ data }) => {   mediaDataChunks.push(data) }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 <em>MediaRecorder<\/em> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u0442\u0438\u043f\u0430 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0435\u043c\u043e\u0439 \u0437\u0430\u043f\u0438\u0441\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u0435\u0442\u043e\u0434\u0430 <em>isTypeSupported<\/em>.<\/p>\n<p>  <\/p>\n<p>\u041f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0438\u043c, \u0447\u0442\u043e \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0437\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u044d\u043a\u0440\u0430\u043d \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0441\u043e \u0437\u0432\u0443\u043a\u043e\u043c. \u041f\u043e\u0442\u043e\u043a \u044d\u043a\u0440\u0430\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u0438\u0434\u0435\u043e. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0432\u0438\u0434\u0435\u043e\u0442\u0440\u0435\u043a\u0438 \u044d\u043a\u0440\u0430\u043d\u0430 \u0438 \u0430\u0443\u0434\u0438\u043e\u0442\u0440\u0435\u043a\u0438 \u043c\u0438\u043a\u0440\u043e\u0444\u043e\u043d\u0430 \u0438 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0438\u0442\u044c \u0438\u0445 \u0432 \u043e\u0434\u0438\u043d \u043f\u043e\u0442\u043e\u043a. \u042d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0430 <em>MediaStream<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">export const createNewStream = (tracks) => new MediaStream(tracks)<\/code><\/pre>\n<p>  <\/p>\n<p>\u0414\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0442\u0440\u0435\u043a\u0438 \u0432 \u0432\u0438\u0434\u0435 \u043c\u0430\u0441\u0441\u0438\u0432\u0430.<\/p>\n<p>  <\/p>\n<p><em>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0437\u0430\u043f\u0438\u0441\u0438<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">const DEFAULT_RECORD_MIME_TYPE = 'video\/webm' const DEFAULT_RECORD_TIMESLICE = 250  \/\/ \u043b\u0443\u0447\u0448\u0435, \u0447\u0442\u043e\u0431\u044b `mediaRecorder` \u0431\u044b\u043b \u043e\u0434\u0438\u043d\u043e\u0447\u043a\u043e\u0439 let mediaRecorder let mediaDataChunks = []  export async function startRecording({   mediaStream,   mimeType,   timeslice = DEFAULT_RECORD_TIMESLICE,   ...restOptions }) {   if (mediaRecorder) return    mediaRecorder = new MediaRecorder(mediaStream, {     mimeType: MediaRecorder.isTypeSupported(mimeType)       ? mimeType       : DEFAULT_RECORD_MIME_TYPE,     ...restOptions   })   console.log('@media recorder', mediaRecorder)    mediaRecorder.onerror = ({ error }) => {     return error   }    mediaRecorder.ondataavailable = ({ data }) => {     mediaDataChunks.push(data)   }    mediaRecorder.start(timeslice) }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 <em>\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ &lt;button id=\"startRecordingBtn\">Start recording&lt;\/button> startRecordingBtn.onclick = async () => {   const { devices, error: devicesError } = await enumerateDevices()   if (devicesError) return handleError(devicesError)    \/\/ \u043c\u044b \u0433\u043e\u0442\u043e\u0432\u044b \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u044d\u043a\u0440\u0430\u043d \u0431\u0435\u0437 \u0437\u0432\u0443\u043a\u0430   let _audioTracks = []   if (devices.some(({ kind }) => kind === 'audioinput')) {     const { audioTracks, error: mediaError } = await getUserMedia()     if (mediaError) return handleError(mediaError)      _audioTracks = audioTracks   }    const { videoTracks, error: displayError } = await getDisplayMedia()   if (displayError) return handleError(displayError)    const mediaStream = createNewStream([..._audioTracks, ...videoTracks])   streamReceiver.srcObject = mediaStream    \/\/ \u0436\u0434\u0435\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u0443\u044e \u043e\u0448\u0438\u0431\u043a\u0443   const recordError = await startRecording({ mediaStream })   if (recordError) return handleError(recordError) }<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 <em>&#171;\u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u0435\u043b\u044f&#187;<\/em>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/2c\/dm\/2z\/2cdm2zappjrisbjl-j-9wypkwnw.png\" data-src=\"https:\/\/habrastorage.org\/webt\/2c\/dm\/2z\/2cdm2zappjrisbjl-j-9wypkwnw.png\"\/>  <\/p>\n<p>  <\/p>\n<p>  <\/p>\n<p><em>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438\/\u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0438<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ \u0432 \u0442\u0430\u043a\u0438\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u0443\u0434\u043e\u0431\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c `IIFE` \u0438 \u0437\u0430\u043c\u044b\u043a\u0430\u043d\u0438\u0435 export const pauseOrResumeRecording = (function () {   let paused = false    return function () {     if (!mediaRecorder) return      paused ? mediaRecorder.resume() : mediaRecorder.pause()     paused = !paused      return paused   } })()<\/code><\/pre>\n<p>  <\/p>\n<p><em>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ &lt;button id=\"pauseOrResumeRecordingBtn\">Pause\/Resume recording&lt;\/button> pauseOrResumeRecordingBtn.onclick = () => {   const paused = pauseOrResumeRecording()   console.log('@recording paused', paused) }<\/code><\/pre>\n<p>  <\/p>\n<p><em>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0437\u0430\u043f\u0438\u0441\u0438<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">export function stopRecording() {   if (!mediaRecorder) return    mediaRecorder.stop()    const _mediaDataChunks = mediaDataChunks   console.log('@media data chunks', _mediaDataChunks)    \/\/ \u043e\u0447\u0438\u0442\u043a\u0430   \/\/ \u042f\u0432\u043d\u043e\u0435 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u044f `dataavailable`   \/\/ \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u0439 \u0437\u0430\u043f\u0438\u0441\u0438   mediaRecorder.ondataavailable = null   mediaRecorder = null   mediaDataChunks = []    return _mediaDataChunks }<\/code><\/pre>\n<p>  <\/p>\n<p><em>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ &lt;button id=\"stopRecordingBtn\">Stop recording&lt;\/button> stopRecordingBtn.onclick = () => {   const chunks = stopRecording()    const blob = new Blob(chunks, {     type: DEFAULT_RECORD_MIME_TYPE   })    \/\/ \u0435\u0441\u043b\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0444\u0430\u0439\u043b, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440   \/\/ https:\/\/w3c.github.io\/FileAPI\/#file-section   \/\/ const file = new File(   \/\/   chunks,   \/\/   `new-record-${Date.now()}.${DEFAULT_RECORD_MIME_TYPE.split('\/').at(-1)}`,   \/\/   {   \/\/     type: DEFAULT_RECORD_MIME_TYPE   \/\/   }   \/\/ )    \/\/ &lt;video id=\"recordBox\" controls>&lt;\/video>   recordBox.src = URL.createObjectURL(blob)   \/\/ \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u0441\u043e \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u0435\u043c \u0444\u0430\u0439\u043b\u0430 \u043d\u0435 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442   URL.revokeObjectURL(blob)    stopTracks() }<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 <em>\u0447\u0430\u0441\u0442\u0435\u0439 \u0434\u0430\u043d\u043d\u044b\u0445<\/em>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/3q\/qb\/nc\/3qqbncxvaindynv4hlwmwz6gmrg.png\" data-src=\"https:\/\/habrastorage.org\/webt\/3q\/qb\/nc\/3qqbncxvaindynv4hlwmwz6gmrg.png\"\/>  <\/p>\n<p>  <\/p>\n<p>  <\/p>\n<h2 id=\"9-kak-preobrazovat-tekst-v-rech\">9. \u041a\u0430\u043a \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u0435\u043a\u0441\u0442 \u0432 \u0440\u0435\u0447\u044c?<\/h2>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/my-js.org\/docs\/cheatsheet\/web-speech\">\u0422\u0443\u0442\u043e\u0440\u0438\u0430\u043b \u043f\u043e Web Speech API<\/a><\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0442\u0435\u043a\u0441\u0442\u0430 \u0432 \u0440\u0435\u0447\u044c \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 <em>SpeechSynthesis<\/em>:<\/p>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/wicg.github.io\/speech-api\/#tts-section\">\u0421\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f<\/a><\/li>\n<li><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/SpeechSynthesis\">MDN<\/a><\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0414\u0430\u043d\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e\u043c \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 <em>window<\/em> (<em>window.speechSynthesis<\/em>).<\/p>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u043e\u0437\u0432\u0443\u0447\u0438\u0432\u0430\u043d\u0438\u044f \u0442\u0435\u043a\u0441\u0442\u0430 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u0433\u043e\u043b\u043e\u0441\u0430 (voices), \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0435 \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435. \u0414\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0438\u0445 \u0441\u043f\u0438\u0441\u043a\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043c\u0435\u0442\u043e\u0434 <em>getVoices<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">const voices = speechSynthesis.getVoices()<\/code><\/pre>\n<p>  <\/p>\n<p>\u042d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434 \u043d\u0430 \u0441\u0435\u0433\u043e\u0434\u043d\u044f\u0448\u043d\u0438\u0439 \u0434\u0435\u043d\u044c \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043d\u0435 \u0441\u043e\u0432\u0441\u0435\u043c \u043e\u0431\u044b\u0447\u043d\u043e. \u041f\u0440\u0438 \u043f\u0435\u0440\u0432\u043e\u043c \u043e\u0437\u0432\u0443\u0447\u0438\u0432\u0430\u043d\u0438\u0438 \u0435\u0433\u043e \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u0434\u0432\u0430\u0436\u0434\u044b, \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u044f \u0441\u043f\u0438\u0441\u043e\u043a \u0433\u043e\u043b\u043e\u0441\u043e\u0432 \u0432 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f <em>voicechanged<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">let voices = speechSynthesis.getVoices()  speechSynthesis.onvoiceschanged = () => {   voices = speechSynthesis.getVoices() }<\/code><\/pre>\n<p>  <\/p>\n<p><em>speechSynthesis<\/em> \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 <em>\u043c\u0435\u0442\u043e\u0434\u044b \u0434\u043b\u044f \u043e\u0437\u0432\u0443\u0447\u0438\u0432\u0430\u043d\u0438\u044f \u0442\u0435\u043a\u0441\u0442\u0430<\/em>:<\/p>\n<p>  <\/p>\n<ul>\n<li><em>start(utterance)<\/em> \u2014 \u0437\u0430\u043f\u0443\u0441\u043a \u043e\u0437\u0432\u0443\u0447\u0438\u0432\u0430\u043d\u0438\u044f;<\/li>\n<li><em>pause<\/em> \u2014 \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u043e\u0437\u0432\u0443\u0447\u0438\u0432\u0430\u043d\u0438\u044f;<\/li>\n<li><em>resume<\/em> \u2014 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0435 \u043e\u0437\u0432\u0443\u0447\u0438\u0432\u0430\u043d\u0438\u044f;<\/li>\n<li><em>cancel<\/em> \u2014 \u043e\u0442\u043c\u0435\u043d\u0430 (\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430) \u043e\u0437\u0432\u0443\u0447\u0438\u0432\u0430\u043d\u0438\u044f.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u041c\u0435\u0442\u043e\u0434 <em>start<\/em> \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 <em>SpeechSynthesisUtterance<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">const utterance = new SpeechSynthesisUtterance(text?)<\/code><\/pre>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/wicg.github.io\/speech-api\/#speechsynthesisutterance\">\u0421\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f<\/a><\/li>\n<li><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/SpeechSynthesisUtterance\">MDN<\/a><\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0414\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0439 <em>\u0442\u0435\u043a\u0441\u0442 \u0434\u043b\u044f \u043e\u0437\u0432\u0443\u0447\u0438\u0432\u0430\u043d\u0438\u044f<\/em>.<\/p>\n<p>  <\/p>\n<p><em>utterance<\/em> \u0438\u043c\u0435\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e <em>\u0441\u0435\u0442\u0442\u0435\u0440\u043e\u0432 \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043e\u0437\u0432\u0443\u0447\u0438\u0432\u0430\u043d\u0438\u044f<\/em>:<\/p>\n<p>  <\/p>\n<ul>\n<li><em>text<\/em> \u2014 \u0442\u0435\u043a\u0441\u0442 \u0434\u043b\u044f \u043e\u0437\u0432\u0443\u0447\u0438\u0432\u0430\u043d\u0438\u044f;<\/li>\n<li><em>lang<\/em> \u2014 \u044f\u0437\u044b\u043a \u043e\u0437\u0432\u0443\u0447\u0438\u0432\u0430\u043d\u0438\u044f;<\/li>\n<li><em>voice<\/em> \u2014 \u0433\u043e\u043b\u043e\u0441 \u0434\u043b\u044f \u043e\u0437\u0432\u0443\u0447\u0438\u0432\u0430\u043d\u0438\u044f \u0438 \u0434\u0440.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u041f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0438\u043c, \u0447\u0442\u043e \u0443 \u043d\u0430\u0441 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u0442\u0430\u043a\u043e\u0439 \u0442\u0435\u043a\u0441\u0442:<\/p>\n<p>  <\/p>\n<pre><code class=\"html\">&lt;textarea id=\"textToSpeech\" rows=\"4\"> \u041c\u044b \u2014 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u0432\u0435\u0441\u0435\u043b\u044c\u044f \u0438 \u0441\u043a\u043e\u0440\u0431\u0438 \u0440\u0443\u0434\u043d\u0438\u043a. \u041c\u044b \u2014 \u0432\u043c\u0435\u0441\u0442\u0438\u043b\u0438\u0449\u0435 \u0441\u043a\u0432\u0435\u0440\u043d\u044b \u0438 \u0447\u0438\u0441\u0442\u044b\u0439 \u0440\u043e\u0434\u043d\u0438\u043a. \u0427\u0435\u043b\u043e\u0432\u0435\u043a, \u0441\u043b\u043e\u0432\u043d\u043e \u0432 \u0437\u0435\u0440\u043a\u0430\u043b\u0435 \u043c\u0438\u0440, \u2014 \u043c\u043d\u043e\u0433\u043e\u043b\u0438\u043a. \u041e\u043d \u043d\u0438\u0447\u0442\u043e\u0436\u0435\u043d \u2014 \u0438 \u043e\u043d \u0436\u0435 \u0431\u0435\u0437\u043c\u0435\u0440\u043d\u043e \u0432\u0435\u043b\u0438\u043a! &lt;\/textarea><\/code><\/pre>\n<p>  <\/p>\n<p><em>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043e\u0437\u0432\u0443\u0447\u0438\u0432\u0430\u043d\u0438\u044f \u044d\u0442\u043e\u0433\u043e \u0442\u0435\u043a\u0441\u0442\u0430 \u0433\u043e\u043b\u043e\u0441\u043e\u043c \u043e\u0442 Google<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ \u0433\u043e\u043b\u043e\u0441 \u0434\u043b\u044f \u043e\u0437\u0432\u0443\u0447\u0438\u0432\u0430\u043d\u0438\u044f let voiceFromGoogle \/\/ \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440 \u043d\u0430\u0447\u0430\u043b\u0430 \u043e\u0437\u0432\u0443\u0447\u0438\u0432\u0430\u043d\u0438\u044f let speakingStarted  export function startSpeechSynthesis() {   if (voiceFromGoogle) return speak()    speechSynthesis.getVoices()    speechSynthesis.onvoiceschanged = () => {     const voices = speechSynthesis.getVoices()     console.log('@voices', voices)      voiceFromGoogle = voices.find((voice) => voice.name === 'Google \u0440\u0443\u0441\u0441\u043a\u0438\u0439')      speak()   } }  function speak() {   const trimmedText = textToSpeech.value.trim()   if (!trimmedText) return    const utterance = new SpeechSynthesisUtterance(trimmedText)   utterance.lang = 'ru-RU'   utterance.voice = voiceFromGoogle   console.log('@utterance', utterance)    speechSynthesis.speak(utterance)   speakingStarted = true    utterance.onend = () => {     speakingStarted = false   } }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 <em>\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ &lt;button id=\"startSpeechSynthesisBtn\">Start speech synthesis&lt;\/button> startSpeechSynthesisBtn.onclick = () => {   startSpeechSynthesis() }<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 <em>\u0441\u043f\u0438\u0441\u043a\u0430 \u0433\u043e\u043b\u043e\u0441\u043e\u0432<\/em>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/h9\/wq\/q3\/h9wqq3znyo2yulaunmmcq55vf-u.png\" data-src=\"https:\/\/habrastorage.org\/webt\/h9\/wq\/q3\/h9wqq3znyo2yulaunmmcq55vf-u.png\"\/>  <\/p>\n<p>  <\/p>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 <em>&#171;\u0432\u044b\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u043d\u0438\u044f&#187;<\/em>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/ra\/lc\/vh\/ralcvh5hdoh5bcjtlh6n3alf2ym.png\" data-src=\"https:\/\/habrastorage.org\/webt\/ra\/lc\/vh\/ralcvh5hdoh5bcjtlh6n3alf2ym.png\"\/>  <\/p>\n<p>  <\/p>\n<p>  <\/p>\n<p><em>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438\/\u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u044f \u043e\u0437\u0432\u0443\u0447\u0438\u0432\u0430\u043d\u0438\u044f<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440 \u043e\u0437\u0432\u0443\u0447\u0438\u0432\u0430\u043d\u0438\u044f `speechSynthesis.speaking` \u0432 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u0435 \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043d\u0435\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e export const pauseOrResumeSpeaking = (function () {   let paused = false    return function () {     if (!speakingStarted) return      paused ? speechSynthesis.resume() : speechSynthesis.pause()     paused = !paused      return paused   } })()<\/code><\/pre>\n<p>  <\/p>\n<p><em>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ &lt;button id=\"pauseOrResumeSpeakingBtn\">Pause\/resume speaking&lt;\/button> pauseOrResumeSpeakingBtn.onclick = () => {   const paused = pauseOrResumeSpeaking()   console.log('@speaking paused', paused) }<\/code><\/pre>\n<p>  <\/p>\n<p><em>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u043e\u0437\u0432\u0443\u0447\u0438\u0432\u0430\u043d\u0438\u044f<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">export function stopSpeaking() {   speechSynthesis.cancel() }<\/code><\/pre>\n<p>  <\/p>\n<p><em>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ &lt;button id=\"stopSpeakingBtn\">Stop speaking&lt;\/button> stopSpeakingBtn.onclick = () => {   stopSpeaking() }<\/code><\/pre>\n<p>  <\/p>\n<h2 id=\"10-kak-preobrazovat-rech-v-tekst\">10. \u041a\u0430\u043a \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0442\u044c \u0440\u0435\u0447\u044c \u0432 \u0442\u0435\u043a\u0441\u0442?<\/h2>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0440\u0435\u0447\u0438 \u0432 \u0442\u0435\u043a\u0441\u0442 \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 <em>SpeechRecognition<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 const speechRecognition =   window.SpeechRecognition || window.webkitSpeechRecognition const recognition = new speechRecognition()<\/code><\/pre>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/wicg.github.io\/speech-api\/#speechreco-section\">\u0421\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f<\/a><\/li>\n<li><a href=\"https:\/\/developer.mozilla.org\/ru\/docs\/Web\/API\/SpeechRecognition\">MDN<\/a><\/li>\n<\/ul>\n<p>  <\/p>\n<p><em>recognition<\/em> \u0438\u043c\u0435\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e <em>\u0441\u0435\u0442\u0442\u0435\u0440\u043e\u0432 \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u044f \u0440\u0435\u0447\u0438<\/em>:<\/p>\n<p>  <\/p>\n<ul>\n<li><em>lang<\/em> \u2014 \u044f\u0437\u044b\u043a \u0434\u043b\u044f \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u044f;<\/li>\n<li><em>continuous<\/em> \u2014 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442, \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u0442\u0441\u044f \u043b\u0438 \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u0435 \u043f\u043e\u0441\u043b\u0435 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043f\u0435\u0440\u0432\u043e\u0433\u043e &#171;\u0444\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e&#187; \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430;<\/li>\n<li><em>interimResults<\/em> \u2014 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442, \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u043b\u0438 &#171;\u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u044b\u0435&#187; \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u044f;<\/li>\n<li><em>maxAlternatives<\/em> \u2014 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u043d\u043d\u043e\u0433\u043e \u0441\u043b\u043e\u0432\u0430, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u044b\u0445 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c. \u0412\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0442\u0441\u044f \u0432 \u0432\u0438\u0434\u0435 \u043c\u0430\u0441\u0441\u0438\u0432\u0430, \u043f\u0435\u0440\u0432\u044b\u043c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u043c \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0435\u0435 \u0441 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 \u0441\u043b\u043e\u0432\u043e.<\/li>\n<\/ul>\n<p>  <\/p>\n<p><em>\u041c\u0435\u0442\u043e\u0434\u044b \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u0435\u043c<\/em>, \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u0435 <em>recognition<\/em>:<\/p>\n<p>  <\/p>\n<ul>\n<li><em>start<\/em> \u2014 \u0437\u0430\u043f\u0443\u0441\u043a \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u044f;<\/li>\n<li><em>stop<\/em> \u2014 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u044f;<\/li>\n<li><em>abort<\/em> \u2014 \u043f\u0440\u0435\u043a\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u044f.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u041f\u0440\u0438 \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u0438 \u0440\u0435\u0447\u0438 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<p>  <\/p>\n<ul>\n<li>\u043f\u0440\u0438 \u0432\u044b\u0437\u043e\u0432\u0435 \u043c\u0435\u0442\u043e\u0434\u0430 <em>start<\/em> \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u043d\u0430\u0441 &#171;\u0441\u043b\u0443\u0448\u0430\u0442\u044c&#187;;<\/li>\n<li>\u043a\u0430\u0436\u0434\u043e\u0435 \u0441\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0435 \u0441\u043b\u043e\u0432\u043e \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043a\u0430\u043a \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0430\u044f \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c \u2014 \u043c\u0430\u0441\u0441\u0438\u0432, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0439 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e (\u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 <em>maxAlternatives<\/em>) \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u044d\u0442\u043e\u0433\u043e \u0441\u043b\u043e\u0432\u0430;<\/li>\n<li>\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u0441\u043b\u043e\u0432\u0430 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043a \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u044e \u0441\u043e\u0431\u044b\u0442\u0438\u044f <em>result<\/em>;<\/li>\n<li>\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u043c\u044b\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u044b\u043c\u0438 (interim) \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430\u043c\u0438 \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u044f;<\/li>\n<li>\u043f\u043e \u0438\u0441\u0442\u0435\u0447\u0435\u043d\u0438\u0438 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 (\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c\u043e\u0433\u043e \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c) \u043f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u043c\u044b \u0437\u0430\u043c\u043e\u043b\u0447\u0430\u043b\u0438, \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u044b\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0441\u0442\u0430\u0442\u0443\u0441 \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e (final);<\/li>\n<li>\u0441\u043d\u043e\u0432\u0430 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 <em>result<\/em>: \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 <em>isFinal<\/em> \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f <em>true<\/em>;<\/li>\n<li>\u043f\u043e\u0441\u043b\u0435 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 <em>end<\/em>;<\/li>\n<li>\u0435\u0441\u043b\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 <em>continuous<\/em> \u0438\u043c\u0435\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <em>false<\/em>, \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u0441\u044f \u043f\u043e\u0441\u043b\u0435 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0441\u043b\u043e\u0432\u0430;<\/li>\n<li>\u0435\u0441\u043b\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 <em>interimResults<\/em> \u0438\u043c\u0435\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <em>false<\/em>, \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0431\u0443\u0434\u0443\u0442 \u0441\u0440\u0430\u0437\u0443 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043a\u0430\u043a \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0435;<\/li>\n<li>\u0441\u043e\u0431\u044b\u0442\u0438\u0435 <em>result<\/em> \u0438\u043c\u0435\u0435\u0442 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e <em>resultIndex<\/em>, \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0438\u043d\u0434\u0435\u043a\u0441 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u043e\u0433\u043e \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430.<\/li>\n<\/ul>\n<p>  <\/p>\n<p><em>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435<\/em>: \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u043d\u0435 \u0443\u043c\u0435\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u043f\u0443\u043d\u043a\u0442\u0443\u0430\u0446\u0438\u0435\u0439: \u043e\u043d \u043f\u043e\u043d\u0438\u043c\u0430\u0435\u0442 \u0441\u043b\u043e\u0432\u0430, \u043d\u043e \u043d\u0435 \u0437\u043d\u0430\u043a\u0438 \u043f\u0440\u0435\u043f\u0438\u043d\u0430\u043d\u0438\u044f. \u0422\u0430\u043a\u0436\u0435 <em>\u043e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435<\/em>, \u0447\u0442\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u043e\u0435 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u044f \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u043c \u0438 \u043f\u043e\u0447\u0442\u0438 \u0432\u0441\u0435\u0433\u0434\u0430 \u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u044b\u043c.<\/p>\n<p>  <\/p>\n<p>\u041f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0438\u043c, \u0447\u0442\u043e \u0443 \u043d\u0430\u0441 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u0438\u043d\u043f\u0443\u0442 \u0434\u043b\u044f \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u044b\u0445 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u0438 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0439 \u0431\u043b\u043e\u043a \u0434\u043b\u044f \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0445 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u044f \u0440\u0435\u0447\u0438:<\/p>\n<p>  <\/p>\n<pre><code class=\"html\">&lt;div class=\"speech-to-text-wrapper\">   &lt;input type=\"text\" id=\"interimTranscriptBox\" \/>   &lt;textarea id=\"finalTranscriptBox\" rows=\"4\">&lt;\/textarea> &lt;\/div><\/code><\/pre>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b, \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u043e\u0439 \u0441 \u043f\u0443\u043d\u043a\u0442\u0443\u0430\u0446\u0438\u0435\u0439, \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0442\u0430\u043a\u043e\u0439 \u0441\u043b\u043e\u0432\u0430\u0440\u044c:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">const DICTIONARY = {   \u0442\u043e\u0447\u043a\u0430: '.',   \u0437\u0430\u043f\u044f\u0442\u0430\u044f: ',',   \u0432\u043e\u043f\u0440\u043e\u0441: '?',   \u0432\u043e\u0441\u043a\u043b\u0438\u0446\u0430\u043d\u0438\u0435: '!',   \u0434\u0432\u043e\u0435\u0442\u043e\u0447\u0438\u0435: ':',   \u0442\u0438\u0440\u0435: '-',   \u0430\u0431\u0437\u0430\u0446: '\\n',   \u043e\u0442\u0441\u0442\u0443\u043f: '\\t' }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0410 \u0434\u043b\u044f \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b, \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u043e\u0439 \u0441 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c, \u0442\u0430\u043a\u0438\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ \u0437\u0430\u043c\u0435\u043d\u044f\u0435\u043c \u0441\u043b\u043e\u0432\u0430 \u043d\u0430 \u0437\u043d\u0430\u043a\u0438 \u043f\u0440\u0435\u043f\u0438\u043d\u0430\u043d\u0438\u044f const editInterim = (s) => s   .split(' ')   .map((word) => {     word = word.trim()     return DICTIONARY[word.toLowerCase()]       ? DICTIONARY[word.toLowerCase()]       : word   })   .join(' ')  \/\/ \u0443\u0434\u0430\u043b\u044f\u0435\u043c \u043b\u0438\u0448\u043d\u0438\u0435 \u043f\u0440\u043e\u0431\u0435\u043b\u044b const editFinal = (s) => s.replace(\/\\s{1,}([\\.+,?!:-])\/g, '$1')<\/code><\/pre>\n<p>  <\/p>\n<p><em>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u044f \u0440\u0435\u0447\u0438<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \"\u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u0442\u0435\u043b\u044f\" let recognition \/\/ \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440 \u043d\u0430\u0447\u0430\u043b\u0430 \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u044f let recognitionStarted \/\/ \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 let finalTranscript  \/\/ \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043e\u0447\u0438\u0441\u0442\u043a\u0438 function resetRecognition() {   recognition = null   recognitionStarted = false   finalTranscript = ''   interimTranscriptBox.value = ''   finalTranscriptBox.value = '' }  export function startSpeechRecognition() {   resetRecognition()    recognition = new speechRecognition()   \/\/ \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u044f   recognition.continuous = true   recognition.interimResults = true   recognition.maxAlternatives = 3   recognition.lang = 'ru-RU'   console.log('@recognition', recognition)    recognition.start()   recognitionStarted = true    recognition.onend = () => {     \/\/ \u041f\u043e\u0432\u0442\u043e\u0440\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u0435, \u0435\u0441\u043b\u0438     \/\/ \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440 \u0438\u043c\u0435\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 `true`     if (!recognitionStarted) return     recognition.start()   }    recognition.onresult = (e) => {     \/\/ \u041f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u044b\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u043c \u0446\u0438\u043a\u043b\u0435 \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u044f     let interimTranscript = ''     \/\/ \u041f\u0435\u0440\u0435\u0431\u0438\u0440\u0430\u0435\u043c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0441 \u0442\u043e\u0433\u043e \u043c\u0435\u0441\u0442\u0430, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0438\u0441\u044c \u0432 \u043f\u0440\u043e\u0448\u043b\u044b\u0439 \u0440\u0430\u0437     for (let i = e.resultIndex; i &lt; e.results.length; i++) {       \/\/ \u0410\u0442\u0440\u0438\u0431\u0443\u0442 `isFinal` \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u043c \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u0440\u0435\u0447\u044c \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u043b\u0430\u0441\u044c (\u043c\u044b \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u043b\u0438 \u0433\u043e\u0432\u043e\u0440\u0438\u0442\u044c)       if (e.results[i].isFinal) {         \/\/ \u0420\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0443\u0435\u043c \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u044b\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442         const interimResult = editInterim(e.results[i][0].transcript)         \/\/ \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0435\u0433\u043e \u043a \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u043c\u0443         finalTranscript += interimResult       } else {         \/\/ \u0412 \u043f\u0440\u043e\u0442\u0438\u0432\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u043d\u043d\u043e\u0435 \u0441\u043b\u043e\u0432\u043e \u0432 \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u044b\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442         interimTranscript += e.results[i][0].transcript       }     }     \/\/ \u0417\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u044b\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0432 `input`     interimTranscriptBox.value = interimTranscript     \/\/ \u0420\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0443\u0435\u043c \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442     finalTranscript = editFinal(finalTranscript)     \/\/ \u0438 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0435\u0433\u043e \u0432 `textarea`     finalTranscriptBox.value = finalTranscript   } }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 <em>\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ &lt;button id=\"startSpeechRecognitionBtn\">Start speech synthesis&lt;\/button> startSpeechRecognitionBtn.onclick = () => {   startSpeechRecognition() }<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 <em>&#171;\u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u0442\u0435\u043b\u044f&#187;<\/em>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/jb\/9g\/tj\/jb9gtj-fiphwmnjgnunyih-orx4.png\" data-src=\"https:\/\/habrastorage.org\/webt\/jb\/9g\/tj\/jb9gtj-fiphwmnjgnunyih-orx4.png\"\/>  <\/p>\n<p>  <\/p>\n<p>  <\/p>\n<p><em>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u044f<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">export function stopRecognition() {   if (!recognition) return   recognition.stop()   recognitionStarted = false }<\/code><\/pre>\n<p>  <\/p>\n<p><em>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ &lt;button id=\"stopRecognitionBtn\">Stop recognition&lt;\/button> stopRecognitionBtn.onclick = () => {   stopRecognition() }<\/code><\/pre>\n<p>  <\/p>\n<p><em>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u043f\u0440\u0435\u043a\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u044f<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">export function abortRecognition() {   if (!recognition) return   recognition.abort()   resetRecognition() }<\/code><\/pre>\n<p>  <\/p>\n<p><em>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a<\/em>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ &lt;button id=\"abortRecognitionBtn\">Abort recognition&lt;\/button> abortRecognitionBtn.onclick = () => {   abortRecognition() }<\/code><\/pre>\n<p>  <\/p>\n<h2 id=\"11-kak-opredelit-podderzhku-vozmozhnostey-po-rabote-s-media-brauzerom\">11. \u041a\u0430\u043a \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 \u043f\u043e \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 \u043c\u0435\u0434\u0438\u0430 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c?<\/h2>\n<p>  <\/p>\n<p><em>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 \u043f\u043e \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 \u043c\u0435\u0434\u0438\u0430<\/em>, \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043d\u044b\u0445 \u0432 \u0434\u0430\u043d\u043d\u043e\u0439 \u0448\u043f\u0430\u0440\u0433\u0430\u043b\u043a\u0435:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">export function verifySupport() {   const unsupportedFeatures = []    if (!('mediaDevices' in navigator)) {     unsupportedFeatures.push('mediaDevices')   }    if (     !('captureStream' in HTMLAudioElement.prototype) &amp;&amp;     !('mozCaptureStream' in HTMLAudioElement.prototype)   ) {     unsupportedFeatures.push('captureStream')   }    ;['MediaStream', 'MediaRecorder', 'Blob', 'File', 'ImageCapture'].forEach(     (f) => {       if (!(f in window)) {         unsupportedFeatures.push(f)       }     }   )    if (!('speechSynthesis' in window)) {     unsupportedFeatures.push('speechSynthesis')   }    if (     !('SpeechRecognition' in window) &amp;&amp;     !('webkitSpeechRecognition' in window)   ) {     unsupportedFeatures.push('SpeechRecognition')   }    return unsupportedFeatures }<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u044d\u0442\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">const unsupportedFeatures = verifySupport() if (unsupportedFeatures.length) {   console.error(unsupportedFeatures) }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0438 \u0432\u0441\u0435 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b \u0438 \u043c\u0435\u0442\u043e\u0434\u044b \u043f\u043e \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 \u043c\u0435\u0434\u0438\u0430, \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c\u044b\u0435 \u0432 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0445 \u0432 \u043d\u0430\u0447\u0430\u043b\u0435 \u0448\u043f\u0430\u0440\u0433\u0430\u043b\u043a\u0438 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f\u0445.<\/p>\n<p>  <\/p>\n<p>\u0421\u043b\u0435\u0434\u0443\u0435\u0442 \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0435\u0449\u0435 \u0434\u0432\u0430 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430, \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u0445 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043c\u0435\u0434\u0438\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u043e\u0441\u0442\u0430\u0432\u0438\u043b\u0438 \u0431\u0435\u0437 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u044f \u0432 \u0441\u0438\u043b\u0443 \u0438\u0445 \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0438 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u043d\u043e\u0441\u0442\u0438:<\/p>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/www.w3.org\/TR\/webaudio\/\">Web Audio API<\/a><\/li>\n<li><a href=\"https:\/\/w3c.github.io\/webrtc-pc\/\">WebRTC 1.0: Real-Time Communication Between Browsers<\/a><\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0427\u0442\u043e \u043a\u0430\u0441\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e, \u0432\u043e\u0442 \u043f\u0430\u0440\u043e\u0447\u043a\u0430 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u043e\u0432, \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0447\u0430\u0442\u044c \u0438\u0437\u0443\u0447\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430:<\/p>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/my-js.org\/docs\/guide\/webrtc\">WebRTC \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0438 \u043a\u0430\u0436\u0434\u043e\u0433\u043e<\/a><\/li>\n<li><a href=\"https:\/\/habr.com\/ru\/company\/timeweb\/blog\/649369\/\">React: WebRTC Media Call<\/a><\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044e \u0437\u0430 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u0438 happy coding!<\/p>\n<p>  <\/p>\n<hr\/>\n<p>  <\/p>\n<p><a href=\"https:\/\/cloud.timeweb.com\/vds-promo-10-rub?utm_source=habr&amp;utm_medium=banner&amp;utm_campaign=vds-promo-10-rub\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/co\/e2\/kh\/coe2kha8u8_pypip-2k3wk3ppa0.png\" data-src=\"https:\/\/habrastorage.org\/webt\/co\/e2\/kh\/coe2kha8u8_pypip-2k3wk3ppa0.png\"\/><\/a><\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"v-portal\" style=\"display:none;\"><\/div>\n<\/div>\n<p> <!----> <!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/company\/timeweb\/blog\/667148\/\"> https:\/\/habr.com\/ru\/company\/timeweb\/blog\/667148\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/webt\/vn\/tg\/pz\/vntgpzpgemeytutve-gevcpoq0e.jpeg\" data-src=\"https:\/\/habrastorage.org\/webt\/vn\/tg\/pz\/vntgpzpgemeytutve-gevcpoq0e.jpeg\" data-blurred=\"true\"\/>  <\/p>\n<p>  <\/p>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u0432\u0435\u0442, \u0434\u0440\u0443\u0437\u044c\u044f!<\/p>\n<p>  <\/p>\n<p>\u0412 \u0434\u0430\u043d\u043d\u043e\u0439 \u0448\u043f\u0430\u0440\u0433\u0430\u043b\u043a\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b \u0432\u0441\u0435 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b \u0438 \u043c\u0435\u0442\u043e\u0434\u044b \u043f\u043e \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 \u043c\u0435\u0434\u0438\u0430 \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435, \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c\u044b\u0435 \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f\u0445:<\/p>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/w3c.github.io\/mediacapture-main\/\">Media Capture and Streams<\/a><\/li>\n<li><a href=\"https:\/\/w3c.github.io\/mediacapture-screen-share\/\">Screen Capture<\/a><\/li>\n<li><a href=\"https:\/\/www.w3.org\/TR\/mediacapture-fromelement\/\">Media Capture from DOM Elements<\/a><\/li>\n<li><a href=\"https:\/\/www.w3.org\/TR\/image-capture\/\">MediaStream Image Capture<\/a><\/li>\n<li><a href=\"https:\/\/www.w3.org\/TR\/mediastream-recording\/\">MediaStream Recording<\/a><\/li>\n<li><a href=\"https:\/\/wicg.github.io\/speech-api\/\">Web Speech API<\/a><\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0428\u043f\u0430\u0440\u0433\u0430\u043b\u043a\u0430 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0430 \u0432 \u0444\u043e\u0440\u043c\u0435 \u0432\u043e\u043f\u0440\u043e\u0441-\u043e\u0442\u0432\u0435\u0442.<\/p>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/harryheman\/Blog-Posts\/tree\/master\/web-media\">\u0420\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0441 \u043a\u043e\u0434\u043e\u043c \u0432\u0441\u0435\u0445 \u0441\u043d\u0438\u043f\u043f\u0435\u0442\u043e\u0432<\/a><\/li>\n<li><a href=\"https:\/\/stackblitz.com\/edit\/js-pfyter?file=index.html\">\u041f\u0435\u0441\u043e\u0447\u043d\u0438\u0446\u0430<\/a><\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0422\u0443\u0442\u043e\u0440\u0438\u0430\u043b\u044b \u043f\u043e \u0442\u0435\u043c\u0435:<\/p>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/habr.com\/ru\/company\/timeweb\/blog\/581086\/\">JavaScript: \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438 \u0437\u0432\u0443\u043a\u0430<\/a><\/li>\n<li><a href=\"https:\/\/habr.com\/ru\/company\/timeweb\/blog\/591417\/\">JavaScript: \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438 \u044d\u043a\u0440\u0430\u043d\u0430<\/a><\/li>\n<li><a href=\"https:\/\/habr.com\/ru\/company\/timeweb\/blog\/646831\/\">JavaScript: \u0437\u0430\u0445\u0432\u0430\u0442 \u043c\u0435\u0434\u0438\u0430\u043f\u043e\u0442\u043e\u043a\u0430 \u0438\u0437 DOM \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432<\/a><\/li>\n<li><a href=\"https:\/\/habr.com\/ru\/company\/timeweb\/blog\/650233\/\">JavaScript: \u0434\u0435\u043b\u0430\u0435\u043c \u0441\u0435\u043b\u0444\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430<\/a><\/li>\n<li><a href=\"https:\/\/habr.com\/ru\/company\/timeweb\/blog\/655143\/\">JavaScript: \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u0447\u0430\u0442 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Socket.io, Express \u0438 React \u0441 \u0430\u043a\u0446\u0435\u043d\u0442\u043e\u043c \u043d\u0430 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 \u043c\u0435\u0434\u0438\u0430<\/a><\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0415\u0441\u043b\u0438 \u0432\u0430\u043c \u044d\u0442\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e, \u043f\u0440\u043e\u0448\u0443 \u043f\u043e\u0434 \u043a\u0430\u0442.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-333539","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/333539","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=333539"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/333539\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=333539"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=333539"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=333539"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}