लाइव स्ट्रीमिंग

ExoPlayer, ज़्यादातर अडैप्टिव लाइव स्ट्रीम को बिना किसी खास कॉन्फ़िगरेशन के चलाता है. ज़्यादा जानकारी के लिए, काम करने वाले फ़ॉर्मैट की जानकारी वाला पेज देखें.

अडैप्टिव लाइव स्ट्रीम में, उपलब्ध मीडिया की एक विंडो दिखती है. यह विंडो, रीयल-टाइम में होने वाले बदलावों के हिसाब से, समय-समय पर अपडेट होती रहती है. इसका मतलब है कि प्लेबैक की पोज़िशन हमेशा इस विंडो में ही होगी. ज़्यादातर मामलों में, यह पोज़िशन उस रीयल-टाइम के करीब होगी जिस दौरान स्ट्रीम बनाई जा रही है. मौजूदा रीयल-टाइम और वीडियो चलने की पोज़िशन के बीच के अंतर को लाइव ऑफ़सेट कहा जाता है.

लाइव वीडियो चलाने की सुविधा का पता लगाना और उसे मॉनिटर करना

जब भी कोई लाइव विंडो अपडेट की जाती है, तो रजिस्टर किए गए Player.Listener इंस्टेंस को onTimelineChanged इवेंट मिलेगा. लाइव वीडियो चलाने की जानकारी पाने के लिए, Player और Timeline.Window के अलग-अलग तरीकों के बारे में क्वेरी करें. इन तरीकों की जानकारी यहां दी गई है.

लाइव विंडो

  • Player.isCurrentWindowLive से पता चलता है कि फ़िलहाल चल रहा मीडिया आइटम लाइव स्ट्रीम है या नहीं. लाइव स्ट्रीम खत्म होने के बाद भी, यह वैल्यू 'सही' बनी रहती है.
  • Player.isCurrentWindowDynamic से पता चलता है कि चल रहे मीडिया आइटम को अब भी अपडेट किया जा रहा है. आम तौर पर, ऐसा उन लाइव स्ट्रीम पर भी होता है जो अभी खत्म नहीं हुई हैं. ध्यान दें कि कुछ मामलों में, यह फ़्लैग नॉन-लाइव स्ट्रीम के लिए भी लागू होता है.
  • Player.getCurrentLiveOffset, मौजूदा रीयल टाइम और वीडियो चलाने की जगह (अगर उपलब्ध हो) के बीच का ऑफ़सेट दिखाता है.
  • Player.getDuration, मौजूदा लाइव विंडो की अवधि दिखाता है.
  • Player.getCurrentPosition, लाइव विंडो की शुरुआत के हिसाब से वीडियो चलाने की पोज़िशन दिखाता है.
  • Player.getCurrentMediaItem मौजूदा मीडिया आइटम दिखाता है. इसमें MediaItem.liveConfiguration, टारगेट लाइव ऑफ़सेट और लाइव ऑफ़सेट अडजस्टमेंट पैरामीटर के लिए, ऐप्लिकेशन से मिले बदलाव दिखाता है.
  • Player.getCurrentTimeline, Timeline में मौजूदा मीडिया स्ट्रक्चर दिखाता है. मौजूदा Timeline.Window को Timeline से वापस पाया जा सकता है. इसके लिए, Player.getCurrentMediaItemIndex और Timeline.getWindow का इस्तेमाल करें. Window में:
    • Window.liveConfiguration में टारगेट लाइव ऑफ़सेट और लाइव ऑफ़सेट अडजस्टमेंट पैरामीटर शामिल होते हैं. ये वैल्यू, मीडिया में मौजूद जानकारी और ऐप्लिकेशन के ज़रिए MediaItem.liveConfiguration में सेट किए गए बदलावों के मुताबिक होती हैं.
    • Window.windowStartTimeMs, यूनिक्स के 'एपिक' (शुरुआत) से लेकर लाइव विंडो शुरू होने तक का समय है.
    • Window.getCurrentUnixTimeMs, मौजूदा रीयल-टाइम के Unix Epoch के बाद का समय है. इस वैल्यू को सर्वर और क्लाइंट के बीच के क्लॉक अंतर के ज़रिए ठीक किया जा सकता है.
    • लाइव विंडो में Window.getDefaultPositionMs वह पोज़िशन है जहां से प्लेयर, डिफ़ॉल्ट रूप से वीडियो चलाना शुरू करेगा.

लाइव स्ट्रीम में वीडियो खोजना

Player.seekTo का इस्तेमाल करके, लाइव विंडो में कहीं भी जाया जा सकता है. सेक करने के लिए दी गई पोज़िशन, लाइव विंडो की शुरुआत के हिसाब से होती है. उदाहरण के लिए, seekTo(0) से लाइव विंडो की शुरुआत पर पहुंचा जा सकता है. प्लेयर उसी लाइव ऑफ़सेट को रखने की कोशिश करेगा, जिस तरह से आगे बढ़ने के बाद किया जा सकता है.

लाइव विंडो में एक डिफ़ॉल्ट पोज़िशन भी होती है, जहां वीडियो चलाना शुरू करना होता है. आम तौर पर, यह पोज़िशन लाइव एज के आस-पास होती है. Player.seekToDefaultPosition पर कॉल करके, वीडियो की डिफ़ॉल्ट पोज़िशन पर जा सकते हैं.

लाइव प्लेबैक का यूज़र इंटरफ़ेस (यूआई)

ExoPlayer के डिफ़ॉल्ट यूज़र इंटरफ़ेस (यूआई) कॉम्पोनेंट, लाइव विंडो की अवधि और उसमें मौजूद वीडियो के मौजूदा प्लेबैक पॉज़िशन को दिखाते हैं. इसका मतलब है कि लाइव विंडो के अपडेट होने पर, पोज़िशन पीछे की ओर दिखेगी. अगर आपको अलग व्यवहार की ज़रूरत है, जैसे कि यूनिक्स समय या मौजूदा लाइव ऑफ़सेट दिखाना, तो PlayerControlView को फ़ोर्क करें और अपनी ज़रूरत के हिसाब से उसमें बदलाव करें.

लाइव वीडियो चलाने के पैरामीटर कॉन्फ़िगर करना

ExoPlayer, लाइव एज से प्लेबैक पोज़िशन के ऑफ़सेट को कंट्रोल करने के लिए कुछ पैरामीटर का इस्तेमाल करता है. साथ ही, प्लेबैक की स्पीड की रेंज को भी कंट्रोल करता है, ताकि इस ऑफ़सेट में बदलाव किया जा सके.

ExoPlayer को इन पैरामीटर की वैल्यू तीन जगहों से मिलती हैं. ये वैल्यू प्राथमिकता के हिसाब से, घटते क्रम में मिलती हैं. इसमें सबसे पहले मिली वैल्यू का इस्तेमाल किया जाता है:

  • MediaItem.Builder.setLiveConfiguration में भेजी गई हर MediaItem वैल्यू के लिए.
  • DefaultMediaSourceFactory पर सेट की गई ग्लोबल डिफ़ॉल्ट वैल्यू.
  • सीधे मीडिया से पढ़ी गई वैल्यू.

Kotlin

// Global settings.
val player =
  ExoPlayer.Builder(context)
    .setMediaSourceFactory(DefaultMediaSourceFactory(context).setLiveTargetOffsetMs(5000))
    .build()

// Per MediaItem settings.
val mediaItem =
  MediaItem.Builder()
    .setUri(mediaUri)
    .setLiveConfiguration(
      MediaItem.LiveConfiguration.Builder().setMaxPlaybackSpeed(1.02f).build()
    )
    .build()
player.setMediaItem(mediaItem)

Java

// Global settings.
ExoPlayer player =
    new ExoPlayer.Builder(context)
        .setMediaSourceFactory(
            new DefaultMediaSourceFactory(context).setLiveTargetOffsetMs(5000))
        .build();

// Per MediaItem settings.
MediaItem mediaItem =
    new MediaItem.Builder()
        .setUri(mediaUri)
        .setLiveConfiguration(
            new MediaItem.LiveConfiguration.Builder().setMaxPlaybackSpeed(1.02f).build())
        .build();
player.setMediaItem(mediaItem);

कॉन्फ़िगरेशन के लिए ये वैल्यू उपलब्ध हैं:

  • targetOffsetMs: टारगेट लाइव ऑफ़सेट. अगर हो सके, तो प्लेयर वीडियो चलाने के दौरान इस लाइव ऑफ़सेट के करीब पहुंचने की कोशिश करेगा.
  • minOffsetMs: लाइव स्ट्रीम के लिए कम से कम ऑफ़सेट. नेटवर्क की मौजूदा स्थितियों के हिसाब से ऑफ़सेट अडजस्ट करने के बाद भी, वीडियो चलाने के दौरान प्लेयर इस ऑफ़सेट से नीचे जाने की कोशिश नहीं करेगा.
  • maxOffsetMs: लाइव स्ट्रीम के लिए ज़्यादा से ज़्यादा ऑफ़सेट. नेटवर्क की मौजूदा स्थिति के हिसाब से ऑफ़सेट में बदलाव करने पर भी, प्लेयर वीडियो चलाने के दौरान इस ऑफ़सेट से ज़्यादा का इस्तेमाल नहीं करेगा.
  • minPlaybackSpeed: वीडियो चलाने की कम से कम स्पीड, जिसका इस्तेमाल प्लेयर, टारगेट लाइव ऑफ़सेट तक पहुंचने के लिए कर सकता है.
  • maxPlaybackSpeed: वीडियो चलाने की ज़्यादा से ज़्यादा स्पीड, जिसका इस्तेमाल करके प्लेयर, टारगेट लाइव ऑफ़सेट तक पहुंचने के लिए वीडियो को तेज़ी से चला सकता है.

वीडियो चलाने की स्पीड अडजस्ट करना

कम इंतज़ार वाली लाइव स्ट्रीम चलाते समय, ExoPlayer वीडियो चलाने की स्पीड में थोड़ा बदलाव करके, लाइव ऑफ़सेट को अडजस्ट करता है. प्लेयर, मीडिया या ऐप्लिकेशन से मिले टारगेट लाइव ऑफ़सेट से मैच करने की कोशिश करेगा. साथ ही, नेटवर्क की स्थिति में होने वाले बदलावों के हिसाब से भी काम करेगा. उदाहरण के लिए, अगर वीडियो चलाने के दौरान फिर से बफ़र करने की समस्या आती है, तो प्लेयर वीडियो चलाने की स्पीड थोड़ी कम कर देगा, ताकि लाइव एज से दूर जाया जा सके. अगर नेटवर्क फिर से इतना बेहतर हो जाता है कि लाइव एज के करीब वीडियो चलाया जा सके, तो प्लेयर, टारगेट लाइव ऑफ़सेट पर वापस जाने के लिए, वीडियो चलाने की स्पीड बढ़ा देगा.

अगर आपको वीडियो चलाने की स्पीड अपने-आप अडजस्ट होने की सुविधा नहीं चाहिए, तो इसे बंद किया जा सकता है. इसके लिए, minPlaybackSpeed और maxPlaybackSpeed प्रॉपर्टी को 1.0f पर सेट करें. इसी तरह, कम लेटेंसी वाली लाइव स्ट्रीम के लिए भी इसे चालू किया जा सकता है. इसके लिए, इन पैरामीटर को 1.0f के अलावा किसी दूसरी वैल्यू पर सेट करें. इन प्रॉपर्टी को सेट करने के तरीके के बारे में ज़्यादा जानकारी के लिए, ऊपर दिया गया कॉन्फ़िगरेशन सेक्शन देखें.

वीडियो चलाने की स्पीड अडजस्ट करने का एल्गोरिदम अपनी पसंद के मुताबिक बनाना

अगर स्पीड में बदलाव करने की सुविधा चालू है, तो LivePlaybackSpeedControl बताता है कि कौनसे बदलाव किए जाने हैं. अपनी पसंद के मुताबिक LivePlaybackSpeedControl लागू किया जा सकता है या डिफ़ॉल्ट तौर पर लागू होने वाले DefaultLivePlaybackSpeedControl को पसंद के मुताबिक बनाया जा सकता है. दोनों मामलों में, प्लेयर बनाते समय एक इंस्टेंस सेट किया जा सकता है:

Kotlin

val player =
  ExoPlayer.Builder(context)
    .setLivePlaybackSpeedControl(
      DefaultLivePlaybackSpeedControl.Builder().setFallbackMaxPlaybackSpeed(1.04f).build()
    )
    .build()

Java

ExoPlayer player =
    new ExoPlayer.Builder(context)
        .setLivePlaybackSpeedControl(
            new DefaultLivePlaybackSpeedControl.Builder()
                .setFallbackMaxPlaybackSpeed(1.04f)
                .build())
        .build();

DefaultLivePlaybackSpeedControl के लिए, कस्टमाइज़ेशन से जुड़े काम के पैरामीटर ये हैं:

  • fallbackMinPlaybackSpeed और fallbackMaxPlaybackSpeed: वीडियो चलाने की कम से कम और ज़्यादा से ज़्यादा स्पीड का इस्तेमाल, वीडियो को अडजस्ट करने के लिए किया जा सकता है. ऐसा तब किया जा सकता है, जब मीडिया और ऐप्लिकेशन के दिए MediaItem दोनों में से किसी एक के हिसाब से वीडियो चलाने की सीमाएं तय न हों.
  • proportionalControlFactor: यह कंट्रोल करता है कि स्पीड अडजस्टमेंट कितना आसान है. ज़्यादा वैल्यू से बदलाव अचानक और प्रतिक्रिया के तौर पर दिखते हैं, लेकिन इस बात की संभावना भी ज़्यादा होती है कि वे सुनाई दें. कम वैल्यू होने पर, स्पीड के बीच का ट्रांज़िशन आसान हो जाता है. हालांकि, वैल्यू कम होने की वजह से इसकी रफ़्तार धीमी होती है.
  • targetLiveOffsetIncrementOnRebufferMs: जब भी रीबफ़र होता है, तो इस वैल्यू को टारगेट लाइव ऑफ़सेट में जोड़ा जाता है, ताकि ज़्यादा सावधानी से आगे बढ़ा जा सके. इस सुविधा को बंद करने के लिए, इसकी वैल्यू को 0 पर सेट करें.
  • minPossibleLiveOffsetSmoothingFactor: यह एक एक्सपोनेन्शियल स्मूदिंग फ़ैक्टर है, जिसका इस्तेमाल मौजूदा बफ़र किए गए मीडिया के आधार पर, सबसे कम से कम लाइव ऑफ़सेट को ट्रैक करने के लिए किया जाता है. अगर वैल्यू 1 के काफ़ी करीब है, तो इसका मतलब है कि अनुमान ज़्यादा सावधानी से लगाया गया है. साथ ही, नेटवर्क की बेहतर स्थिति के हिसाब से अडजस्ट होने में ज़्यादा समय लग सकता है. वहीं, कम वैल्यू का मतलब है कि अनुमान तेज़ी से अडजस्ट होगा. हालांकि, इसकी वजह से फिर से बफ़र होने का खतरा ज़्यादा होगा.

BehindLiveWindowException और ERROR_CODE_BEHIND_LIVE_WINDOW

ऐसा हो सकता है कि वीडियो चलाने की जगह, लाइव विंडो से पीछे हो. उदाहरण के लिए, अगर प्लेयर को रोका गया है या वह लंबे समय तक बफ़र कर रहा है. ऐसा होने पर, वीडियो नहीं चलेगा और Player.Listener.onPlayerError के ज़रिए, गड़बड़ी कोड ERROR_CODE_BEHIND_LIVE_WINDOW वाला अपवाद रिपोर्ट किया जाएगा. ऐप्लिकेशन कोड, डिफ़ॉल्ट पोज़िशन पर वीडियो चलाकर, ऐसी गड़बड़ियों को ठीक कर सकता है. डेमो ऐप्लिकेशन की PlayerActivity इस तरीके की जानकारी देती है.

Kotlin

override fun onPlayerError(error: PlaybackException) {
  if (error.errorCode == PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW) {
    // Re-initialize player at the live edge.
    player.seekToDefaultPosition()
    player.prepare()
  } else {
    // Handle other errors
  }
}

Java

@Override
public void onPlayerError(PlaybackException error) {
  if (error.errorCode == PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW) {
    // Re-initialize player at the live edge.
    player.seekToDefaultPosition();
    player.prepare();
  } else {
    // Handle other errors
  }
}