التقاط الصوت والفيديو بتنسيق HTML5

مقدمة

التقاط الصوت أو الفيديو كان "الكأس المقدسة" لتطوير الويب لفترة طويلة. لسنوات عديدة، كان علينا الاعتماد على المكوّنات الإضافية في المتصفح (فلاش أو Silverlight) لإنجاز المهمة. هيّا

HTML5 للإنقاذ. وقد لا يكون هذا الأمر واضحًا، لكن ظهور HTML5 قد جلب زيادة كبيرة في الوصول إلى أجهزة الجهاز. رصد الموقع الجغرافي (GPS) واجهة برمجة التطبيقات Orientation API (مقياس التسارع) وWebGL (GPU) وWeb Audio API (أجهزة الصوت) من الأمثلة المثالية على ذلك. هذه الميزات قوية للغاية، وتعرض واجهات برمجة تطبيقات JavaScript عالية المستوى بالإضافة إلى إمكانات الأجهزة الأساسية للنظام.

يقدم هذا البرنامج التعليمي واجهة برمجة تطبيقات جديدة، وهي GetUserMedia، التي تتيح تطبيقات الويب للدخول إلى كاميرا المستخدم وميكروفونه.

الطريق إلى getUserMedia()

إذا لم تكن مدركًا لتاريخها، فإنّ طريقة وصولنا إلى واجهة برمجة تطبيقات getUserMedia() هي قصة شيقة.

صيغ متعددة لـ "واجهات برمجة تطبيقات التقاط الوسائط" على مدار السنوات القليلة الماضية. أدرك العديد من الأشخاص الحاجة إلى التمكن من الوصول إلى الأجهزة الأصلية على الويب، ولكنهم دفعت الجميع ووالدتهم إلى وضع مواصفات جديدة معًا. حسنًا لدرجة أن W3C قررت أخيرًا تشكيل مجموعة عمل. الغرض الوحيد منه؟ فكر في الجنون! مجموعة عمل سياسة واجهات برمجة تطبيقات الأجهزة (DAP) بدمج عدد كبير من المقترحات وتوحيدها.

سأحاول تلخيص ما حدث في عام 2011...

الجولة 1: التقاط وسائط HTML

كانت ميزة HTML Media Capture هي الأولى التي طوّرها DAP لتوحيد التقاط الوسائط على الويب. تعمل هذه الميزة من خلال تحميل <input type="file"> زائدة وإضافة قيم جديدة للمعلمة accept.

إذا أردت السماح للمستخدمين بأخذ لقطة لأنفسهم باستخدام كاميرا الويب، الذي يمكن تحقيقه باستخدام capture=camera:

<input type="file" accept="image/*;capture=camera">

إنّ تسجيل فيديو أو صوت يشبه ما يلي:

<input type="file" accept="video/*;capture=camcorder">
<input type="file" accept="audio/*;capture=microphone">

لطيف جدًا، أليس كذلك؟ أحب بشكل خاص أنها تعيد استخدام إدخال ملف. دلاليًا، له معنى كبير. حيث يظهر هذا "API" بالتحديد القصور هو القدرة على تنفيذ تأثيرات في الوقت الفعلي (مثل عرض بيانات كاميرا الويب المباشرة على <canvas> وتطبيق فلاتر WebGL) لا يتيح لك HTML Media Capture إلا تسجيل ملف وسائط أو أخذ لقطة في الوقت المناسب.

الدعم:

  • متصفّح Android 3.0 - بأحد عمليات التنفيذ الأولى. يمكنك مشاهدة هذا الفيديو لتجربة هذه الميزة.
  • Chrome لنظام Android (0.16)
  • فايرفوكس للجوّال 10.0
  • iOS6 Safari وChrome (دعم جزئي)

الجولة 2: عنصر الجهاز

اعتقد الكثيرون أن HTML Media Capture كان يحدّ من القيود المفروضة، لذلك التي كانت تدعم أي نوع من الأجهزة (المستقبلية). وليس من المستغرب أن التصميم يسمى لعنصر جديد، وهو العنصر <device>، والذي أصبح السابق لـ getUserMedia().

كان Opera من أوائل المتصفّحات التي اعتمدت عمليات تنفيذ أوّلية من مقطع الفيديو بناءً على العنصر <device>. بعد فترة وجيزة (اليوم نفسه على وجه التحديد) قررت شركة WhatWG إزالة علامة <device> لصالح منتج آخر وجديد، ولكن هذه المرة واجهة برمجة تطبيقات JavaScript تُسمى navigator.getUserMedia() وبعد أسبوع، طرحت Opera إصدارات جديدة تضمّنت التوافق مع مواصفات getUserMedia() المُحدَّثة. في وقت لاحق من ذلك العام، انضمت Microsoft إلى البرنامج من خلال إطلاق برنامج Lab for IE9. تدعم المواصفات الجديدة.

هذا ما كان سيبدو عليه <device>:

<device type="media" onchange="update(this.data)"></device>
<video autoplay></video>
<script>
  function update(stream) {
    document.querySelector('video').src = stream.url;
  }
</script>

الدعم:

ولسوء الحظ، لم يتم إطلاق أي متصفح على الإطلاق يتضمن <device>. هناك واجهة برمجة تطبيقات واحدة أخرى لا داعي للقلق بشأنها، وأعتقد أنّ :) <device> لديها أمران رائعان على الرغم من ذلك: 1.) كان دلالياً، 2.) يمكن توسيعه بسهولة لدعم أكثر من مجرد أجهزة صوت/فيديو.

خذ نفَسًا. هذه الأشياء تتحرك بسرعة!

الجولة 3: WebRTC

في النهاية، سار العنصر <device> في مسار مشروع Dodo.

يتم تسريع وتيرة العثور على واجهة برمجة تطبيقات للالتقاط مناسبة بفضل جهد WebRTC (الاتصالات في الوقت الفعلي على الويب). يشرف مجموعة عمل W3C WebRTC على هذه المواصفات. ويتم التنفيذ من قِبل Google وOpera وMozilla وبعض التطبيقات الأخرى.

يرتبط getUserMedia() ببروتوكول WebRTC لأنّه البوابة إلى هذه المجموعة من واجهات برمجة التطبيقات. يوفر وسائل الوصول إلى الكاميرا المحلية/بث الميكروفون للمستخدم.

الدعم:

تم توفير getUserMedia() في الإصدارات 21 من Chrome وOpera 18 وFirefox 17.

الخطوات الأولى

باستخدام navigator.mediaDevices.getUserMedia()، يمكننا أخيرًا النقر على كاميرا الويب وإدخال الميكروفون بدون مكوّن إضافي. بإمكانك الآن الوصول إلى الكاميرا عبر مكالمة هاتفية وليس إمكانية تثبيت التطبيق. ويتم إخفاؤها مباشرةً في المتصفِّح هل أنت متحمس؟

رصد الميزات

إنّ رصد الميزات هو إجراء بسيط للتحقّق من توفُّر navigator.mediaDevices.getUserMedia:

if (navigator.mediaDevices?.getUserMedia) {
  // Good to go!
} else {
  alert("navigator.mediaDevices.getUserMedia() is not supported");
}

الحصول على إمكانية الوصول إلى جهاز إدخال

لاستخدام كاميرا الويب أو الميكروفون، نحتاج إلى طلب إذن. المعلمة الأولى لـ navigator.mediaDevices.getUserMedia() هي كائن يحدد التفاصيل المتطلبات لكل نوع من الوسائط التي تريد الوصول إليها. على سبيل المثال، إذا كنت تريد الوصول إلى كاميرا الويب، يجب أن تكون المَعلمة الأولى هي {video: true}. لاستخدام كل من الميكروفون والكاميرا، البطاقة {video: true, audio: true}:

<video autoplay></video>

<script>
  navigator.mediaDevices
    .getUserMedia({ video: true, audio: true })
    .then((localMediaStream) => {
      const video = document.querySelector("video");
      video.srcObject = localMediaStream;
    })
    .catch((error) => {
      console.log("Rejected!", error);
    });
</script>

موافق. ما الذي يحدث هنا؟ يعد التقاط الوسائط مثالاً رائعًا على واجهات برمجة تطبيقات HTML5 الجديدة معًا. ويعمل هذا البرنامج مع الزملاء في HTML5 الآخرين، مثل <audio> و<video>. يُرجى العلم أنّنا لا نضبط السمة src أو ندرج عناصر <source>. في العنصر <video>. فبدلاً من إرسال عنوان URL إلى ملف وسائط في الفيديو، نستخدم srcObject إلى الكائن LocalMediaStream الذي يمثل كاميرا الويب.

أنا أطلب أيضًا من <video> إلى autoplay، وإلّا فسيتم تجميده على الإطار الأول. تتم إضافة "controls" على النحو المتوقَّع أيضًا.

ضبط قيود الوسائط (درجة الدقة والارتفاع والعرض)

يمكن أيضًا استخدام المَعلمة الأولى لـ getUserMedia() لتحديد المزيد من المتطلبات (أو القيود) على بث الوسائط المعروض. على سبيل المثال، بدلاً من الإشارة فقط إلى رغبتك في الوصول الأساسي إلى الفيديو (مثل {video: true})، يمكنك أيضًا أن تطلب البث. الدقة العالية:

const hdConstraints = {
  video: { width: { exact:  1280} , height: { exact: 720 } },
};

const stream = await navigator.mediaDevices.getUserMedia(hdConstraints);
const vgaConstraints = {
  video: { width: { exact:  640} , height: { exact: 360 } },
};

const stream = await navigator.mediaDevices.getUserMedia(hdConstraints);

لمزيد من الإعدادات، يُرجى الاطّلاع على Restrictts API.

اختيار مصدر وسائط

تطلب الطريقة enumerateDevices() للواجهة MediaDevices قائمة بأجهزة إدخال وإخراج الوسائط المتاحة، مثل الميكروفونات والكاميرات وسماعات الرأس وما إلى ذلك. يتم التعامل مع الوعد المعروض باستخدام مصفوفة من عناصر MediaDeviceInfo تصف الأجهزة.

في هذا المثال، تم اختيار آخر ميكروفون وكاميرا تم العثور عليهما مصدر بث الوسائط:

if (!navigator.mediaDevices?.enumerateDevices) {
  console.log("enumerateDevices() not supported.");
} else {
  // List cameras and microphones.
  navigator.mediaDevices
    .enumerateDevices()
    .then((devices) => {
      let audioSource = null;
      let videoSource = null;

      devices.forEach((device) => {
        if (device.kind === "audioinput") {
          audioSource = device.deviceId;
        } else if (device.kind === "videoinput") {
          videoSource = device.deviceId;
        }
      });
      sourceSelected(audioSource, videoSource);
    })
    .catch((err) => {
      console.error(`${err.name}: ${err.message}`);
    });
}

async function sourceSelected(audioSource, videoSource) {
  const constraints = {
    audio: { deviceId: audioSource },
    video: { deviceId: videoSource },
  };
  const stream = await navigator.mediaDevices.getUserMedia(constraints);
}

يمكنك مشاهدة العرض التوضيحي الرائع للفنان "سام دوتون" حول كيفية للسماح للمستخدمين باختيار مصدر الوسائط

الأمان

تعرض المتصفّحات مربّع حوار الأذونات عند طلب الرقم navigator.mediaDevices.getUserMedia(). والذي يتيح للمستخدمين خيار منح أو منع الوصول إلى الكاميرا/الميكروفون. على سبيل المثال، هنا هو مربّع حوار الأذونات في Chrome:

مربّع حوار الأذونات في Chrome
مربّع حوار الأذونات في Chrome

توفير إجراء احتياطي

بالنسبة إلى المستخدمين الذين لا يتوفَّر لديهم navigator.mediaDevices.getUserMedia()، يمكنك اتخاذ إجراء احتياطي إلى ملف فيديو حالي إذا لم تكن واجهة برمجة التطبيقات متوافقة و/أو تعذّر الاتصال لسبب ما:

if (!navigator.mediaDevices?.getUserMedia) {
  video.src = "fallbackvideo.webm";
} else {
  const stream = await navigator.mediaDevices.getUserMedia({ video: true });
  video.srcObject = stream;
}