একটি MediaSessionService সহ পটভূমি প্লেব্যাক

প্রায়শই এমন পরিস্থিতিতে মিডিয়া চালানো দরকার হয় যখন কোনো অ্যাপ ফোরগ্রাউন্ডে থাকে না। উদাহরণস্বরূপ, ব্যবহারকারী যখন তার ডিভাইস লক করে রাখেন বা অন্য কোনো অ্যাপ ব্যবহার করেন, তখনও একটি মিউজিক প্লেয়ার সাধারণত গান বাজাতে থাকে। Media3 লাইব্রেরিটি এমন কিছু ইন্টারফেস সরবরাহ করে, যা আপনাকে ব্যাকগ্রাউন্ড প্লেব্যাক সমর্থন করতে সাহায্য করে।

একটি MediaSessionService ব্যবহার করুন

ব্যাকগ্রাউন্ড প্লেব্যাক চালু করতে, আপনার Player এবং MediaSession একটি আলাদা সার্ভিসের মধ্যে রাখা উচিত। এর ফলে আপনার অ্যাপ ফোরগ্রাউন্ডে না থাকলেও ডিভাইসটি মিডিয়া পরিবেশন করা চালিয়ে যেতে পারে।

MediaSessionService মিডিয়া সেশনকে অ্যাপের অ্যাক্টিভিটি থেকে আলাদাভাবে চালানোর সুযোগ দেয়।
চিত্র ১ : MediaSessionService অ্যাপের অ্যাক্টিভিটি থেকে মিডিয়া সেশনকে আলাদাভাবে চালানোর সুযোগ দেয়।

কোনো সার্ভিসের ভেতরে প্লেয়ার হোস্ট করার সময় MediaSessionService ব্যবহার করা উচিত। এটি করার জন্য, MediaSessionService এক্সটেন্ড করে এমন একটি ক্লাস তৈরি করুন এবং এর ভেতরে আপনার মিডিয়া সেশনটি তৈরি করুন।

MediaSessionService ব্যবহার করার ফলে Google Assistant, সিস্টেম মিডিয়া কন্ট্রোল, পেরিফেরাল ডিভাইসের মিডিয়া বাটন, বা Wear OS-এর মতো কম্প্যানিয়ন ডিভাইসের মতো বাহ্যিক ক্লায়েন্টরা আপনার অ্যাপের UI অ্যাক্টিভিটিতে কোনো রকম অ্যাক্সেস ছাড়াই আপনার সার্ভিসটি খুঁজে পেতে, এর সাথে সংযুক্ত হতে এবং প্লেব্যাক নিয়ন্ত্রণ করতে পারে। প্রকৃতপক্ষে, একই MediaSessionService সাথে একই সময়ে একাধিক ক্লায়েন্ট অ্যাপ সংযুক্ত থাকতে পারে, এবং প্রতিটি অ্যাপের নিজস্ব MediaController থাকে।

পরিষেবা জীবনচক্র বাস্তবায়ন করুন

আপনাকে আপনার সার্ভিসের দুটি লাইফসাইকেল মেথড ইমপ্লিমেন্ট করতে হবে:

  • প্রথম কন্ট্রোলারটি সংযোগ স্থাপন করতে যাওয়ার সময় onCreate() কল করা হয় এবং সার্ভিসটি ইনস্ট্যানশিয়েট ও চালু করা হয়। Player এবং MediaSession তৈরি করার জন্য এটিই সেরা জায়গা।
  • সার্ভিসটি বন্ধ করার সময় onDestroy() কল করা হয়। প্লেয়ার এবং সেশন সহ সমস্ত রিসোর্স রিলিজ করা প্রয়োজন।

ব্যবহারকারী যখন সাম্প্রতিক কাজগুলো থেকে অ্যাপটি বাতিল করে দেয়, তখন কী ঘটবে তা কাস্টমাইজ করতে আপনি ঐচ্ছিকভাবে onTaskRemoved(Intent) ওভাররাইড করতে পারেন। ডিফল্টরূপে, প্লেব্যাক চালু থাকলে সার্ভিসটি চলতে থাকে এবং অন্যথায় বন্ধ হয়ে যায়।

কোটলিন

class PlaybackService : MediaSessionService() {
  private var mediaSession: MediaSession? = null

  // Create your Player and MediaSession in the onCreate lifecycle event
  override fun onCreate() {
    super.onCreate()
    val player = ExoPlayer.Builder(this).build()
    mediaSession = MediaSession.Builder(this, player).build()
  }

  // Remember to release the player and media session in onDestroy
  override fun onDestroy() {
    mediaSession?.run {
      player.release()
      release()
      mediaSession = null
    }
    super.onDestroy()
  }

  override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaSession? =
    mediaSession
}

জাভা

class PlaybackService extends MediaSessionService {
  private MediaSession mediaSession = null;

  // Create your Player and MediaSession in the onCreate lifecycle event
  @Override
  public void onCreate() {
    super.onCreate();
    ExoPlayer player = new ExoPlayer.Builder(this).build();
    mediaSession = new MediaSession.Builder(this, player).build();
  }

  // Remember to release the player and media session in onDestroy
  @Override
  public void onDestroy() {
    mediaSession.getPlayer().release();
    mediaSession.release();
    mediaSession = null;
    super.onDestroy();
  }

  @Override
  public MediaSession onGetSession(MediaSession.ControllerInfo controllerInfo) {
    return mediaSession;
  }
}

ব্যাকগ্রাউন্ডে প্লেব্যাক চালু রাখার বিকল্প হিসেবে, ব্যবহারকারী অ্যাপটি বন্ধ করে দিলে আপনি যেকোনো পরিস্থিতিতেই পরিষেবাটি বন্ধ করে দিতে পারেন:

কোটলিন

@OptIn(UnstableApi::class)
override fun onTaskRemoved(rootIntent: Intent?) {
  pauseAllPlayersAndStopSelf()
}

জাভা

@OptIn(markerClass = UnstableApi.class)
@Override
public void onTaskRemoved(@Nullable Intent rootIntent) {
  pauseAllPlayersAndStopSelf();
}

onTaskRemoved এর অন্য যেকোনো ম্যানুয়াল প্রয়োগের ক্ষেত্রে, প্লেব্যাকটি চলমান কিনা এবং ফোরগ্রাউন্ড সার্ভিসটি চালু হয়েছে কিনা তা পরীক্ষা করতে আপনি isPlaybackOngoing() ব্যবহার করতে পারেন।

মিডিয়া সেশনে প্রবেশাধিকার প্রদান করুন

সার্ভিসটি তৈরি করার সময় নির্মিত আপনার মিডিয়া সেশনে অন্যান্য ক্লায়েন্টদের অ্যাক্সেস দেওয়ার জন্য onGetSession() মেথডটি ওভাররাইড করুন।

কোটলিন

class PlaybackService : MediaSessionService() {

  // [...] lifecycle methods omitted

  override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaSession? =
    mediaSession
}

জাভা

class PlaybackService extends MediaSessionService {

  // [...] lifecycle methods omitted

  @Override
  public MediaSession onGetSession(MediaSession.ControllerInfo controllerInfo) {
    return mediaSession;
  }
}

ম্যানিফেস্টে পরিষেবাটি ঘোষণা করুন।

একটি প্লেব্যাক ফোরগ্রাউন্ড সার্ভিস চালানোর জন্য অ্যাপটির FOREGROUND_SERVICE এবং FOREGROUND_SERVICE_MEDIA_PLAYBACK পারমিশন প্রয়োজন:

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />

আপনাকে অবশ্যই ম্যানিফেস্টে আপনার Service ক্লাসটি ডিক্লেয়ার করতে হবে, যার ইন্টেন্ট ফিল্টার হবে MediaSessionService এবং foregroundServiceTypemediaPlayback অন্তর্ভুক্ত থাকবে।

<service
    android:name=".PlaybackService"
    android:foregroundServiceType="mediaPlayback"
    android:exported="true">
    <intent-filter>
        <action android:name="androidx.media3.session.MediaSessionService"/>
        <action android:name="android.media.browse.MediaBrowserService"/>
    </intent-filter>
</service>

MediaController ব্যবহার করে প্লেব্যাক নিয়ন্ত্রণ করুন

আপনার প্লেয়ার UI ধারণকারী অ্যাক্টিভিটি বা ফ্র্যাগমেন্টে, আপনি একটি MediaController ব্যবহার করে UI এবং আপনার মিডিয়া সেশনের মধ্যে একটি সংযোগ স্থাপন করতে পারেন। আপনার UI, সেশনের মধ্যে থাকা প্লেয়ারে UI থেকে কমান্ড পাঠানোর জন্য মিডিয়া কন্ট্রোলার ব্যবহার করে। একটি MediaController তৈরি এবং ব্যবহার করার বিষয়ে বিস্তারিত জানতে "Create a MediaController গাইডটি দেখুন।

MediaController কমান্ড পরিচালনা করুন

MediaSession তার MediaSession.Callback এর মাধ্যমে কন্ট্রোলার থেকে কমান্ড গ্রহণ করে। একটি MediaSession ইনিশিয়ালাইজ করলে MediaSession.Callback এর একটি ডিফল্ট ইমপ্লিমেন্টেশন তৈরি হয়, যা একটি MediaController থেকে আপনার প্লেয়ারে পাঠানো সমস্ত কমান্ড স্বয়ংক্রিয়ভাবে পরিচালনা করে।

বিজ্ঞপ্তি

একটি MediaSessionService স্বয়ংক্রিয়ভাবে আপনার জন্য একটি MediaNotification তৈরি করে, যা বেশিরভাগ ক্ষেত্রেই কাজ করে। ডিফল্টরূপে, প্রকাশিত নোটিফিকেশনটি একটি MediaStyle নোটিফিকেশন হয়, যা আপনার মিডিয়া সেশনের সর্বশেষ তথ্য দিয়ে আপডেট থাকে এবং প্লেব্যাক কন্ট্রোল প্রদর্শন করে। MediaNotification টি আপনার সেশন সম্পর্কে অবগত থাকে এবং একই সেশনে সংযুক্ত অন্য যেকোনো অ্যাপের প্লেব্যাক নিয়ন্ত্রণ করতে এটি ব্যবহার করা যেতে পারে।

উদাহরণস্বরূপ, একটি MediaSessionService ব্যবহারকারী মিউজিক স্ট্রিমিং অ্যাপ আপনার MediaSession কনফিগারেশনের উপর ভিত্তি করে একটি MediaNotification তৈরি করবে, যা বর্তমানে প্লে হওয়া মিডিয়া আইটেমটির টাইটেল, আর্টিস্ট, অ্যালবাম আর্ট এবং প্লেব্যাক কন্ট্রোল প্রদর্শন করবে।

প্রয়োজনীয় মেটাডেটা মিডিয়ার মধ্যেই প্রদান করা যেতে পারে অথবা মিডিয়া আইটেমের অংশ হিসেবে ঘোষণা করা যেতে পারে, যেমনটি নিম্নলিখিত কোড স্নিপেটে দেখানো হয়েছে:

কোটলিন

val mediaItem =
  MediaItem.Builder()
    .setMediaId("media-1")
    .setUri(mediaUri)
    .setMediaMetadata(
      MediaMetadata.Builder()
        .setArtist("David Bowie")
        .setTitle("Heroes")
        .setArtworkUri(artworkUri)
        .build()
    )
    .build()

mediaController.setMediaItem(mediaItem)
mediaController.prepare()
mediaController.play()

জাভা

MediaItem mediaItem =
    new MediaItem.Builder()
        .setMediaId("media-1")
        .setUri(mediaUri)
        .setMediaMetadata(
            new MediaMetadata.Builder()
                .setArtist("David Bowie")
                .setTitle("Heroes")
                .setArtworkUri(artworkUri)
                .build())
        .build();

mediaController.setMediaItem(mediaItem);
mediaController.prepare();
mediaController.play();

বিজ্ঞপ্তির জীবনচক্র

Player প্লেলিস্টে MediaItem ইনস্ট্যান্স থাকলেই নোটিফিকেশনটি তৈরি হয়।

Player এবং MediaSession অবস্থার উপর ভিত্তি করে সমস্ত নোটিফিকেশন আপডেট স্বয়ংক্রিয়ভাবে সম্পন্ন হয়।

ফোরগ্রাউন্ড সার্ভিসটি চালু থাকা অবস্থায় নোটিফিকেশনটি সরানো যাবে না। নোটিফিকেশনটি তাৎক্ষণিকভাবে সরাতে, আপনাকে অবশ্যই Player.release() কল করতে হবে অথবা Player.clearMediaItems() ব্যবহার করে প্লেলিস্টটি খালি করতে হবে।

যদি ব্যবহারকারীর আর কোনো কার্যকলাপ ছাড়া প্লেয়ারটি ১০ মিনিটের বেশি সময় ধরে পজ, স্টপ বা ফেইল হয়ে থাকে, তাহলে সার্ভিসটি স্বয়ংক্রিয়ভাবে ফোরগ্রাউন্ড সার্ভিস স্টেট থেকে বেরিয়ে যায়, যাতে সিস্টেম এটিকে ডেস্ট্রয় করতে পারে। আপনি প্লেব্যাক রিজাম্পশন (playback resumption) প্রয়োগ করতে পারেন, যা ব্যবহারকারীকে সার্ভিসের লাইফসাইকেল পুনরায় শুরু করতে এবং পরবর্তী কোনো সময়ে প্লেব্যাক আবার চালু করার সুযোগ দেবে।

বিজ্ঞপ্তি কাস্টমাইজেশন

MediaItem.MediaMetadata পরিবর্তন করে বর্তমানে প্লে হওয়া আইটেমটির মেটাডেটা কাস্টমাইজ করা যায়। যদি আপনি কোনো চলমান আইটেমের মেটাডেটা আপডেট করতে চান, তাহলে প্লেব্যাক বন্ধ না করেই মেটাডেটা আপডেট করার জন্য Player.replaceMediaItem ব্যবহার করতে পারেন।

অ্যান্ড্রয়েড মিডিয়া কন্ট্রোলের জন্য কাস্টম মিডিয়া বাটন প্রেফারেন্স সেট করার মাধ্যমে আপনি নোটিফিকেশনে দেখানো কিছু বাটনও কাস্টমাইজ করতে পারেন। অ্যান্ড্রয়েড মিডিয়া কন্ট্রোল কাস্টমাইজ করা সম্পর্কে আরও পড়ুন

নোটিফিকেশনটিকে আরও কাস্টমাইজ করতে, DefaultMediaNotificationProvider.Builder ব্যবহার করে অথবা প্রোভাইডার ইন্টারফেসের একটি কাস্টম ইমপ্লিমেন্টেশন তৈরি করে একটি MediaNotification.Provider তৈরি করুন। setMediaNotificationProvider ব্যবহার করে আপনার প্রোভাইডারটিকে MediaSessionService এ যুক্ত করুন।

প্লেব্যাক পুনরায় শুরু

MediaSessionService বন্ধ হয়ে যাওয়ার পরেও, এমনকি ডিভাইসটি রিবুট করার পরেও, ব্যবহারকারীদের সার্ভিসটি পুনরায় চালু করে যেখান থেকে প্লেব্যাক ছেড়েছিলেন সেখান থেকে আবার শুরু করার সুযোগ দেওয়া সম্ভব। ডিফল্টরূপে, প্লেব্যাক পুনরায় শুরু করার সুবিধাটি বন্ধ থাকে। এর মানে হলো, আপনার সার্ভিসটি চালু না থাকলে ব্যবহারকারী প্লেব্যাক আবার শুরু করতে পারবেন না। এই ফিচারটি চালু করতে, আপনাকে একটি মিডিয়া বাটন রিসিভার ডিক্লেয়ার করতে হবে এবং onPlaybackResumption মেথডটি ইমপ্লিমেন্ট করতে হবে।

Media3 মিডিয়া বাটন রিসিভার ঘোষণা করুন

আপনার ম্যানিফেস্টে MediaButtonReceiver ঘোষণা করে শুরু করুন:

<receiver android:name="androidx.media3.session.MediaButtonReceiver"
  android:exported="true">
  <intent-filter>
    <action android:name="android.intent.action.MEDIA_BUTTON" />
  </intent-filter>
</receiver>

প্লেব্যাক পুনরায় শুরু করার কলব্যাক বাস্তবায়ন করুন

যখন কোনো ব্লুটুথ ডিভাইস অথবা অ্যান্ড্রয়েড সিস্টেম UI-এর প্লেব্যাক পুনরায় শুরু করার ফিচারের মাধ্যমে অনুরোধ করা হয়, তখন onPlaybackResumption() কলব্যাক মেথডটি কল করা হয়।

কোটলিন

override fun onPlaybackResumption(
  mediaSession: MediaSession,
  controller: MediaSession.ControllerInfo,
  isForPlayback: Boolean,
): ListenableFuture<MediaSession.MediaItemsWithStartPosition> {
  val settableFuture = SettableFuture.create<MediaSession.MediaItemsWithStartPosition>()
  settableFuture.addListener(
    {
      // Your app is responsible for storing the playlist, metadata (like title
      // and artwork) of the current item and the start position to use here.
      val resumptionPlaylist = restorePlaylist()
      settableFuture.set(resumptionPlaylist)
    },
    MoreExecutors.directExecutor(),
  )
  return settableFuture
}

জাভা

@Override
public ListenableFuture<MediaItemsWithStartPosition> onPlaybackResumption(
    MediaSession mediaSession, ControllerInfo controller, boolean isForPlayback) {
  SettableFuture<MediaItemsWithStartPosition> settableFuture = SettableFuture.create();
  settableFuture.addListener(
      () -> {
        // Your app is responsible for storing the playlist, metadata (like title
        // and artwork) of the current item and the start position to use here.
        MediaItemsWithStartPosition resumptionPlaylist = restorePlaylist();
        settableFuture.set(resumptionPlaylist);
      },
      MoreExecutors.directExecutor());
  return settableFuture;
}

যদি আপনি প্লেব্যাক স্পিড, রিপিট মোড বা শাফেল মোডের মতো অন্যান্য প্যারামিটার সংরক্ষণ করে থাকেন, তাহলে কলব্যাকটি সম্পূর্ণ হওয়ার পর Media3 প্লেয়ারকে প্রস্তুত করে প্লেব্যাক শুরু করার আগে, onPlaybackResumption() ফাংশনটিতে এই প্যারামিটারগুলো দিয়ে প্লেয়ারকে কনফিগার করা একটি ভালো জায়গা।

isForPlayback false সেট করে ডিভাইস রিবুট করার পর অ্যান্ড্রয়েড সিস্টেম UI পুনরায় চালু হওয়ার নোটিফিকেশন তৈরি করতে এই মেথডটি বুট টাইমে কল করা হয়। একটি রিচ নোটিফিকেশনের জন্য, বর্তমান আইটেমের title এবং artworkData বা artworkUri এর মতো MediaMetadata ফিল্ডগুলো স্থানীয়ভাবে উপলব্ধ ভ্যালু দিয়ে পূরণ করার পরামর্শ দেওয়া হয়, কারণ তখনও নেটওয়ার্ক অ্যাক্সেস উপলব্ধ নাও থাকতে পারে। এছাড়াও, পুনরায় চালু হওয়া প্লেব্যাকের অবস্থান নির্দেশ করতে আপনি MediaMetadata.extrasMediaConstants.EXTRAS_KEY_COMPLETION_STATUS এবং MediaConstants.EXTRAS_KEY_COMPLETION_PERCENTAGE যোগ করতে পারেন।

উন্নত কন্ট্রোলার কনফিগারেশন এবং পূর্ববর্তী সংস্করণের সাথে সামঞ্জস্যতা

একটি সাধারণ দৃশ্যকল্প হলো অ্যাপের UI-তে প্লেব্যাক নিয়ন্ত্রণ এবং প্লেলিস্ট প্রদর্শনের জন্য MediaController ব্যবহার করা। একই সাথে, সেশনটি মোবাইল বা টিভির অ্যান্ড্রয়েড মিডিয়া কন্ট্রোল ও অ্যাসিস্ট্যান্ট, ঘড়ির জন্য Wear OS এবং গাড়ির অ্যান্ড্রয়েড অটোর মতো বাহ্যিক ক্লায়েন্টদের কাছে উন্মুক্ত থাকে। Media3 সেশন ডেমো অ্যাপটি এমন একটি দৃশ্যকল্প বাস্তবায়নকারী অ্যাপের উদাহরণ।

এই বাহ্যিক ক্লায়েন্টরা লিগ্যাসি AndroidX লাইব্রেরির MediaControllerCompat অথবা অ্যান্ড্রয়েড প্ল্যাটফর্মের android.media.session.MediaController এর মতো এপিআই ব্যবহার করতে পারে। Media3 লিগ্যাসি লাইব্রেরির সাথে সম্পূর্ণরূপে ব্যাকওয়ার্ড কম্প্যাটিবল এবং অ্যান্ড্রয়েড প্ল্যাটফর্ম এপিআই-এর সাথে ইন্টারঅপারেবিলিটি প্রদান করে।

বিশ্বস্ত নিয়ন্ত্রকদের সনাক্ত করুন

যেকোনো অ্যাপ আপনার মিডিয়া সেশন বা লাইব্রেরিতে সংযোগ করার চেষ্টা করতে পারে। আপনি যদি সিস্টেম কন্ট্রোলার, মিডিয়া কন্টেন্ট নিয়ন্ত্রণের অনুমতি থাকা কন্ট্রোলার এবং আপনার নিজের অ্যাপের অ্যাক্সেস সীমাবদ্ধ করতে চান, তাহলে একটি সাধারণ অ্যাক্সেস যাচাইয়ের জন্য ControllerInfo.isTrusted() ব্যবহার করতে পারেন। বিকল্পভাবে, আপনি পরবর্তী বিভাগগুলিতে বর্ণিত পদ্ধতি অনুযায়ী মিডিয়া নোটিফিকেশন কন্ট্রোলার বা অ্যান্ড্রয়েড অটো কন্ট্রোলারের মতো আরও নির্দিষ্ট কন্ট্রোলার শনাক্ত করতে পারেন।

মিডিয়া নোটিফিকেশন কন্ট্রোলার ব্যবহার করুন

এটা বোঝা গুরুত্বপূর্ণ যে এই লিগ্যাসি এবং প্ল্যাটফর্ম কন্ট্রোলারগুলো একই স্টেট শেয়ার করে এবং কন্ট্রোলার দ্বারা ভিজিবিলিটি কাস্টমাইজ করা যায় না (উদাহরণস্বরূপ, উপলব্ধ PlaybackState.getActions() এবং PlaybackState.getCustomActions() )। এই লিগ্যাসি এবং প্ল্যাটফর্ম কন্ট্রোলারগুলোর সাথে সামঞ্জস্যতা বজায় রাখার জন্য, আপনি প্ল্যাটফর্ম মিডিয়া সেশনে সেট করা স্টেট কনফিগার করতে মিডিয়া নোটিফিকেশন কন্ট্রোলার ব্যবহার করতে পারেন।

উদাহরণস্বরূপ, একটি অ্যাপ প্ল্যাটফর্ম সেশনের জন্য বিশেষভাবে উপলব্ধ কমান্ড এবং মিডিয়া বোতামের পছন্দগুলি সেট করতে MediaSession.Callback.onConnect() এর একটি বাস্তবায়ন নিম্নরূপভাবে প্রদান করতে পারে:

কোটলিন

override fun onConnectAsync(
  session: MediaSession,
  controller: MediaSession.ControllerInfo,
): ListenableFuture<ConnectionResult> {
  if (session.isMediaNotificationController(controller)) {
    val playerCommands =
      ConnectionResult.DEFAULT_PLAYER_COMMANDS.buildUpon()
        .remove(COMMAND_SEEK_TO_PREVIOUS)
        .remove(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM)
        .remove(COMMAND_SEEK_TO_NEXT)
        .remove(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM)
        .build()
    // Custom button preferences and commands to configure the platform session.
    return immediateFuture(
      AcceptedResultBuilder(session, controller)
        .setMediaButtonPreferences(listOf(seekBackButton, seekForwardButton))
        .setAvailablePlayerCommands(playerCommands)
        .build()
    )
  }
  // Default commands with default button preferences for all other controllers.
  return immediateFuture(AcceptedResultBuilder(session, controller).build())
}

জাভা

@Override
public ListenableFuture<ConnectionResult> onConnectAsync(
    MediaSession session, MediaSession.ControllerInfo controller) {
  if (session.isMediaNotificationController(controller)) {
    Player.Commands playerCommands =
        ConnectionResult.DEFAULT_PLAYER_COMMANDS
            .buildUpon()
            .remove(COMMAND_SEEK_TO_PREVIOUS)
            .remove(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM)
            .remove(COMMAND_SEEK_TO_NEXT)
            .remove(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM)
            .build();
    // Custom button preferences and commands to configure the platform session.
    return immediateFuture(
        new AcceptedResultBuilder(session, controller)
            .setMediaButtonPreferences(ImmutableList.of(seekBackButton, seekForwardButton))
            .setAvailablePlayerCommands(playerCommands)
            .build());
  }
  // Default commands with default button preferences for all other controllers.
  return immediateFuture(new AcceptedResultBuilder(session, controller).build());
}

কাস্টম কমান্ড পাঠানোর জন্য অ্যান্ড্রয়েড অটোকে অনুমোদন দিন

MediaLibraryService ব্যবহার করার সময় এবং মোবাইল অ্যাপের সাথে Android Auto সমর্থন করার জন্য, Android Auto কন্ট্রোলারে উপযুক্ত কমান্ড উপলব্ধ থাকা প্রয়োজন, অন্যথায় Media3 সেই কন্ট্রোলার থেকে আগত কাস্টম কমান্ড প্রত্যাখ্যান করবে:

কোটলিন

override fun onConnectAsync(
  session: MediaSession,
  controller: MediaSession.ControllerInfo,
): ListenableFuture<ConnectionResult> {
  val sessionCommands =
    ConnectionResult.DEFAULT_SESSION_COMMANDS.buildUpon().add(customCommand).build()
  if (session.isMediaNotificationController(controller)) {
    // ... See above.
  } else if (session.isAutoCompanionController(controller)) {
    // Available commands to accept incoming custom commands from Auto.
    return immediateFuture(
      AcceptedResultBuilder(session, controller)
        .setAvailableSessionCommands(sessionCommands)
        .build()
    )
  }
  // Default commands for all other controllers.
  return immediateFuture(AcceptedResultBuilder(session, controller).build())
}

জাভা

@Override
public ListenableFuture<ConnectionResult> onConnectAsync(
    MediaSession session, MediaSession.ControllerInfo controller) {
  SessionCommands sessionCommands =
      ConnectionResult.DEFAULT_SESSION_COMMANDS.buildUpon().add(customCommand).build();
  if (session.isMediaNotificationController(controller)) {
    // ... See above.
  } else if (session.isAutoCompanionController(controller)) {
    // Available commands to accept incoming custom commands from Auto.
    return immediateFuture(
        new AcceptedResultBuilder(session, controller)
            .setAvailableSessionCommands(sessionCommands)
            .build());
  }
  // Default commands for all other controllers.
  return immediateFuture(new AcceptedResultBuilder(session, controller).build());
}

সেশন ডেমো অ্যাপটিতে একটি অটোমোটিভ মডিউল রয়েছে, যা অটোমোটিভ ওএস-এর জন্য সমর্থন প্রদর্শন করে এবং এর জন্য একটি পৃথক এপিকে প্রয়োজন।