يوضح لك هذا الدليل كيفية إنشاء تطبيق مرسل يعمل بنظام التشغيل Android ويعمل بتكنولوجيا Google Cast من خلال توجيهك من خلال نموذج تطبيق.
لمتابعة هذا الدليل، يمكنك تنزيل AdvancedExample.zip، وهو تطبيق كامل من Android ينفّذ وظيفة الإرسال لمقاطع الفيديو التي تحتوي على إعلانات باستخدام حزمة IMA Android SDK.
المتطلبات الأساسية
ويستند هذا الدليل إلى المعرفة الحالية لأداة Google Cast SDK وIMA SDK لنظام التشغيل Android. ويجب على المستخدمين التعرف على ما يلي:
يناقش هذا الدليل الإعداد المحدد المستخدم في المثال المتقدم للتواصل مع المتلقي. ولا تغطي شفرة إعداد Cast القياسية أو تشغيل إعلانات الوسائط التفاعلية العادية. لمزيد من التفاصيل حول تنفيذ جهاز الاستقبال، يُرجى مراجعة دليل استقبال HTML5.
مشغّل الوسائط
ويتم تنفيذ وظيفة تحميل الوسائط على جهاز الاستقبال في CastApplication.java، إلى جانب معظم الرموز المتعلقة بالإرسال. الوسائط التي يحاول تحميلها هي عنوان URL للمحتوى، ثم تُرسل رسالة مخصّصة إلى المُستلِم تطلب منه طلب الإعلانات باستخدام علامة الإعلان نفسها والبحث عن الطابع الزمني الحالي للمُرسِل.
CastApplication.java
private void createMediaPlayer() {
Log.d(TAG, "making media player");
// Create a Remote Media Player
mRemoteMediaPlayer = new RemoteMediaPlayer();
mRemoteMediaPlayer.setOnStatusUpdatedListener(
new RemoteMediaPlayer.OnStatusUpdatedListener() {
@Override
public void onStatusUpdated() {
MediaStatus mediaStatus = mRemoteMediaPlayer.getMediaStatus();
Log.d(TAG, "Media status: " + mediaStatus);
}
});
mRemoteMediaPlayer.setOnMetadataUpdatedListener(
new RemoteMediaPlayer.OnMetadataUpdatedListener() {
@Override
public void onMetadataUpdated() {
MediaInfo mediaInfo = mRemoteMediaPlayer.getMediaInfo();
Log.d(TAG, "Media info: " + mediaInfo);
}
});
try {
Cast.CastApi.setMessageReceivedCallbacks(sApiClient,
mRemoteMediaPlayer.getNamespace(), mRemoteMediaPlayer);
} catch (IOException e) {
Log.e(TAG, "Exception while creating media channel", e);
}
mRemoteMediaPlayer
.requestStatus(sApiClient)
.setResultCallback(
new ResultCallback<RemoteMediaPlayer.MediaChannelResult>() {
@Override
public void onResult(RemoteMediaPlayer.MediaChannelResult result) {
if (!result.getStatus().isSuccess()) {
Log.e(TAG, "Failed to request status.");
} else {
MediaMetadata mediaMetadata =
new MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE);
mediaMetadata.putString(MediaMetadata.KEY_TITLE, "My video");
MediaInfo mediaInfo = new MediaInfo.Builder(mContentUrl)
.setContentType("video/mp4")
.setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
.setMetadata(mediaMetadata)
.build();
loadMedia(mediaInfo, false);
}
}
});
}
private void loadMedia(MediaInfo mediaInfo, Boolean autoplay) {
try {
Log.d(TAG, "loading media");
mRemoteMediaPlayer.load(sApiClient, mediaInfo, autoplay)
.setResultCallback(new ResultCallback<RemoteMediaPlayer.MediaChannelResult>() {
@Override
public void onResult(RemoteMediaPlayer.MediaChannelResult result) {
if (result.getStatus().isSuccess()) {
boolean adStarted = mVideoPlayerController.hasAdStarted();
if (mVideoFragment.isVmap() || !adStarted) {
sendMessage("requestAd," + mAdTagUrl + ","
+ mVideoPlayerController.getCurrentContentTime());
} else {
sendMessage("seek,"
+ mVideoPlayerController.getCurrentContentTime());
}
} else {
Log.e(TAG, "Error loading Media : "
+ result.getStatus().getStatusCode());
}
}
});
} catch (Exception e) {
Log.e(TAG, "Problem opening media during loading", e);
}
}
private void sendMessage(String message) {
if (sApiClient != null && incomingMsgHandler != null) {
try {
Log.d(TAG, "Sending message: " + message);
Cast.CastApi.sendMessage(sApiClient, NAMESPACE, message)
.setResultCallback(new ResultCallback<Status>() {
@Override
public void onResult(Status result) {
if (!result.isSuccess()) {
Log.e(TAG, "Sending message failed");
}
}
});
} catch (Exception e) {
Log.e(TAG, "Exception while sending message", e);
}
}
}
تم تحديد رسالتين في استدعاء onResult
: seek
لاستئناف التشغيل على جهاز الاستقبال دون إعلانات والرسالة requestAd
التي تعيد طلب علامة الإعلان نفسها على جهاز الاستقبال. يتم استخدام الرسالة requestAd
لقوائم التشغيل الإعلانية وقائمة تشغيل إعلانات الفيديو (VMAP) في هذا المثال، ولكن يمكنك تحديد سلوكك الخاص بما يجب أن يحدث عند إرسال المحتوى. يتم الفصل بين هذه الرسائل بفواصل، حيث تكون المعلمة الأولى هي اسم الرسالة، وتكون المعلمات المتبقية هي علامة الإعلان ووقت البحث.
معاودة الاتصال بـ MediaRouter
يتعامل MediaRouter.Callback
مع بدء البث وإيقافه بالإضافة إلى التحكم في تبديل تشغيل الفيديو بين Android وأجهزة البث. يتضمن هذا إيقاف الفيديو مؤقتًا والبحث عنه.
CastApplication.java
private final MediaRouter.Callback mediaRouterCallback = new MediaRouter.Callback() {
@Override
public void onRouteSelected(MediaRouter router, MediaRouter.RouteInfo info) {
// User starts casting. Pause video on device and set Google Cast device.
mVideoPlayerController = mVideoFragment.getVideoPlayerController();
mVideoPlayerController.pause();
mAdTagUrl = mVideoPlayerController.getAdTagUrl();
mContentUrl = mVideoPlayerController.getContentVideoUrl();
CastDevice device = CastDevice.getFromBundle(info.getExtras());
setSelectedDevice(device);
}
@Override
public void onRouteUnselected(MediaRouter router, MediaRouter.RouteInfo info) {
// User stops casting. Resume video on device and seek to current time of Google Cast.
mVideoPlayerController.resume();
if (mCastAdPlaying) {
mVideoPlayerController.seek(mCastContentTime);
} else {
double videoPosition = mRemoteMediaPlayer.getApproximateStreamPosition();
mVideoPlayerController.seek(videoPosition / 1000.0);
}
stopCastApplication();
setSelectedDevice(null);
}
};
الرسائل
يحدّد التطبيق MessageReceivedCallback
للسماح للمُستلِم بإرسال إشعارات حول الوقت المحدّد من فيديو يتم فيه إرسال البث وعندما يبدأ الإعلان الذي تم إرساله ثم يبدأ المحتوى. ويتم إرسال هذه الرسائل من قِبل
المستلم ويتم التعامل معها من خلال رسالتين، onContentPauseRequested
وonContentResumeRequested
.
ويتم الفصل بين هذه الرسائل بفواصل وبتنسيق مشابه للرسائل seek
وrequestAd
الموضحة أعلاه.
CastApplication.java
public final Cast.MessageReceivedCallback incomingMsgHandler =
new Cast.MessageReceivedCallback() {
@Override
public void onMessageReceived(CastDevice castDevice, String namespace,
String message) {
Log.d(TAG, "Receiving message: " + message);
String[] splitMessage = message.split(",");
String event = splitMessage[0];
switch (event) {
case "onContentPauseRequested":
mCastAdPlaying = true;
mCastContentTime = Double.parseDouble(splitMessage[1]);
return;
case "onContentResumeRequested":
mCastAdPlaying = false;
return;
}
}
};
الخطوات التالية
في هذه المرحلة، تكون على دراية جيدة بكيفية تفاعل تطبيق مرسل Android مع جهاز الاستقبال. لتجربتها، أنشئ تطبيق مستلِم وسجِّل المُستلِم لتلقي مُعرِّف التطبيق الذي يتم استخدامه مع طلبات البيانات من واجهة برمجة التطبيقات من تطبيق المُرسِل.