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

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

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

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

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

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

يوضّح المثال أدناه كيفية إلغاء السلوك التلقائي لرصد ما إذا كان اتصال المُرسِل لا يزال متصلاً بشكل نشط. عندما يتعذّر على "مستلِم الويب" التواصل مع مُرسِل مدّة 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);

ضبط المشغّل

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

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

يوضِّح المثال أدناه كيفية ضبط PlaybackConfig عند بدء استخدام CastReceiverContext. تلغي الإعدادات الطلبات الصادرة للحصول على بيانات البيان. يحدِّد المعالِج أنّه يجب إرسال طلبات التحكّم في الوصول باستخدام بروتوكول CORS باستخدام بيانات اعتماد مثل ملفات تعريف الارتباط أو عناوين التفويض.

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

يوضّح المثال أدناه كيفية إلغاء PlaybackConfig باستخدام أسلوبَي الالتقاط والضبط المقدَّمَين في 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) لتطبيق Web Receiver بمعالجة أحداث المشغّل. يستخدِم مستمع الحدث مَعلمة 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 باعتراض الرسائل و تنفيذ رمز مخصّص على هذه الرسائل. يأخذ معرّف اعتراض الرسائل مَعلمة cast.framework.messages.MessageType تحدد نوع الرسالة التي يجب اعتراضها.

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

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

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 معلومات عن الجهاز على جهاز البث المتصل وجهاز الفيديو أو الصوت المرتبط به. تقدّم طريقة 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();

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

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

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

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

  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 سلسلة من واجهتَي برمجة التطبيقات (API) لمعالجة هذه الأنواع من الطلبات. لدعم هذه الطلبات، يجب تنفيذ ما يلي:

  • اضبط 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;
}

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

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

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

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

لمنع طلب صوتي من تشغيل طلب وسائط على جهاز مزوّد بتطبيق "مساعد Google"، يجب أولاً ضبط طلبات الوسائط المتوافقة التي تريد توفيرها. بعد ذلك، عليك فرض هذه الأوامر من خلال تفعيل CastReceiverOptions.enforceSupportedCommands. سيتغيّر واجهة المستخدم في أجهزة إرسال حزمة تطوير البرامج (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" إلى تشغيل ميزة التقديم أو الإيقاف في تطبيق Web Receiver.

بالنسبة إلى أوامر الوسائط التي لا يتوافق معها تطبيقك، يجب عرض سبب خطأ مناسب، مثل 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"، مثل الاستماع إلى نطق المستخدم أو الردّ عليه، يتم إرسال رسالة NOT_IN_FOCUS FocusState إلى تطبيق Web Receiver عند بدء النشاط. يتم إرسال رسالة أخرى تتضمّن 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، أريد تفعيل الشرح"، لأنّه تم استنتاج اللغة من اللغة التي تم بها قول العبارة. إذا تم طلب اللغة صراحةً، مثل "حسنًا، ‫Google، أريد تفعيل مقاطع الترجمة والشرح باللغة الإنجليزية"، يتم ضبط isSuggestedLanguage على false.

البيانات الوصفية وميزة "البث الصوتي"

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

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

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

تتمثل عملية نقل البث في ما يلي:

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

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

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

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

لتنفيذ عملية نقل البث لجهاز "مُستلِم الويب"، اتّبِع الخطوات التالية:

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

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

توفّر حزمة تطوير البرامج (SDK) لبرنامج Web Receiver عملية تنفيذ تلقائية لتطبيقات 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، سيتم التحميل المُسبَق على الفور قدر الإمكان. وبالتالي، إذا تم تحديد قيمة كبيرة جدًا لمقياس التحميل المُسبَق في عنصر "قائمة المحتوى التالي"، يمكن أن يؤدي ذلك إلى بدء تحميل المحتوى التالي أثناء تشغيل المحتوى الحالي. ومع ذلك، نترك عملية ضبط هذه القيمة واختيارها للمطوّر لأنّ هذه القيمة يمكن أن تؤثّر في معدل نقل البيانات وأداء البث المباشر للمادة التي يتم تشغيلها حاليًا.

سيتم تفعيل ميزة "التحميل المُسبَق" تلقائيًا لمحتوى HLS وDASH و"البث السلس".

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

الرسائل المخصّصة

يشكّل تبادل الرسائل طريقة التفاعل الرئيسية لتطبيقات Web Receiver.

يُرسِل المُرسِل الرسائل إلى "مستقبل الويب" باستخدام واجهات برمجة تطبيقات المُرسِل لنظام التشغيل الذي يستخدمه المُرسِل (Android أو iOS أو الويب). يحتوي كائن الحدث (الذي يمثّل رسالة) الذي يتم تمريره إلى مستمعي الأحداث على عنصر data (event.data) حيث تأخذ البيانات سمات نوع الحدث المحدّد.

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

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

في ما يلي مقتطف رمز لتطبيق Web Receiver للاستماع إلى الرسائل المخصّصة من المُرسِلين المتصلين:

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. يمكن لمستقبل الويب إرسال الرسائل إلى مُرسِل فردي، إما استجابةً لرسالة تم استلامها أو بسبب تغيير في حالة التطبيق. بالإضافة إلى المراسلة من نقطة إلى نقطة، يمكن لجهاز "مستلِم الويب" أيضًا بث الرسائل إلى كل المُرسِلين المتصلين.

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

يُرجى الاطّلاع على دليل 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 للتأكّد مما يلي: إذا كان مسار الشهادة الموثوق به لموقعك الإلكتروني يتضمّن شهادة CA مصنّفة على أنّها "تنزيل إضافي"، قد لا يتم تحميلها على منصّات Android المتوافقة.
  • في حين أنّ جهاز Chromecast يعرض صفحة جهاز الاستقبال على مستوى رسومات بدقة 720p، قد تعرض منصات Cast الأخرى، بما في ذلك Android TV، الصفحة بدقة تصل إلى 1080p. تأكَّد من أنّ صفحة المستلِم تتمكّن من التأقلم بسلاسة مع درجات الدقة المختلفة.