मीडिया डाउनलोड किया जा रहा है

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

मीडिया डाउनलोड करने के लिए क्लास. ऐरो के निर्देश, डेटा के फ़्लो को दिखाते हैं.

  • DownloadService: DownloadManager को रैप करता है और उस पर निर्देश भेजता है. यह सेवा, ऐप्लिकेशन के बैकग्राउंड में होने पर भी DownloadManager को चालू रखने की अनुमति देती है.
  • DownloadManager: यह कई डाउनलोड मैनेज करता है. साथ ही, DownloadIndex से और उसमें, डाउनलोड की स्थिति को लोड (और सेव) करता है. साथ ही, नेटवर्क कनेक्शन जैसी ज़रूरी शर्तों के आधार पर, डाउनलोड शुरू और बंद करता है. कॉन्टेंट डाउनलोड करने के लिए, मैनेजर आम तौर पर HttpDataSource से डाउनलोड किया जा रहा डेटा पढ़ेगा और उसे Cache में लिखेगा.
  • DownloadIndex: डाउनलोड की स्थिति को सेव करता है.

DownloadService बनाना

DownloadService बनाने के लिए, उसे सबक्लास बनाएं और उसके एब्स्ट्रैक्ट तरीके लागू करें:

  • getDownloadManager(): इस्तेमाल की जाने वाली DownloadManager को दिखाता है.
  • getScheduler(): एक वैकल्पिक Scheduler दिखाता है. यह Scheduler, डाउनलोड की प्रोसेस को फिर से शुरू कर सकता है. ऐसा तब होता है, जब बाकी बचे डाउनलोड की ज़रूरी शर्तें पूरी हो जाती हैं. ExoPlayer में ये सुविधाएं उपलब्ध हैं:
    • PlatformScheduler, जो JobScheduler का इस्तेमाल करता है (एपीआई कम से कम 21 होना चाहिए). ऐप्लिकेशन की अनुमतियों से जुड़ी ज़रूरी शर्तों के लिए, PlatformScheduler के Javadoc देखें.
    • WorkManagerScheduler, जो WorkManager का इस्तेमाल करता है.
  • getForegroundNotification(): यह फ़ंक्शन, सेवा के फ़ोरग्राउंड में चलने पर दिखाई जाने वाली सूचना दिखाता है. डिफ़ॉल्ट स्टाइल में सूचना बनाने के लिए, DownloadNotificationHelper.buildProgressNotification का इस्तेमाल किया जा सकता है.

आखिर में, अपनी AndroidManifest.xml फ़ाइल में सेवा के बारे में बताएं:

<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC"/>
<application>
  <service android:name="com.myapp.MyDownloadService"
      android:exported="false"
      android:foregroundServiceType="dataSync">
    <!-- This is needed for Scheduler -->
    <intent-filter>
      <action android:name="androidx.media3.exoplayer.downloadService.action.RESTART"/>
      <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
  </service>
</application>

इसका उदाहरण देखने के लिए, ExoPlayer के डेमो ऐप्लिकेशन में DemoDownloadService और AndroidManifest.xml देखें.

DownloadManager बनाना

नीचे दिए गए कोड स्निपेट में, DownloadManager को इंस्टैंशिएट करने का तरीका बताया गया है. इसे DownloadService में getDownloadManager() से दिखाया जा सकता है:

Kotlin

// Note: This should be a singleton in your app.
val databaseProvider = StandaloneDatabaseProvider(context)

// A download cache should not evict media, so should use a NoopCacheEvictor.
val downloadCache = SimpleCache(downloadDirectory, NoOpCacheEvictor(), databaseProvider)

// Create a factory for reading the data from the network.
val dataSourceFactory = DefaultHttpDataSource.Factory()

// Choose an executor for downloading data. Using Runnable::run will cause each download task to
// download data on its own thread. Passing an executor that uses multiple threads will speed up
// download tasks that can be split into smaller parts for parallel execution. Applications that
// already have an executor for background downloads may wish to reuse their existing executor.
val downloadExecutor = Executor(Runnable::run)

// Create the download manager.
val downloadManager =
  DownloadManager(context, databaseProvider, downloadCache, dataSourceFactory, downloadExecutor)

// Optionally, properties can be assigned to configure the download manager.
downloadManager.requirements = requirements
downloadManager.maxParallelDownloads = 3

Java

// Note: This should be a singleton in your app.
databaseProvider = new StandaloneDatabaseProvider(context);

// A download cache should not evict media, so should use a NoopCacheEvictor.
downloadCache = new SimpleCache(downloadDirectory, new NoOpCacheEvictor(), databaseProvider);

// Create a factory for reading the data from the network.
dataSourceFactory = new DefaultHttpDataSource.Factory();

// Choose an executor for downloading data. Using Runnable::run will cause each download task to
// download data on its own thread. Passing an executor that uses multiple threads will speed up
// download tasks that can be split into smaller parts for parallel execution. Applications that
// already have an executor for background downloads may wish to reuse their existing executor.
Executor downloadExecutor = Runnable::run;

// Create the download manager.
downloadManager =
    new DownloadManager(
        context, databaseProvider, downloadCache, dataSourceFactory, downloadExecutor);

// Optionally, setters can be called to configure the download manager.
downloadManager.setRequirements(requirements);
downloadManager.setMaxParallelDownloads(3);

इसका उदाहरण देखने के लिए, डेमो ऐप्लिकेशन में DemoUtil देखें.

डाउनलोड जोड़ना

डाउनलोड की गई किसी फ़ाइल को जोड़ने के लिए, DownloadRequest बनाएं और उसे अपने DownloadService पर भेजें. अडैप्टिव स्ट्रीम के लिए, DownloadRequest बनाने में मदद पाने के लिए, DownloadHelper का इस्तेमाल करें. यहां दिए गए उदाहरण में, डाउनलोड का अनुरोध करने का तरीका बताया गया है:

Kotlin

val downloadRequest = DownloadRequest.Builder(contentId, contentUri).build()

Java

DownloadRequest downloadRequest = new DownloadRequest.Builder(contentId, contentUri).build();

इस उदाहरण में, contentId कॉन्टेंट का यूनीक आइडेंटिफ़ायर है. सामान्य मामलों में, contentUri का इस्तेमाल अक्सर contentId के तौर पर किया जा सकता है. हालांकि, ऐप्लिकेशन अपने इस्तेमाल के उदाहरण के हिसाब से, अपनी पसंद के आईडी स्कीम का इस्तेमाल कर सकते हैं. DownloadRequest.Builder में कुछ वैकल्पिक सेटर भी होते हैं. उदाहरण के लिए, setKeySetId और setData का इस्तेमाल, डीआरएम और कस्टम डेटा को सेट करने के लिए किया जा सकता है. ऐप्लिकेशन, डाउनलोड किए गए कॉन्टेंट के साथ इन डेटा को जोड़ना चाहता है. कॉन्टेंट के MIME टाइप की जानकारी, setMimeType का इस्तेमाल करके भी दी जा सकती है. ऐसा उन मामलों में एक हिंट के तौर पर किया जा सकता है जहां contentUri से कॉन्टेंट टाइप का पता नहीं चलता.

अनुरोध बनाने के बाद, डाउनलोड जोड़ने के लिए DownloadService को अनुरोध भेजा जा सकता है:

Kotlin

DownloadService.sendAddDownload(
  context,
  MyDownloadService::class.java,
  downloadRequest,
  /* foreground= */ false
)

Java

DownloadService.sendAddDownload(
    context, MyDownloadService.class, downloadRequest, /* foreground= */ false);

इस उदाहरण में, MyDownloadService ऐप्लिकेशन का DownloadService सबक्लास है और foreground पैरामीटर यह कंट्रोल करता है कि सेवा को फ़ोरग्राउंड में शुरू किया जाएगा या नहीं. अगर आपका ऐप्लिकेशन पहले से फ़ोरग्राउंड में है, तो foreground पैरामीटर को सामान्य रूप से false पर सेट किया जाना चाहिए. इसकी वजह यह है कि DownloadService खुद को फ़ोरग्राउंड में डाल देगा, अगर उसे लगता है कि उसे काम करना है.

डाउनलोड की गई फ़ाइलें हटाई जा रही हैं

DownloadService को 'हटाएं' निर्देश भेजकर, किसी डाउनलोड को हटाया जा सकता है. इसमें contentId, हटाए जाने वाले डाउनलोड की पहचान करता है:

Kotlin

DownloadService.sendRemoveDownload(
  context,
  MyDownloadService::class.java,
  contentId,
  /* foreground= */ false
)

Java

DownloadService.sendRemoveDownload(
    context, MyDownloadService.class, contentId, /* foreground= */ false);

DownloadService.sendRemoveAllDownloads की मदद से, डाउनलोड किया गया सारा डेटा भी हटाया जा सकता है.

डाउनलोड शुरू और बंद करना

डाउनलोड सिर्फ़ तब शुरू होगा, जब ये चार शर्तें पूरी होंगी:

  • डाउनलोड रुकने की वजह नहीं दी गई है.
  • डाउनलोड की प्रोसेस रुक नहीं रही है.
  • डाउनलोड की प्रोग्रेस से जुड़ी ज़रूरी शर्तें पूरी हो गई हैं. ज़रूरी शर्तों में, इस्तेमाल किए जा सकने वाले नेटवर्क टाइप से जुड़ी पाबंदियों के साथ-साथ यह भी बताया जा सकता है कि डिवाइस को चार्जर से कनेक्ट किया गया हो या नहीं.
  • एक साथ डाउनलोड की जा सकने वाली ज़्यादा से ज़्यादा संख्या से ज़्यादा डाउनलोड न किए जा रहे हों.

इन सभी स्थितियों को कंट्रोल करने के लिए, अपने DownloadService पर निर्देश भेजें.

डाउनलोड रुकने की वजहें सेट करना और उन्हें मिटाना

एक या सभी डाउनलोड को रोकने की वजह सेट की जा सकती है:

Kotlin

// Set the stop reason for a single download.
DownloadService.sendSetStopReason(
  context,
  MyDownloadService::class.java,
  contentId,
  stopReason,
  /* foreground= */ false
)

// Clear the stop reason for a single download.
DownloadService.sendSetStopReason(
  context,
  MyDownloadService::class.java,
  contentId,
  Download.STOP_REASON_NONE,
  /* foreground= */ false
)

Java

// Set the stop reason for a single download.
DownloadService.sendSetStopReason(
    context, MyDownloadService.class, contentId, stopReason, /* foreground= */ false);

// Clear the stop reason for a single download.
DownloadService.sendSetStopReason(
    context,
    MyDownloadService.class,
    contentId,
    Download.STOP_REASON_NONE,
    /* foreground= */ false);

stopReason की वैल्यू शून्य के अलावा कोई भी हो सकती है. Download.STOP_REASON_NONE = 0 एक खास वैल्यू है, जिसका मतलब है कि डाउनलोड नहीं रुका है. जिन ऐप्लिकेशन में डाउनलोड रोकने की कई वजहें होती हैं वे अलग-अलग वैल्यू का इस्तेमाल करके, यह ट्रैक कर सकते हैं कि हर डाउनलोड क्यों रोका गया. सभी डाउनलोड के लिए, डाउनलोड रोकने की वजह सेट करने और उसे हटाने का तरीका, किसी एक डाउनलोड के लिए डाउनलोड रोकने की वजह सेट करने और उसे हटाने के तरीके जैसा ही है. हालांकि, contentId को null पर सेट किया जाना चाहिए.

अगर डाउनलोड की वजह से डाउनलोड रुकने की वजह शून्य से ज़्यादा है, तो उसकी स्थिति Download.STATE_STOPPED होगी. स्टॉप की वजहें DownloadIndex में बनी रहती हैं. इसलिए, अगर ऐप्लिकेशन प्रोसेस बंद हो जाती है और बाद में रीस्टार्ट हो जाता है, तो भी इसे सेव रखा जाता है.

सभी डाउनलोड रोकना और फिर से शुरू करना

सभी डाउनलोड को रोका और फिर से शुरू किया जा सकता है. इसके लिए, यह तरीका अपनाएं:

Kotlin

// Pause all downloads.
DownloadService.sendPauseDownloads(
  context,
  MyDownloadService::class.java,
  /* foreground= */ false
)

// Resume all downloads.
DownloadService.sendResumeDownloads(
  context,
  MyDownloadService::class.java,
  /* foreground= */ false
)

Java

// Pause all downloads.
DownloadService.sendPauseDownloads(context, MyDownloadService.class, /* foreground= */ false);

// Resume all downloads.
DownloadService.sendResumeDownloads(context, MyDownloadService.class, /* foreground= */ false);

डाउनलोड रोके जाने पर, उनकी स्थिति Download.STATE_QUEUED के तौर पर दिखेगी. स्टॉप की वजहें सेट करने के विपरीत, इस तरीके से किसी भी स्थिति में बदलाव नहीं होता. इससे सिर्फ़ DownloadManager के रनटाइम की स्थिति पर असर पड़ता है.

डाउनलोड को प्रोसेस करने के लिए ज़रूरी शर्तें सेट करना

Requirements का इस्तेमाल, उन शर्तों के बारे में बताने के लिए किया जा सकता है जिन्हें पूरा करने के बाद ही, डाउनलोड की प्रोसेस शुरू की जा सकती है. DownloadManager बनाते समय, DownloadManager.setRequirements() को कॉल करके ज़रूरी शर्तें सेट की जा सकती हैं. उदाहरण के लिए, ऊपर दिया गया उदाहरण. DownloadService को कमांड भेजकर भी इन्हें डाइनैमिक तरीके से बदला जा सकता है:

Kotlin

// Set the download requirements.
DownloadService.sendSetRequirements(
  context, MyDownloadService::class.java, requirements, /* foreground= */ false)

Java

// Set the download requirements.
DownloadService.sendSetRequirements(
  context,
  MyDownloadService.class,
  requirements,
  /* foreground= */ false);

अगर ज़रूरी शर्तें पूरी न होने की वजह से डाउनलोड नहीं हो पा रहा है, तो उसकी स्थिति Download.STATE_QUEUED होगी. DownloadManager.getNotMetRequirements() की मदद से, उन ज़रूरी शर्तों के बारे में क्वेरी की जा सकती है जो पूरी नहीं की गई हैं.

एक साथ ज़्यादा से ज़्यादा कितने वीडियो डाउनलोड किए जा सकते हैं, यह सेट करना

एक साथ डाउनलोड की जा सकने वाली फ़ाइलों की ज़्यादा से ज़्यादा संख्या सेट करने के लिए, DownloadManager.setMaxParallelDownloads() को कॉल करें. आम तौर पर, DownloadManager बनाते समय ऐसा किया जाता है, जैसा कि ऊपर दिए गए उदाहरण में बताया गया है.

जब एक साथ कई फ़ाइलें डाउनलोड करने की तय सीमा पूरी हो जाती है, तो Download.STATE_QUEUED स्टेटस दिखता है.

डाउनलोड के बारे में क्वेरी करना

DownloadManager के DownloadIndex से, सभी डाउनलोड की स्थिति के बारे में जानकारी मांगी जा सकती है. इसमें, डाउनलोड की गई फ़ाइलें भी शामिल हैं. DownloadIndex पाने के लिए, DownloadManager.getDownloadIndex() पर कॉल करें. इसके बाद, DownloadIndex.getDownloads() को कॉल करके, सभी डाउनलोड पर कर्सर घुमाया जा सकता है. इसके अलावा, DownloadIndex.getDownload() को कॉल करके, किसी एक डाउनलोड की स्थिति के बारे में जानकारी भी पाई जा सकती है.

DownloadManager से, DownloadManager.getCurrentDownloads() की जानकारी भी मिलती है. इससे सिर्फ़ डाउनलोड की मौजूदा स्थिति (यानी पूरा नहीं हुआ या पूरा नहीं हो सका) की जानकारी मिलती है. यह तरीका, सूचनाओं और यूज़र इंटरफ़ेस (यूआई) के उन अन्य कॉम्पोनेंट को अपडेट करने के लिए काम आता है जो मौजूदा डाउनलोड की स्थिति और प्रोग्रेस दिखाते हैं.

डाउनलोड किए गए वीडियो सुनना

DownloadManager में किसी लिसनर को जोड़ा जा सकता है, ताकि मौजूदा डाउनलोड की स्थिति बदलने पर आपको इसकी सूचना मिल सके:

Kotlin

downloadManager.addListener(
  object : DownloadManager.Listener { // Override methods of interest here.
  }
)

Java

downloadManager.addListener(
    new DownloadManager.Listener() {
      // Override methods of interest here.
    });

उदाहरण के लिए, डेमो ऐप्लिकेशन की DownloadTracker क्लास में DownloadManagerListener देखें.

डाउनलोड किया गया कॉन्टेंट चलाया जा रहा है

डाउनलोड किया गया कॉन्टेंट चलाना, ऑनलाइन कॉन्टेंट चलाने जैसा ही है. हालांकि, इसमें डेटा को नेटवर्क से पढ़ने के बजाय, डाउनलोड किए गए Cache से पढ़ा जाता है.

डाउनलोड किया गया कॉन्टेंट चलाने के लिए, उसी Cache इंस्टेंस का इस्तेमाल करके CacheDataSource.Factory बनाएं जिसका इस्तेमाल डाउनलोड करने के लिए किया गया था. साथ ही, प्लेयर बनाते समय इसे DefaultMediaSourceFactory में इंजेक्ट करें:

Kotlin

// Create a read-only cache data source factory using the download cache.
val cacheDataSourceFactory: DataSource.Factory =
  CacheDataSource.Factory()
    .setCache(downloadCache)
    .setUpstreamDataSourceFactory(httpDataSourceFactory)
    .setCacheWriteDataSinkFactory(null) // Disable writing.

val player =
  ExoPlayer.Builder(context)
    .setMediaSourceFactory(
      DefaultMediaSourceFactory(context).setDataSourceFactory(cacheDataSourceFactory)
    )
    .build()

Java

// Create a read-only cache data source factory using the download cache.
DataSource.Factory cacheDataSourceFactory =
    new CacheDataSource.Factory()
        .setCache(downloadCache)
        .setUpstreamDataSourceFactory(httpDataSourceFactory)
        .setCacheWriteDataSinkFactory(null); // Disable writing.

ExoPlayer player =
    new ExoPlayer.Builder(context)
        .setMediaSourceFactory(
            new DefaultMediaSourceFactory(context).setDataSourceFactory(cacheDataSourceFactory))
        .build();

अगर उसी प्लेयर इंस्टेंस का इस्तेमाल, डाउनलोड नहीं किए गए कॉन्टेंट को चलाने के लिए भी किया जाएगा, तो CacheDataSource.Factory को रीड-ओनली के तौर पर कॉन्फ़िगर किया जाना चाहिए, ताकि वीडियो चलाने के दौरान उस कॉन्टेंट को भी डाउनलोड न किया जाए.

CacheDataSource.Factory के साथ प्लेयर को कॉन्फ़िगर करने के बाद, उसे डाउनलोड किए गए कॉन्टेंट को चलाने का ऐक्सेस मिल जाएगा. किसी डाउनलोड को चलाना, उससे जुड़े MediaItem को प्लेयर को पास करने जितना आसान हो जाता है. MediaItem, Download.request.toMediaItem का इस्तेमाल करके Download से या DownloadRequest.toMediaItem का इस्तेमाल करके सीधे DownloadRequest से लिया जा सकता है.

MediaSource कॉन्फ़िगरेशन

ऊपर दिए गए उदाहरण में, डाउनलोड किए गए कैश मेमोरी को सभी MediaItems के लिए चलाने के लिए उपलब्ध कराया गया है. डाउनलोड कैश मेमोरी को अलग-अलग MediaSource इंस्टेंस के लिए भी उपलब्ध कराया जा सकता है. इसे सीधे प्लेयर को पास किया जा सकता है:

Kotlin

val mediaSource =
  ProgressiveMediaSource.Factory(cacheDataSourceFactory)
    .createMediaSource(MediaItem.fromUri(contentUri))
player.setMediaSource(mediaSource)
player.prepare()

Java

ProgressiveMediaSource mediaSource =
    new ProgressiveMediaSource.Factory(cacheDataSourceFactory)
        .createMediaSource(MediaItem.fromUri(contentUri));
player.setMediaSource(mediaSource);
player.prepare();

स्ट्रीम के हिसाब से वीडियो डाउनलोड करना और चलाना

अडैप्टिव स्ट्रीम (जैसे, DASH, SmoothStreaming, और HLS) में आम तौर पर, एक से ज़्यादा मीडिया ट्रैक होते हैं. ऐसे कई ट्रैक होते हैं जिनमें एक जैसा कॉन्टेंट, अलग-अलग क्वालिटी में होता है. जैसे, एसडी, एचडी, और 4K वीडियो ट्रैक. एक ही तरह के कई ट्रैक में अलग-अलग कॉन्टेंट भी हो सकता है. जैसे, अलग-अलग भाषाओं में कई ऑडियो ट्रैक.

स्ट्रीमिंग के दौरान, ट्रैक सिलेक्टर का इस्तेमाल करके यह चुना जा सकता है कि कौनसे ट्रैक चलाए जाएं. इसी तरह, डाउनलोड करने के लिए, DownloadHelper का इस्तेमाल करके यह चुना जा सकता है कि कौनसे ट्रैक डाउनलोड किए जाएं. DownloadHelper का सामान्य इस्तेमाल करने के लिए, यह तरीका अपनाएं:

  1. किसी DownloadHelper.forMediaItem तरीके का इस्तेमाल करके, DownloadHelper बनाएं. हेल्पर को तैयार करें और कॉलबैक का इंतज़ार करें.

    Kotlin

    val downloadHelper =
     DownloadHelper.forMediaItem(
       context,
       MediaItem.fromUri(contentUri),
       DefaultRenderersFactory(context),
       dataSourceFactory
     )
    downloadHelper.prepare(callback)
    

    Java

    DownloadHelper downloadHelper =
       DownloadHelper.forMediaItem(
           context,
           MediaItem.fromUri(contentUri),
           new DefaultRenderersFactory(context),
           dataSourceFactory);
    downloadHelper.prepare(callback);
    
  2. इसके अलावा, getMappedTrackInfo और getTrackSelections का इस्तेमाल करके, डिफ़ॉल्ट रूप से चुने गए ट्रैक की जांच करें. साथ ही, clearTrackSelections, replaceTrackSelections, और addTrackSelection का इस्तेमाल करके, उनमें बदलाव करें.
  3. getDownloadRequest को कॉल करके, चुने गए ट्रैक के लिए DownloadRequest बनाएं. ऊपर बताए गए तरीके से, डाउनलोड जोड़ने के लिए अनुरोध को अपने DownloadService पर भेजा जा सकता है.
  4. release() का इस्तेमाल करके, हेल्पर को छोड़ें.

डाउनलोड किए गए अडैप्टिव कॉन्टेंट को चलाने के लिए, प्लेयर को कॉन्फ़िगर करना और ऊपर बताए गए तरीके से उससे जुड़ा MediaItem पास करना ज़रूरी है.

MediaItem बनाते समय, MediaItem.localConfiguration.streamKeys को DownloadRequest में मौजूद ट्रैक से मैच करने के लिए सेट किया जाना चाहिए, ताकि प्लेयर सिर्फ़ डाउनलोड किए गए ट्रैक के सबसेट को चलाने की कोशिश करे. MediaItem बनाने के लिए, Download.request.toMediaItem और DownloadRequest.toMediaItem का इस्तेमाल करने पर, यह काम आपके लिए हो जाएगा.