إضافة الميزات الأساسية إلى مستقبِل الويب المخصّص

تحتوي هذه الصفحة على مقتطفات من الرموز وأوصاف للميزات المتاحة لتطبيق "برنامج استقبال الويب المخصّص".

  1. عنصر cast-media-player يمثّل واجهة مستخدم مشغّل مدمج مضمّنة في Web Receiver.
  2. نمط مخصّص يشبه CSS لعنصر cast-media-player من أجل تحديد نمط عناصر مختلفة في واجهة المستخدم، مثل background-image وsplash-image وfont-family.
  3. عنصر نص برمجي لتحميل إطار عمل Web Receiver
  4. رمز JavaScript لاعتراض الرسائل والتعامل مع الأحداث
  5. قائمة المحتوى التالي للتشغيل التلقائي
  6. خيارات ضبط عملية التشغيل
  7. خيارات لضبط سياق Web Receiver
  8. خيارات لضبط الأوامر التي يتيحها تطبيق "أداة استقبال الويب"
  9. طلب JavaScript لبدء تطبيق "أداة استقبال الويب"

إعدادات التطبيق وخياراته

إعداد التطبيق

CastReceiverContext هي الفئة الخارجية المعروضة للمطوّر، وهي تدير عملية تحميل المكتبات الأساسية وتتولّى عملية إعداد Web Receiver SDK. توفر حزمة SDK واجهات برمجة تطبيقات تتيح لمطوّري التطبيقات ضبط إعدادات حزمة SDK من خلال CastReceiverOptions. يتم تقييم عمليات الإعداد هذه مرة واحدة عند تشغيل التطبيق، ويتم نقلها إلى حزمة تطوير البرامج (SDK) عند ضبط المَعلمة الاختيارية في طلب start.

يوضّح المثال أدناه كيفية إلغاء السلوك التلقائي لتحديد ما إذا كان اتصال المرسل لا يزال نشطًا. عندما يتعذّر على Web Receiver التواصل مع جهاز الإرسال لمدة maxInactivity ثانية، يتم إرسال الحدث SENDER_DISCONNECTED. تلغي الإعدادات أدناه هذه المهلة. يمكن أن يكون ذلك مفيدًا عند تصحيح الأخطاء لأنّه يمنع تطبيق Web Receiver من إغلاق جلسة "أداة تصحيح الأخطاء عن بُعد في Chrome" عندما لا يكون هناك أي أجهزة إرسال متصلة في حالة IDLE.

const context = cast.framework.CastReceiverContext.getInstance();
const options = new cast.framework.CastReceiverOptions();
options.maxInactivity = 3600; // Development only
context.start(options);

ضبط المشغّل

عند تحميل المحتوى، توفّر حزمة تطوير البرامج Web Receiver SDK طريقة لضبط متغيرات التشغيل، مثل معلومات إدارة الحقوق الرقمية (DRM) وإعدادات إعادة المحاولة ومعالجات الطلبات باستخدام cast.framework.PlaybackConfig. تتولّى PlayerManager معالجة هذه المعلومات، ويتم تقييمها عند إنشاء اللاعبين. يتم إنشاء المشغّلات في كل مرة يتم فيها تمرير عملية تحميل جديدة إلى Web Receiver SDK. يتم تقييم التعديلات التي يتم إجراؤها على PlaybackConfig بعد إنشاء المشغّل في عملية تحميل المحتوى التالية. توفّر حزمة تطوير البرامج (SDK) الطرق التالية لتعديل PlaybackConfig.

  • CastReceiverOptions.playbackConfig لإلغاء خيارات الإعداد التلقائية عند بدء CastReceiverContext.
  • PlayerManager.getPlaybackConfig() للحصول على الإعدادات الحالية.
  • PlayerManager.setPlaybackConfig() لتجاوز الإعداد الحالي. يتم تطبيق هذا الإعداد على جميع عمليات التحميل اللاحقة أو إلى أن يتم إلغاؤه مرة أخرى.
  • PlayerManager.setMediaPlaybackInfoHandler() لتطبيق إعدادات إضافية فقط على عنصر الوسائط الذي يتم تحميله بالإضافة إلى الإعدادات الحالية. يتم استدعاء المعالج قبل إنشاء اللاعب مباشرةً. التغييرات التي يتم إجراؤها هنا ليست دائمة ولا يتم تضمينها في طلبات البحث إلى getPlaybackConfig(). عند تحميل عنصر الوسائط التالي، يتم استدعاء معالج الأحداث هذا مرة أخرى.

يوضّح المثال أدناه كيفية ضبط PlaybackConfig عند تهيئة CastReceiverContext. تتجاوز عملية الإعداد الطلبات الصادرة للحصول على بيانات وصفية. يحدّد المعالج أنّه يجب تقديم طلبات Access-Control في CORS باستخدام بيانات الاعتماد، مثل ملفات تعريف الارتباط أو عناوين التفويض.

const playbackConfig = new cast.framework.PlaybackConfig();
playbackConfig.manifestRequestHandler = requestInfo => {
  requestInfo.withCredentials = true;
};
context.start({playbackConfig: playbackConfig});

يوضّح المثال أدناه كيفية إلغاء PlaybackConfig باستخدام الدالة getter والدالة setter المتوفّرتين في PlayerManager. يضبط هذا الإعداد المشغّل على استئناف تشغيل المحتوى بعد تحميل شريحة واحدة.

const playerManager =
    cast.framework.CastReceiverContext.getInstance().getPlayerManager();
const playbackConfig = (Object.assign(
            new cast.framework.PlaybackConfig(), playerManager.getPlaybackConfig()));
playbackConfig.autoResumeNumberOfSegments = 1;
playerManager.setPlaybackConfig(playbackConfig);

يوضّح المثال أدناه كيفية تجاهل PlaybackConfig لطلب تحميل معيّن باستخدام معالج معلومات تشغيل الوسائط. يستدعي المعالج طريقة getLicenseUrlForMedia تم تنفيذها في التطبيق للحصول على licenseUrl من contentId الخاص بالعنصر الحالي.

playerManager.setMediaPlaybackInfoHandler((loadRequestData, playbackConfig) => {
  const mediaInformation = loadRequestData.media;
  playbackConfig.licenseUrl = getLicenseUrlForMedia(mediaInformation.contentId);

  return playbackConfig;
});

أداة معالجة الأحداث

تتيح حزمة تطوير البرامج (SDK) الخاصة بـ "برنامج استقبال الويب" لتطبيق "برنامج استقبال الويب" معالجة أحداث المشغّل. تتلقّى أداة معالجة الأحداث مَعلمة cast.framework.events.EventType (أو مصفوفة من هذه المَعلمات) تحدّد الأحداث التي يجب أن تؤدي إلى تشغيل أداة المعالجة. يمكن العثور على مصفوفات مُعدّة مسبقًا من cast.framework.events.EventType ومفيدة في تصحيح الأخطاء في cast.framework.events.category. تقدّم مَعلمة الحدث معلومات إضافية عن الحدث.

على سبيل المثال، إذا أردت معرفة وقت بث تغيير mediaStatus، يمكنك استخدام المنطق التالي للتعامل مع الحدث:

const playerManager =
    cast.framework.CastReceiverContext.getInstance().getPlayerManager();
playerManager.addEventListener(
    cast.framework.events.EventType.MEDIA_STATUS, (event) => {
      // Write your own event handling code, for example
      // using the event.mediaStatus value
});

اعتراض الرسائل

تتيح حزمة تطوير البرامج (SDK) الخاصة بـ Web Receiver لتطبيق Web Receiver اعتراض الرسائل وتنفيذ رمز مخصّص على تلك الرسائل. يأخذ معترِض الرسائل cast.framework.messages.MessageType مَعلمة تحدّد نوع الرسالة التي يجب اعتراضها.

يجب أن يعرض المعترِض الطلب المعدَّل أو Promise يتم تنفيذه باستخدام قيمة الطلب المعدَّل. سيؤدي عرض null إلى منع استدعاء معالج الرسائل التلقائي. يمكنك الاطّلاع على تحميل الوسائط لمزيد من التفاصيل.

على سبيل المثال، إذا أردت تغيير بيانات طلب التحميل، يمكنك استخدام المنطق التالي لاعتراضها وتعديلها:

const context = cast.framework.CastReceiverContext.getInstance();
const playerManager = context.getPlayerManager();

playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.LOAD, loadRequestData => {
      const error = new cast.framework.messages.ErrorData(
                      cast.framework.messages.ErrorType.LOAD_FAILED);
      if (!loadRequestData.media) {
        error.reason = cast.framework.messages.ErrorReason.INVALID_PARAM;
        return error;
      }

      if (!loadRequestData.media.entity) {
        return loadRequestData;
      }

      return thirdparty.fetchAssetAndAuth(loadRequestData.media.entity,
                                          loadRequestData.credentials)
        .then(asset => {
          if (!asset) {
            throw cast.framework.messages.ErrorReason.INVALID_REQUEST;
          }

          loadRequestData.media.contentUrl = asset.url;
          loadRequestData.media.metadata = asset.metadata;
          loadRequestData.media.tracks = asset.tracks;
          return loadRequestData;
        }).catch(reason => {
          error.reason = reason; // cast.framework.messages.ErrorReason
          return error;
        });
    });

context.start();

معالجة الأخطاء

عند حدوث أخطاء في أداة اعتراض الرسائل، يجب أن يعرض تطبيق Web Receiver رمز cast.framework.messages.ErrorType وcast.framework.messages.ErrorReason المناسبَين.

playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.LOAD, loadRequestData => {
      const error = new cast.framework.messages.ErrorData(
                      cast.framework.messages.ErrorType.LOAD_CANCELLED);
      if (!loadRequestData.media) {
        error.reason = cast.framework.messages.ErrorReason.INVALID_PARAM;
        return error;
      }

      ...

      return fetchAssetAndAuth(loadRequestData.media.entity,
                               loadRequestData.credentials)
        .then(asset => {
          ...
          return loadRequestData;
        }).catch(reason => {
          error.reason = reason; // cast.framework.messages.ErrorReason
          return error;
        });
    });

اعتراض الرسائل مقابل أداة معالجة الأحداث

في ما يلي بعض الاختلافات الرئيسية بين اعتراض الرسائل ومعالج الأحداث:

  • لا يتيح لك معالج الأحداث تعديل بيانات الطلب.
  • من الأفضل استخدام أداة معالجة الأحداث لتفعيل الإحصاءات أو دالة مخصّصة.
playerManager.addEventListener(cast.framework.events.category.CORE,
    event => {
        console.log(event);
    });
  • يتيح لك اعتراض الرسائل الاستماع إلى رسالة واعتراضها وتعديل بيانات الطلب نفسها.
  • يُستخدَم اعتراض الرسائل بشكل أفضل للتعامل مع المنطق المخصّص فيما يتعلّق ببيانات الطلبات.

جارٍ تحميل الوسائط

توفّر السمة MediaInformation العديد من السمات لتحميل الوسائط في الرسالة cast.framework.messages.MessageType.LOAD، بما في ذلك entity وcontentUrl وcontentId.

  • entity هي السمة المقترَحة التي يجب استخدامها في عملية التنفيذ لكل من تطبيقات المرسِل والمستلِم. الموقع هو عنوان URL لصفحة معيّنة يمكن أن يكون إما قائمة تشغيل أو محتوى وسائط. يجب أن يحلّل تطبيقك عنوان URL هذا ويملأ حقلًا واحدًا على الأقل من الحقلَين الآخرَين.
  • يتوافق contentUrl مع عنوان URL القابل للتشغيل الذي سيستخدمه المشغّل لتحميل المحتوى. على سبيل المثال، يمكن أن يشير عنوان URL هذا إلى بيان DASH.
  • يمكن أن يكون contentId إما عنوان URL لمحتوى قابل للتشغيل (مشابه لعنوان URL الخاص بالسمة contentUrl ) أو معرّفًا فريدًا للمحتوى أو قائمة التشغيل التي يتم تحميلها. في حال استخدام هذه السمة كمعرّف، يجب أن يملأ تطبيقك عنوان URL قابلاً للتشغيل في contentUrl.

ننصحك باستخدام entity لتخزين رقم التعريف الحقيقي أو معلمات المفتاح، واستخدام contentUrl لعنوان URL الخاص بالوسائط. يظهر مثال على ذلك في المقتطف التالي حيث يكون entity متوفّرًا في طلب LOAD ويتم استرداد contentUrl القابل للتشغيل:

playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.LOAD, loadRequestData => {
      ...

      if (!loadRequestData.media.entity) {
        // Copy the value from contentId for legacy reasons if needed
        loadRequestData.media.entity = loadRequestData.media.contentId;
      }

      return thirdparty.fetchAssetAndAuth(loadRequestData.media.entity,
                                          loadRequestData.credentials)
        .then(asset => {
          loadRequestData.media.contentUrl = asset.url;
          ...
          return loadRequestData;
        });
    });

إمكانات الجهاز

توفّر طريقة getDeviceCapabilities معلومات الجهاز المتصل بجهاز Cast وجهاز الفيديو أو الصوت المتصل به. توفّر طريقة getDeviceCapabilities معلومات الدعم لـ "مساعد Google" والبلوتوث وأجهزة العرض والصوت المتصلة.

تعرض هذه الطريقة عنصرًا يمكنك طلب البحث فيه عن طريق تمرير أحد التعدادات المحددة للحصول على إمكانية الجهاز لهذا التعداد. يتم تحديد القيم المتعدّدة في cast.framework.system.DeviceCapabilities.

يتحقّق هذا المثال مما إذا كان جهاز Web Receiver قادرًا على تشغيل محتوى HDR وDolbyVision (DV) باستخدام المفتاحَين IS_HDR_SUPPORTED وIS_DV_SUPPORTED على التوالي.

const context = cast.framework.CastReceiverContext.getInstance();
context.addEventListener(cast.framework.system.EventType.READY, () => {
  const deviceCapabilities = context.getDeviceCapabilities();
  if (deviceCapabilities &&
      deviceCapabilities[cast.framework.system.DeviceCapabilities.IS_HDR_SUPPORTED]) {
    // Write your own event handling code, for example
    // using the deviceCapabilities[cast.framework.system.DeviceCapabilities.IS_HDR_SUPPORTED] value
  }
  if (deviceCapabilities &&
      deviceCapabilities[cast.framework.system.DeviceCapabilities.IS_DV_SUPPORTED]) {
    // Write your own event handling code, for example
    // using the deviceCapabilities[cast.framework.system.DeviceCapabilities.IS_DV_SUPPORTED] value
  }
});
context.start();

التعامل مع تفاعل المستخدم

يمكن للمستخدم التفاعل مع تطبيق Web Receiver من خلال تطبيقات المرسِل (الويب وAndroid وiOS) والأوامر الصوتية على الأجهزة المتوافقة مع "مساعد Google" وعناصر التحكّم باللمس على الشاشات الذكية وأجهزة التحكّم عن بُعد على أجهزة Android TV. توفّر حزمة تطوير البرامج (SDK) الخاصة بـ Cast واجهات برمجة تطبيقات متنوعة تتيح لتطبيق "المستقبِل على الويب" التعامل مع هذه التفاعلات وتعديل واجهة مستخدم التطبيق من خلال حالات إجراءات المستخدم، كما تتيح إرسال التغييرات بشكل اختياري لتعديل أي خدمات خلفية.

طلبات الوسائط المتوافقة

تستند حالات عناصر التحكّم في واجهة المستخدم إلى MediaStatus.supportedMediaCommands لأدوات التحكّم الموسّعة على أجهزة iOS وAndroid، وتطبيقات جهاز الاستقبال والتحكّم عن بُعد التي تعمل على الأجهزة التي تعمل باللمس، وتطبيقات جهاز الاستقبال على أجهزة Android TV. عند تفعيل Command معيّن على مستوى الموقع، يتم تفعيل الأزرار المرتبطة بهذا الإجراء. إذا لم يتم ضبط القيمة، سيتم إيقاف الزر. يمكن تغيير هذه القيم على "برنامج استقبال الويب" من خلال:

  1. استخدام PlayerManager.setSupportedMediaCommands لضبط Commands
  2. إضافة أمر جديد باستخدام addSupportedMediaCommands
  3. إزالة أمر حالي باستخدام removeSupportedMediaCommands
playerManager.setSupportedMediaCommands(cast.framework.messages.Command.SEEK |
  cast.framework.messages.Command.PAUSE);

عندما يجهّز المستلِم MediaStatus المعدَّل، سيتضمّن التغييرات في السمة supportedMediaCommands. عند بث الحالة، ستعدّل تطبيقات المرسِل المتصلة الأزرار في واجهة المستخدم الخاصة بها وفقًا لذلك.

لمزيد من المعلومات حول أوامر الوسائط وأجهزة اللمس المتوافقة، يُرجى الاطّلاع على Accessing UI controls الدليل.

إدارة حالات إجراءات المستخدم

عندما يتفاعل المستخدمون مع واجهة المستخدم أو يرسلون طلبات صوتية، يمكنهم التحكّم في تشغيل المحتوى والخصائص ذات الصلة بالعنصر الذي يتم تشغيله. تتعامل حزمة SDK تلقائيًا مع الطلبات التي تتحكّم في التشغيل. تتطلّب الطلبات التي تعدّل خصائص العنصر الحالي الذي يتم تشغيله، مثل الأمر LIKE، أن يتعامل تطبيق المتلقّي معها. توفّر حزمة SDK سلسلة من واجهات برمجة التطبيقات للتعامل مع هذه الأنواع من الطلبات. لإتاحة هذه الطلبات، يجب اتّخاذ الإجراءات التالية:

  • اضبط قيمة MediaInformation userActionStates باستخدام إعدادات المستخدم المفضّلة عند تحميل عنصر وسائط.
  • اعتراض الرسائل USER_ACTION وتحديد الإجراء المطلوب
  • عدِّل MediaInformation UserActionState لتعديل واجهة المستخدم.

يعترض المقتطف التالي طلب LOAD ويملأ MediaInformation الخاص بـ LoadRequestData. في هذه الحالة، يكون المستخدم معجبًا بالمحتوى الذي يتم تحميله.

playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.LOAD, (loadRequestData) => {
      const userActionLike = new cast.framework.messages.UserActionState(
          cast.framework.messages.UserAction.LIKE);
      loadRequestData.media.userActionStates = [userActionLike];

      return loadRequestData;
    });

يستقبل المقتطف التالي الرسالة USER_ACTION ويتعامل مع طلب تغيير الخلفية. ثم يجري مكالمة لتعديل UserActionState على جهاز الاستقبال.

playerManager.setMessageInterceptor(cast.framework.messages.MessageType.USER_ACTION,
  (userActionRequestData) => {
    // Obtain the media information of the current content to associate the action to.
    let mediaInfo = playerManager.getMediaInformation();

    // If there is no media info return an error and ignore the request.
    if (!mediaInfo) {
        console.error('Not playing media, user action is not supported');
        return new cast.framework.messages.ErrorData(messages.ErrorType.BAD_REQUEST);
    }

    // Reach out to backend services to store user action modifications. See sample below.
    return sendUserAction(userActionRequestData, mediaInfo)

    // Upon response from the backend, update the client's UserActionState.
    .then(backendResponse => updateUserActionStates(backendResponse))

    // If any errors occurred in the backend return them to the cast receiver.
    .catch((error) => {
      console.error(error);
      return error;
    });
});

تُحاكي المقتطفة التالية طلبًا إلى خدمة خلفية. تتحقّق الدالة من UserActionRequestData لمعرفة نوع التغيير الذي طلبه المستخدم، ولا تجري طلبًا من الشبكة إلا إذا كان الإجراء متوافقًا مع الخلفية.

function sendUserAction(userActionRequestData, mediaInfo) {
  return new Promise((resolve, reject) => {
    switch (userActionRequestData.userAction) {
      // Handle user action changes supported by the backend.
      case cast.framework.messages.UserAction.LIKE:
      case cast.framework.messages.UserAction.DISLIKE:
      case cast.framework.messages.UserAction.FOLLOW:
      case cast.framework.messages.UserAction.UNFOLLOW:
      case cast.framework.messages.UserAction.FLAG:
      case cast.framework.messages.UserAction.SKIP_AD:
        let backendResponse = {userActionRequestData: userActionRequestData, mediaInfo: mediaInfo};
        setTimeout(() => {resolve(backendResponse)}, 1000);
        break;
      // Reject all other user action changes.
      default:
        reject(
          new cast.framework.messages.ErrorData(cast.framework.messages.ErrorType.INVALID_REQUEST));
    }
  });
}

يأخذ المقتطف التالي UserActionRequestData ويضيف UserActionState أو يزيله من MediaInformation. يؤدي تعديل UserActionState في MediaInformation إلى تغيير حالة الزر المرتبط بالإجراء المطلوب. يظهر هذا التغيير في واجهة المستخدم الخاصة بعناصر التحكّم في الشاشة الذكية وتطبيق التحكّم عن بُعد وواجهة مستخدم Android TV. يتم أيضًا بثها من خلال رسائل MediaStatus الصادرة لتعديل واجهة المستخدم الخاصة بأداة التحكّم الموسّعة على أجهزة iOS وAndroid التي يتم الإرسال منها.

function updateUserActionStates(backendResponse) {
  // Unwrap the backend response.
  let mediaInfo = backendResponse.mediaInfo;
  let userActionRequestData = backendResponse.userActionRequestData;

  // If the current item playing has changed, don't update the UserActionState for the current item.
  if (playerManager.getMediaInformation().entity !== mediaInfo.entity) {
    return;
  }

  // Check for existing userActionStates in the MediaInformation.
  // If none, initialize a new array to populate states with.
  let userActionStates = mediaInfo.userActionStates || [];

  // Locate the index of the UserActionState that will be updated in the userActionStates array.
  let index = userActionStates.findIndex((currUserActionState) => {
    return currUserActionState.userAction == userActionRequestData.userAction;
  });

  if (userActionRequestData.clear) {
    // Remove the user action state from the array if cleared.
    if (index >= 0) {
      userActionStates.splice(index, 1);
    }
    else {
      console.warn("Could not find UserActionState to remove in MediaInformation");
    }
  } else {
    // Add the UserActionState to the array if enabled.
    userActionStates.push(
      new cast.framework.messages.UserActionState(userActionRequestData.userAction));
  }

  // Update the UserActionState array and set the new MediaInformation
  mediaInfo.userActionStates = userActionStates;
  playerManager.setMediaInformation(mediaInfo, true);
  return;
}

الطلبات الصوتية

تتوفّر أوامر الوسائط التالية حاليًا في Web Receiver SDK للأجهزة المتوافقة مع "مساعد Google". يمكن العثور على عمليات التنفيذ التلقائية لهذه الأوامر في cast.framework.PlayerManager.

Command الوصف
Play تشغيل الفيديو أو استئناف تشغيله من حالة الإيقاف المؤقت
إيقاف مؤقت إيقاف المحتوى الذي يتم تشغيله حاليًا مؤقتًا
السابق التخطّي إلى عنصر الوسائط السابق في قائمة انتظار الوسائط
التالي التخطّي إلى عنصر الوسائط التالي في قائمة وسائطك
إيقاف إيقاف الوسائط التي يتم تشغيلها حاليًا
عدم التكرار إيقاف تكرار عناصر الوسائط في قائمة المحتوى التالي بعد الانتهاء من تشغيل آخر عنصر في القائمة
تكرار أغنية واحدة تكرار الوسائط التي يتم تشغيلها حاليًا إلى أجل غير مسمى
تكرار الكل تكرار كل العناصر في قائمة الانتظار بعد تشغيل آخر عنصر فيها
تكرار الكل والترتيب العشوائي بعد الانتهاء من تشغيل آخر عنصر في قائمة المحتوى التالي، يتم ترتيب القائمة بشكل عشوائي وتكرار جميع العناصر فيها.
ترتيب عشوائي لتبديل ترتيب عناصر الوسائط في قائمة انتظار الوسائط
تفعيل / إيقاف ميزة "الترجمة والشرح" تفعيل أو إيقاف الترجمة والشرح للوسائط يمكن أيضًا تفعيل / إيقاف الميزة حسب اللغة.
التقديم/الترجيع إلى الوقت المطلق ينتقِل إلى الوقت المطلق المحدّد.
الانتقال إلى وقت نسبي مقارنةً بالوقت الحالي للانتقال إلى الأمام أو الخلف بمقدار الفترة الزمنية المحدّدة مقارنةً بوقت التشغيل الحالي
اللعب مرة أخرى إعادة تشغيل الوسائط المشغَّلة حاليًا أو تشغيل آخر عنصر وسائط تم تشغيله إذا لم يكن يتم تشغيل أي وسائط حاليًا
ضبط سرعة التشغيل تغيير سرعة تشغيل الوسائط يجب التعامل مع هذا الإجراء تلقائيًا. يمكنك استخدام أداة اعتراض الرسائل SET_PLAYBACK_RATE لتجاوز طلبات المعدّل الواردة.

طلبات الوسائط الصوتية المتوافقة

لمنع أمر صوتي من تشغيل أمر وسائط على جهاز مزوّد بخدمة "مساعد Google"، عليك أولاً ضبط أوامر الوسائط المتوافقة التي تريد إتاحتها. بعد ذلك، يجب فرض هذه الأوامر من خلال تفعيل السمة CastReceiverOptions.enforceSupportedCommands. ستتغيّر واجهة المستخدم على أجهزة الإرسال التي تستخدم Cast SDK والأجهزة التي تعمل باللمس لتعكس هذه الإعدادات. إذا لم يتم تفعيل العلامة، سيتم تنفيذ الطلبات الصوتية الواردة.

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

في المثال أدناه، نقدّم CastReceiverOptions عند بدء CastReceiverContext. أتحنا استخدام الأمر PAUSE، وألزمنا المشغّل بدعم هذا الأمر فقط. أما إذا طلب أمر صوتي إجراء عملية أخرى، مثل SEEK، فسيتم رفضه. سيتم إعلام المستخدم بأنّ الأمر غير متاح بعد.

const context = cast.framework.CastReceiverContext.getInstance();

context.start({
  enforceSupportedCommands: true,
  supportedCommands: cast.framework.messages.Command.PAUSE
});

يمكنك تطبيق منطق منفصل لكل أمر تريد حظره. أزِل العلامة enforceSupportedCommands، ويمكنك اعتراض الرسالة الواردة لكل أمر تريد حظره. في هذه المرحلة، نوقف الطلب الذي تقدّمه حزمة تطوير البرامج (SDK) لكي لا تؤدي أوامر SEEK الصادرة إلى الأجهزة المتوافقة مع "مساعد Google" إلى بدء البحث في تطبيق "برنامج استقبال الويب".

بالنسبة إلى أوامر الوسائط التي لا يدعمها تطبيقك، عليك عرض سبب خطأ مناسب، مثل NOT_SUPPORTED.

playerManager.setMessageInterceptor(cast.framework.messages.MessageType.SEEK,
  seekData => {
    // Block seeking if the SEEK supported media command is disabled
    if (!(playerManager.getSupportedMediaCommands() & cast.framework.messages.Command.SEEK)) {
      let e = new cast.framework.messages.ErrorData(cast.framework.messages.ErrorType
      .INVALID_REQUEST);
      e.reason = cast.framework.messages.ErrorReason.NOT_SUPPORTED;
      return e;
    }

    return seekData;
  });

الخروج من التطبيق من خلال النشاط الصوتي

إذا كانت منصة Cast تعمل على تشغيل صوت تطبيقك في الخلفية بسبب نشاط "مساعد Google"، مثل الاستماع إلى كلام المستخدم أو الرد عليه، يتم إرسال رسالة FocusState تتضمّن NOT_IN_FOCUS إلى تطبيق "برنامج استقبال الويب" عند بدء النشاط. يتم إرسال رسالة أخرى تتضمّن IN_FOCUS عند انتهاء النشاط. استنادًا إلى تطبيقك والوسائط التي يتم تشغيلها، قد تحتاج إلى إيقاف الوسائط مؤقتًا عندما يكون FocusState هو NOT_IN_FOCUS عن طريق اعتراض نوع الرسالة FOCUS_STATE.

على سبيل المثال، من المفيد إيقاف تشغيل الكتاب الصوتي مؤقتًا إذا كان "مساعد Google" يستجيب لطلب من المستخدم.

playerManager.setMessageInterceptor(cast.framework.messages.MessageType.FOCUS_STATE,
  focusStateRequestData => {
    // Pause content when the app is out of focus. Resume when focus is restored.
    if (focusStateRequestData.state == cast.framework.messages.FocusState.NOT_IN_FOCUS) {
      playerManager.pause();
    } else {
      playerManager.play();
    }

    return focusStateRequestData;
  });

لغة الترجمة والشرح المحدّدة صوتيًا

عندما لا يحدّد المستخدم اللغة التي يريد استخدامها في التسميات التوضيحية، تكون اللغة المستخدَمة هي اللغة نفسها التي تم التحدّث بها عند إدخال الأمر. في هذه السيناريوهات، تشير المَعلمة isSuggestedLanguage في الرسالة الواردة إلى ما إذا كان المستخدم قد اقترح اللغة المرتبطة أو طلبها بشكل صريح.

على سبيل المثال، تم ضبط isSuggestedLanguage على true للطلب "Ok Google، أريد تفعيل الترجمة والشرح"، لأنّ اللغة تم استنتاجها من اللغة التي تم التحدّث بها. إذا تم طلب اللغة بشكل صريح، مثلاً "Ok Google، فعِّل مقاطع الشرح باللغة الإنجليزية"، يتم ضبط isSuggestedLanguage على false.

البيانات الوصفية وبث الصوت

على الرغم من أنّ Web Receiver يتعامل مع الأوامر الصوتية تلقائيًا، عليك التأكّد من أنّ البيانات الوصفية الخاصة بالمحتوى كاملة ودقيقة. يضمن ذلك أن يتعامل "مساعد Google" مع الطلبات الصوتية بشكل سليم وأن تظهر البيانات الوصفية بشكل صحيح على أنواع جديدة من واجهات المستخدم، مثل تطبيق Google Home والشاشات الذكية، مثل Google Home Hub.

إعادة توجيه البث

يُعدّ الحفاظ على حالة الجلسة أساس عملية نقل البث، حيث يمكن للمستخدمين نقل عمليات بث الصوت والفيديو الحالية بين الأجهزة باستخدام الطلبات الصوتية أو تطبيق Google Home أو الشاشات الذكية. يتوقف تشغيل الوسائط على أحد الأجهزة (الجهاز المصدر) ويستمر على جهاز آخر (الجهاز الوجهة). يمكن لأي جهاز Cast مزوّد بأحدث البرامج الثابتة أن يكون مصدرًا أو وجهة لنقل البث.

في ما يلي تسلسل الأحداث لنقل البث:

  1. على الجهاز المصدر:
    1. يتوقف تشغيل الوسائط.
    2. يتلقّى تطبيق Web Receiver أمرًا لحفظ حالة الوسائط الحالية.
    3. تم إيقاف تطبيق Web Receiver.
  2. على الجهاز الوجهة، اتّبِع الخطوات التالية:
    1. يتم تحميل تطبيق Web Receiver.
    2. يتلقّى تطبيق Web Receiver أمرًا لاستعادة حالة الوسائط المحفوظة.
    3. يتم استئناف تشغيل الوسائط.

تشمل عناصر حالة الوسائط ما يلي:

  • الموضع أو الطابع الزمني المحدّد للأغنية أو الفيديو أو عنصر الوسائط
  • موضعه في قائمة انتظار أوسع (مثل قائمة تشغيل أو راديو الفنان)
  • المستخدم الذي تمّت مصادقته
  • حالة التشغيل (على سبيل المثال، قيد التشغيل أو متوقف مؤقتًا)

تفعيل ميزة إعادة توجيه البث

لتنفيذ ميزة "نقل البث" في تطبيق Web Receiver، اتّبِع الخطوات التالية:

  1. عدِّل supportedMediaCommands باستخدام الأمر STREAM_TRANSFER:
    playerManager.addSupportedMediaCommands(
    cast.framework.messages.Command.STREAM_TRANSFER, true);
  2. يمكنك اختياريًا إلغاء معترِضَي الرسائل SESSION_STATE وRESUME_SESSION كما هو موضّح في الحفاظ على حالة الجلسة. لا تتجاوز هذه القيم إلا إذا كانت هناك حاجة إلى تخزين بيانات مخصّصة كجزء من لقطة الجلسة. وفي الحالات الأخرى، سيتيح التنفيذ التلقائي للحفاظ على حالات الجلسات نقل البث.

الحفاظ على حالة الجلسة

توفّر حزمة تطوير البرامج Web Receiver SDK عملية تنفيذ تلقائية لتطبيقات Web Receiver من أجل الحفاظ على حالات الجلسة من خلال أخذ لقطة لحالة الوسائط الحالية وتحويل الحالة إلى طلب تحميل واستئناف الجلسة باستخدام طلب التحميل.

يمكن تجاهل طلب التحميل الذي تم إنشاؤه بواسطة Web Receiver في أداة اعتراض الرسائل SESSION_STATE إذا لزم الأمر. إذا أردت إضافة بيانات مخصّصة إلى طلب التحميل، ننصحك بوضعها في loadRequestData.customData.

playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.SESSION_STATE,
    function (sessionState) {
        // Override sessionState.loadRequestData if needed.
        const newCredentials = updateCredentials_(sessionState.loadRequestData.credentials);
        sessionState.loadRequestData.credentials = newCredentials;

        // Add custom data if needed.
        sessionState.loadRequestData.customData = {
            'membership': 'PREMIUM'
        };

        return sessionState;
    });

يمكن استرداد البيانات المخصّصة من loadRequestData.customData في أداة اعتراض الرسائل RESUME_SESSION.

let cred_ = null;
let membership_ = null;

playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.RESUME_SESSION,
    function (resumeSessionRequest) {
        let sessionState = resumeSessionRequest.sessionState;

        // Modify sessionState.loadRequestData if needed.
        cred_ = sessionState.loadRequestData.credentials;

        // Retrieve custom data.
        membership_ = sessionState.loadRequestData.customData.membership;

        return resumeSessionRequest;
    });

التحميل المُسبَق للمحتوى

يتيح Web Receiver التحميل المُسبَق لعناصر الوسائط بعد عنصر التشغيل الحالي في قائمة الانتظار.

تنزّل عملية التحميل المُسبَق عدة مقاطع من العناصر القادمة. يتم تحديد المدة في قيمة preloadTime في عنصر QueueItem (يتم ضبطها تلقائيًا على 20 ثانية في حال عدم توفيرها). يتم التعبير عن الوقت بالثواني، بالنسبة إلى نهاية العنصر الذي يتم تشغيله حاليًا . القيم الموجبة فقط هي القيم الصالحة. على سبيل المثال، إذا كانت القيمة 10 ثوانٍ، سيتم التحميل المسبق لهذا العنصر قبل 10 ثوانٍ من انتهاء العنصر السابق. إذا كان وقت التحميل المُسبَق أكبر من الوقت المتبقي في currentItem، سيتم التحميل المُسبَق في أقرب وقت ممكن. لذلك، إذا تم تحديد قيمة كبيرة جدًا للتحميل المُسبَق في queueItem، يمكن تحقيق تأثير تحميل العنصر التالي مُسبقًا في كل مرة يتم فيها تشغيل العنصر الحالي. ومع ذلك، نترك للمطوّر تحديد هذا الإعداد واختياره، لأنّ هذه القيمة يمكن أن تؤثر في معدل نقل البيانات وأداء البث للعنصر الذي يتم تشغيله حاليًا.

سيعمل التحميل المُسبق مع محتوى HLS وDASH وSmooth Streaming تلقائيًا.

لن يتم التحميل المسبق لملفات الفيديو والصوت العادية بتنسيق MP4، مثل ملفات MP3، لأنّ أجهزة Cast لا تتوافق إلا مع عنصر وسائط واحد ولا يمكن استخدامها للتحميل المسبق أثناء تشغيل عنصر محتوى حالي.

رسائل مخصّصة

تبادل الرسائل هو طريقة التفاعل الرئيسية لتطبيقات Web Receiver.

يرسل جهاز الإرسال رسائل إلى Web Receiver باستخدام واجهات برمجة تطبيقات جهاز الإرسال الخاصة بالنظام الأساسي الذي يعمل عليه (Android أو iOS أو الويب). يحتوي عنصر الحدث (الذي يمثّل الرسالة) الذي يتم تمريره إلى أدوات معالجة الأحداث على عنصر بيانات (event.data) تتخذ فيه البيانات خصائص نوع الحدث المحدّد.

يمكن لتطبيق Web Receiver اختيار الاستماع إلى الرسائل في مساحة اسم محدّدة. وبذلك، يُقال إنّ تطبيق "برنامج استقبال الويب" يتوافق مع بروتوكول مساحة الاسم هذا. ويعود الأمر بعد ذلك إلى أي مرسِلين متصلين يريدون التواصل في مساحة الاسم هذه لاستخدام البروتوكول المناسب.

يتم تحديد جميع مساحات الأسماء بواسطة سلسلة ويجب أن تبدأ بـ "urn:x-cast:" متبوعةً بأي سلسلة. على سبيل المثال، "urn:x-cast:com.example.cast.mynamespace".

في ما يلي مقتطف رمز برمجي لجهاز استقبال الويب للاستماع إلى الرسائل المخصّصة من أجهزة الإرسال المرتبطة:

const context = cast.framework.CastReceiverContext.getInstance();

const CUSTOM_CHANNEL = 'urn:x-cast:com.example.cast.mynamespace';
context.addCustomMessageListener(CUSTOM_CHANNEL, function(customEvent) {
  // handle customEvent.
});

context.start();

وبالمثل، يمكن لتطبيقات Web Receiver إبقاء المُرسِلين على علم بحالة Web Receiver من خلال إرسال رسائل إلى المُرسِلين المتصلين. يمكن لتطبيق Web Receiver إرسال رسائل باستخدام sendCustomMessage(namespace, senderId, message) على CastReceiverContext. يمكن لجهاز استقبال الويب إرسال رسائل إلى مُرسِل فردي، إما ردًا على رسالة تم تلقّيها أو بسبب تغيير في حالة التطبيق. بالإضافة إلى المراسلة من نقطة إلى نقطة (بحد أقصى 64 كيلوبايت)، يمكن أن يبث "برنامج استقبال الويب" الرسائل إلى جميع أجهزة الإرسال المتصلة.

البث على الأجهزة الصوتية

يمكنك الاطّلاع على دليل Google Cast لأجهزة الصوت للحصول على الدعم بشأن تشغيل الصوت فقط.

Android TV

يناقش هذا القسم كيفية استخدام Google Web Receiver لإدخالاتك كتشغيل، بالإضافة إلى توافق Android TV.

دمج تطبيقك مع جهاز التحكّم عن بُعد

يُترجم Google Web Receiver الذي يعمل على جهاز Android TV الإدخال من عناصر التحكّم في الجهاز (أي وحدة التحكّم عن بُعد المحمولة باليد) كرسائل تشغيل الوسائط المحدّدة لمساحة الاسم urn:x-cast:com.google.cast.media، كما هو موضّح في رسائل تشغيل الوسائط. يجب أن يدعم تطبيقك هذه الرسائل للتحكّم في تشغيل الوسائط في التطبيق، وذلك للسماح بالتحكّم الأساسي في التشغيل من خلال عناصر التحكّم في Android TV.

إرشادات التوافق مع Android TV

في ما يلي بعض الاقتراحات والأخطاء الشائعة التي يجب تجنُّبها لضمان توافق تطبيقك مع Android TV:

  • يُرجى العِلم أنّ سلسلة وكيل المستخدم تتضمّن كلاً من "Android" و "CrKey"، وقد تعيد بعض المواقع الإلكترونية التوجيه إلى موقع إلكتروني مخصّص للأجهزة الجوّالة فقط لأنّها ترصد التصنيف "Android". لا تفترض أنّ كلمة "Android" في سلسلة وكيل المستخدم تشير دائمًا إلى مستخدم جهاز جوّال.
  • قد تستخدم حزمة الوسائط في Android تنسيق GZIP الشفاف لجلب البيانات. تأكَّد من أنّ بيانات الوسائط يمكنها الاستجابة إلى Accept-Encoding: gzip.
  • قد يتم تشغيل أحداث وسائط HTML5 على Android TV في أوقات مختلفة عن Chromecast، ما قد يكشف عن مشاكل لم تكن ظاهرة على Chromecast.
  • عند تعديل الوسائط، استخدِم الأحداث ذات الصلة بالوسائط التي يتم تشغيلها بواسطة عناصر <audio>/<video> ، مثل timeupdate وpause وwaiting. تجنَّب استخدام الأحداث ذات الصلة بالشبكات، مثل progress وsuspend وstalled، لأنّها غالبًا ما تكون مرتبطة بنظام التشغيل. اطّلِع على أحداث الوسائط لمزيد من المعلومات حول معالجة أحداث الوسائط في جهاز الاستقبال.
  • عند ضبط شهادات HTTPS الخاصة بموقعك الإلكتروني المستلِم، احرص على تضمين شهادات مرجع تصديق وسيطة. راجِع صفحة اختبار Qualsys SSL للتأكّد مما يلي: إذا كان مسار الشهادة الموثوق به لموقعك الإلكتروني يتضمّن شهادة هيئة إصدار شهادات تحمل التصنيف "تنزيل إضافي"، قد لا يتم تحميلها على المنصات المستندة إلى Android.
  • بينما يعرض Chromecast صفحة جهاز الاستقبال على مستوى رسومات بدقة 720p، قد تعرض منصات البث الأخرى، بما في ذلك Android TV، الصفحة بدقة تصل إلى 1080p. تأكَّد من أنّ صفحة جهاز الاستقبال تتكيّف بشكل جيد مع درجات الدقة المختلفة.