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

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

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

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

DownloadService बनाना

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

  • getDownloadManager(): इस्तेमाल की जाने वाली DownloadManager वैल्यू दिखाता है.
  • getScheduler(): यह एक वैकल्पिक Scheduler दिखाता है. इससे सेवा को फिर से शुरू किया जा सकता है. ऐसा तब किया जा सकता है, जब डाउनलोड पूरे करने के लिए ज़रूरी शर्तें पूरी हो गई हों. ExoPlayer, इन सुविधाओं को लागू करने के तरीके उपलब्ध कराता है:
    • PlatformScheduler का इस्तेमाल करता है. इसके लिए, JobScheduler का इस्तेमाल किया जाता है. इसका एपीआई वर्शन कम से कम 21 होना चाहिए. ऐप्लिकेशन की अनुमति से जुड़ी ज़रूरी शर्तों के लिए, PlatformScheduler javadocs देखें.
    • 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 का इस्तेमाल, DRM और कस्टम डेटा सेट करने के लिए किया जा सकता है. यह डेटा, ऐप्लिकेशन को डाउनलोड से जोड़ना होता है. कॉन्टेंट के 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 से डेटा पढ़ा जाता है.

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

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 से Download.request.toMediaItem का इस्तेमाल करके या सीधे तौर पर DownloadRequest से DownloadRequest.toMediaItem का इस्तेमाल करके हासिल किया जा सकता है.

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

ऊपर दिए गए उदाहरण में, डाउनलोड की गई कैश मेमोरी को सभी MediaItem के प्लेबैक के लिए उपलब्ध कराया गया है. डाउनलोड की गई कैश मेमोरी को अलग-अलग 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.Factory इंस्टेंस का इस्तेमाल करके DownloadHelper बनाएं. सहायता करने वाले व्यक्ति को तैयार करें और कॉलबैक का इंतज़ार करें.
  2. getMappedTrackInfo और getTrackSelections का इस्तेमाल करके, डिफ़ॉल्ट रूप से चुने गए ट्रैक की जांच करें. इसके बाद, clearTrackSelections, replaceTrackSelections, और addTrackSelection का इस्तेमाल करके, उनमें बदलाव करें.
  3. DownloadRequest को कॉल करके, चुने गए ट्रैक के लिए DownloadRequest बनाएं.getDownloadRequest ऊपर बताए गए तरीके से, डाउनलोड करने का अनुरोध आपके DownloadService को भेजा जा सकता है.
  4. release() का इस्तेमाल करके, हेल्पर को रिलीज़ करें.

Kotlin

val downloadHelper =
  DownloadHelper.Factory()
    .setRenderersFactory(DefaultRenderersFactory(context))
    .setDataSourceFactory(dataSourceFactory)
    .create(MediaItem.fromUri(contentUri))
downloadHelper.prepare(callback)

Java

DownloadHelper downloadHelper =
    new DownloadHelper.Factory()
        .setRenderersFactory(new DefaultRenderersFactory(context))
        .setDataSourceFactory(dataSourceFactory)
        .create(MediaItem.fromUri(contentUri));
downloadHelper.prepare(callback);

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

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