लाइव टीवी देखते समय, उपयोगकर्ता चैनल बदलता है और उसे चैनल और प्रोग्राम की जानकारी गायब होने से पहले, उसे कुछ समय के लिए मिटा दिया जाता है. दूसरी तरह की जानकारी, जैसे कि मैसेज ("घर पर कोई काम न करें"), सबटाइटल या विज्ञापनों को लगातार जारी रखना पड़ सकता है. किसी भी टीवी की तरह ऐप्लिकेशन न हो, तो इस तरह की जानकारी से स्क्रीन पर प्रोग्राम के कॉन्टेंट में कोई रुकावट नहीं आनी चाहिए.
यह भी देखें कि प्रोग्राम का कुछ कॉन्टेंट दिखाया जाना चाहिए या नहीं, क्योंकि कॉन्टेंट की रेटिंग और माता-पिता के कंट्रोल वाली सेटिंग की जानकारी. साथ ही, यह जानकारी कि आपका ऐप्लिकेशन कैसे काम करता है. कॉन्टेंट ब्लॉक किया गया है या उपलब्ध नहीं है. इस लेसन में बताया गया है कि अपने टीवी इनपुट के उपयोगकर्ता को कैसे डेवलप करें के बारे में हमारा सुझाव है.
आज़माएं टीवी इनपुट सेवा का नमूना.
प्लेयर को प्लैटफ़ॉर्म के साथ इंटिग्रेट करें
आपके टीवी इनपुट को वीडियो को Surface
ऑब्जेक्ट पर रेंडर करना होगा, जिसे पास किया जाएगा
TvInputService.Session.onSetSurface()
तरीका. यहां एक उदाहरण दिया गया है. इसमें, गेम खेलने के लिए MediaPlayer
इंस्टेंस इस्तेमाल करने का तरीका बताया गया है
Surface
ऑब्जेक्ट में कॉन्टेंट:
Kotlin
override fun onSetSurface(surface: Surface?): Boolean { player?.setSurface(surface) mSurface = surface return true } override fun onSetStreamVolume(volume: Float) { player?.setVolume(volume, volume) mVolume = volume }
Java
@Override public boolean onSetSurface(Surface surface) { if (player != null) { player.setSurface(surface); } mSurface = surface; return true; } @Override public void onSetStreamVolume(float volume) { if (player != null) { player.setVolume(volume, volume); } mVolume = volume; }
इसी तरह, का इस्तेमाल करके ऐसा करने का तरीका यहां बताया गया है ExoPlayer:
Kotlin
override fun onSetSurface(surface: Surface?): Boolean { player?.createMessage(videoRenderer)?.apply { type = MSG_SET_SURFACE payload = surface send() } mSurface = surface return true } override fun onSetStreamVolume(volume: Float) { player?.createMessage(audioRenderer)?.apply { type = MSG_SET_VOLUME payload = volume send() } mVolume = volume }
Java
@Override public boolean onSetSurface(@Nullable Surface surface) { if (player != null) { player.createMessage(videoRenderer) .setType(MSG_SET_SURFACE) .setPayload(surface) .send(); } mSurface = surface; return true; } @Override public void onSetStreamVolume(float volume) { if (player != null) { player.createMessage(videoRenderer) .setType(MSG_SET_VOLUME) .setPayload(volume) .send(); } mVolume = volume; }
ओवरले का इस्तेमाल करना
सबटाइटल, मैसेज, विज्ञापन या MHEG-5 डेटा ब्रॉडकास्ट दिखाने के लिए ओवरले का इस्तेमाल करें. डिफ़ॉल्ट रूप से,
ओवरले बंद है. सेशन बनाते समय, कॉल करके इसे चालू किया जा सकता है
TvInputService.Session.setOverlayViewEnabled(true)
,
जैसा कि नीचे दिए गए उदाहरण में बताया गया है:
Kotlin
override fun onCreateSession(inputId: String): Session = onCreateSessionInternal(inputId).apply { setOverlayViewEnabled(true) sessions.add(this) }
Java
@Override public final Session onCreateSession(String inputId) { BaseTvInputSessionImpl session = onCreateSessionInternal(inputId); session.setOverlayViewEnabled(true); sessions.add(session); return session; }
ओवरले के लिए View
ऑब्जेक्ट का इस्तेमाल करें, जो TvInputService.Session.onCreateOverlayView()
से मिला है, जैसा कि यहां दिखाया गया है:
Kotlin
override fun onCreateOverlayView(): View = (context.getSystemService(LAYOUT_INFLATER_SERVICE) as LayoutInflater).run { inflate(R.layout.overlayview, null).apply { subtitleView = findViewById<SubtitleView>(R.id.subtitles).apply { // Configure the subtitle view. val captionStyle: CaptionStyleCompat = CaptionStyleCompat.createFromCaptionStyle(captioningManager.userStyle) setStyle(captionStyle) setFractionalTextSize(captioningManager.fontScale) } } }
Java
@Override public View onCreateOverlayView() { LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE); View view = inflater.inflate(R.layout.overlayview, null); subtitleView = (SubtitleView) view.findViewById(R.id.subtitles); // Configure the subtitle view. CaptionStyleCompat captionStyle; captionStyle = CaptionStyleCompat.createFromCaptionStyle( captioningManager.getUserStyle()); subtitleView.setStyle(captionStyle); subtitleView.setFractionalTextSize(captioningManager.fontScale); return view; }
ओवरले की लेआउट परिभाषा कुछ ऐसी दिखाई दे सकती है:
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <com.google.android.exoplayer.text.SubtitleView android:id="@+id/subtitles" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|center_horizontal" android:layout_marginLeft="16dp" android:layout_marginRight="16dp" android:layout_marginBottom="32dp" android:visibility="invisible"/> </FrameLayout>
कॉन्टेंट को कंट्रोल करें
जब उपयोगकर्ता किसी चैनल को चुनता है, तो आपका टीवी इनपुट, TvInputService.Session
ऑब्जेक्ट में onTune()
कॉलबैक को हैंडल करता है. सिस्टम टीवी
ऐप्लिकेशन की 'माता-पिता का कंट्रोल' सुविधा से यह तय किया जाता है कि कॉन्टेंट रेटिंग के हिसाब से कौनसा कॉन्टेंट दिखाया जाए.
यहां दिए गए सेक्शन में बताया गया है कि
TvInputService.Session
notify
तरीके
सिस्टम टीवी ऐप्लिकेशन से बातचीत कर सकते हैं.
वीडियो को उपलब्ध न कराएं
जब उपयोगकर्ता चैनल बदलता है, तो आपको यह पक्का करना होगा कि स्क्रीन पर कोई आगाह न हो
वीडियो आर्टफ़ैक्ट को डाउनलोड करें. TvInputService.Session.onTune()
को कॉल करने पर,
वीडियो को प्रज़ेंट होने से रोका जा सकता है. इसके लिए, TvInputService.Session.notifyVideoUnavailable()
पर कॉल करें
और VIDEO_UNAVAILABLE_REASON_TUNING
स्थिरांक को पास करना, जैसे कि
नीचे दिए गए उदाहरण में दिखाया गया है.
Kotlin
override fun onTune(channelUri: Uri): Boolean { subtitleView?.visibility = View.INVISIBLE notifyVideoUnavailable(TvInputManager.VIDEO_UNAVAILABLE_REASON_TUNING) unblockedRatingSet.clear() dbHandler.apply { removeCallbacks(playCurrentProgramRunnable) playCurrentProgramRunnable = PlayCurrentProgramRunnable(channelUri) post(playCurrentProgramRunnable) } return true }
Java
@Override public boolean onTune(Uri channelUri) { if (subtitleView != null) { subtitleView.setVisibility(View.INVISIBLE); } notifyVideoUnavailable(TvInputManager.VIDEO_UNAVAILABLE_REASON_TUNING); unblockedRatingSet.clear(); dbHandler.removeCallbacks(playCurrentProgramRunnable); playCurrentProgramRunnable = new PlayCurrentProgramRunnable(channelUri); dbHandler.post(playCurrentProgramRunnable); return true; }
इसके बाद, जब Surface
में कॉन्टेंट रेंडर किया जाता है, तो आपको
TvInputService.Session.notifyVideoAvailable()
वीडियो को दिखाने की अनुमति देता है, जैसे:
Kotlin
fun onRenderedFirstFrame(surface:Surface) { firstFrameDrawn = true notifyVideoAvailable() }
Java
@Override public void onRenderedFirstFrame(Surface surface) { firstFrameDrawn = true; notifyVideoAvailable(); }
यह ट्रांज़िशन कुछ सेकंड के अंदर ही किया जा सकता है, लेकिन स्क्रीन खाली होने पर चित्र को अजीब ब्लिप और कंपन में दिखाने की अनुमति देने की तुलना में विज़ुअल रूप से बेहतर.
काम करने के बारे में ज़्यादा जानकारी के लिए, प्लेयर को प्लैटफ़ॉर्म के साथ इंटिग्रेट करना लेख भी देखें
वीडियो रेंडर करने के लिए Surface
की मदद लें.
माता-पिता के कंट्रोल वाली सुविधा का इस्तेमाल करना
यह पता लगाने के लिए कि किसी कॉन्टेंट को माता-पिता के कंट्रोल और कॉन्टेंट रेटिंग से ब्लॉक किया गया है या नहीं,
TvInputManager
क्लास तरीके, isParentalControlsEnabled()
और isRatingBlocked(android.media.tv.TvContentRating)
. आपने लोगों तक पहुंचाया मुफ़्त में
यह भी पक्का किया जा सकता है कि कॉन्टेंट का TvContentRating
का सेट कर सकता है. यहां दिए गए सैंपल में, इन बातों के बारे में बताया गया है.
Kotlin
private fun checkContentBlockNeeded() { currentContentRating?.also { rating -> if (!tvInputManager.isParentalControlsEnabled || !tvInputManager.isRatingBlocked(rating) || unblockedRatingSet.contains(rating)) { // Content rating is changed so we don't need to block anymore. // Unblock content here explicitly to resume playback. unblockContent(null) return } } lastBlockedRating = currentContentRating player?.run { // Children restricted content might be blocked by TV app as well, // but TIF should do its best not to show any single frame of blocked content. releasePlayer() } notifyContentBlocked(currentContentRating) }
Java
private void checkContentBlockNeeded() { if (currentContentRating == null || !tvInputManager.isParentalControlsEnabled() || !tvInputManager.isRatingBlocked(currentContentRating) || unblockedRatingSet.contains(currentContentRating)) { // Content rating is changed so we don't need to block anymore. // Unblock content here explicitly to resume playback. unblockContent(null); return; } lastBlockedRating = currentContentRating; if (player != null) { // Children restricted content might be blocked by TV app as well, // but TIF should do its best not to show any single frame of blocked content. releasePlayer(); } notifyContentBlocked(currentContentRating); }
यह तय करने के बाद कि कॉन्टेंट को ब्लॉक करना चाहिए या नहीं, सिस्टम टीवी को इसकी सूचना दें
Android पर कॉल करने के लिए,
TvInputService.Session
तरीका notifyContentAllowed()
या
notifyContentBlocked()
, जैसा कि पिछले उदाहरण में दिखाया गया है.
TvContentRating
क्लास का इस्तेमाल करके
COLUMN_CONTENT_RATING
TvContentRating.createRating()
तरीका, जैसा कि यहां दिखाया गया है:
Kotlin
val rating = TvContentRating.createRating( "com.android.tv", "US_TV", "US_TV_PG", "US_TV_D", "US_TV_L" )
Java
TvContentRating rating = TvContentRating.createRating( "com.android.tv", "US_TV", "US_TV_PG", "US_TV_D", "US_TV_L");
ट्रैक चुनने का काम मैनेज करना
TvTrackInfo
क्लास में ऐसे मीडिया ट्रैक के बारे में जानकारी होती है
ट्रैक टाइप (वीडियो, ऑडियो या सबटाइटल) वगैरह में से किसी भी तरह का हो सकता है.
जब पहली बार आपके टीवी इनपुट सेशन को ट्रैक की जानकारी मिलेगी, तो उसे कॉल करना चाहिए
सिस्टम टीवी ऐप्लिकेशन को अपडेट करने के लिए, सभी ट्रैक की सूची के साथ TvInputService.Session.notifyTracksChanged()
. जब वहां
ट्रैक की जानकारी में एक बदलाव है,
notifyTracksChanged()
फिर से अपडेट करें.
सिस्टम टीवी ऐप्लिकेशन में एक से ज़्यादा ट्रैक होने पर, उपयोगकर्ता को कोई खास ट्रैक चुनने के लिए इंटरफ़ेस मिलता है
ट्रैक, दिए गए ट्रैक टाइप के लिए उपलब्ध हो; जैसे, अलग-अलग भाषाओं में सबटाइटल. आपका टीवी
इनपुट इसके लिए प्रतिक्रिया देता है:
onSelectTrack()
अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है
सिस्टम टीवी ऐप्लिकेशन से कॉल करके
notifyTrackSelected()
, जैसा कि नीचे दिए गए उदाहरण में दिखाया गया है. ध्यान दें कि जब null
को ट्रैक आईडी के रूप में पास किया जाता है, तो इससे ट्रैक अनलिंक हो जाता है.
Kotlin
override fun onSelectTrack(type: Int, trackId: String?): Boolean = mPlayer?.let { player -> if (type == TvTrackInfo.TYPE_SUBTITLE) { if (!captionEnabled && trackId != null) return false selectedSubtitleTrackId = trackId subtitleView.visibility = if (trackId == null) View.INVISIBLE else View.VISIBLE } player.trackInfo.indexOfFirst { it.trackType == type }.let { trackIndex -> if( trackIndex >= 0) { player.selectTrack(trackIndex) notifyTrackSelected(type, trackId) true } else false } } ?: false
Java
@Override public boolean onSelectTrack(int type, String trackId) { if (player != null) { if (type == TvTrackInfo.TYPE_SUBTITLE) { if (!captionEnabled && trackId != null) { return false; } selectedSubtitleTrackId = trackId; if (trackId == null) { subtitleView.setVisibility(View.INVISIBLE); } } int trackIndex = -1; MediaPlayer.TrackInfo[] trackInfos = player.getTrackInfo(); for (int index = 0; index < trackInfos.length; index++) { MediaPlayer.TrackInfo trackInfo = trackInfos[index]; if (trackInfo.getTrackType() == type) { trackIndex = index; break; } } if (trackIndex >= 0) { player.selectTrack(trackIndex); notifyTrackSelected(type, trackId); return true; } } return false; }