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

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

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

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

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

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

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

সেবা জীবনচক্র বাস্তবায়ন

আপনাকে আপনার পরিষেবার দুটি জীবনচক্র পদ্ধতি প্রয়োগ করতে হবে:

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

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

কোটলিন

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

  // Create your player and media session 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()
  }
}

জাভা

public 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 fun onTaskRemoved(rootIntent: Intent?) {
  pauseAllPlayersAndStopSelf()
}

জাভা

@Override
public void onTaskRemoved(@Nullable Intent rootIntent) {
  pauseAllPlayersAndStopSelf();
}

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

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

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

কোটলিন

class PlaybackService : MediaSessionService() {
  private var mediaSession: MediaSession? = null
  // [...] lifecycle methods omitted

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

জাভা

public class PlaybackService extends MediaSessionService {
  private MediaSession mediaSession = null;
  // [...] 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" />

আপনাকে অবশ্যই MediaSessionService এর একটি উদ্দেশ্য ফিল্টার এবং একটি foregroundServiceType যাতে mediaPlayback অন্তর্ভুক্ত থাকে ম্যানিফেস্টে আপনার Service শ্রেণী ঘোষণা করতে হবে।

<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 তৈরি এবং ব্যবহার করার বিষয়ে বিস্তারিত জানার জন্য একটি MediaController তৈরি করুন নির্দেশিকা দেখুন।

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

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

বিজ্ঞপ্তি

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

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

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

কোটলিন

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() ব্যবহার করে প্লেলিস্টটি সাফ করতে হবে।

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

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

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

আপনি Android মিডিয়া নিয়ন্ত্রণের জন্য কাস্টম মিডিয়া বোতাম পছন্দগুলি সেট করে বিজ্ঞপ্তিতে দেখানো কিছু বোতাম কাস্টমাইজ করতে পারেন। অ্যান্ড্রয়েড মিডিয়া নিয়ন্ত্রণগুলি কাস্টমাইজ করার বিষয়ে আরও পড়ুন

বিজ্ঞপ্তিটিকে আরও কাস্টমাইজ করতে, 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: ControllerInfo
): ListenableFuture<MediaItemsWithStartPosition> {
  val settable = SettableFuture.create<MediaItemsWithStartPosition>()
  scope.launch {
    // Your app is responsible for storing the playlist and the start position
    // to use here
    val resumptionPlaylist = restorePlaylist()
    settable.set(resumptionPlaylist)
  }
  return settable
}

জাভা

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

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

উন্নত নিয়ামক কনফিগারেশন এবং পশ্চাদপদ সামঞ্জস্য

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

এই বহিরাগত ক্লায়েন্টরা লিগ্যাসি AndroidX লাইব্রেরির MediaControllerCompat বা Android প্ল্যাটফর্মের android.media.session.MediaController এর মতো API ব্যবহার করতে পারে৷ Media3 লিগ্যাসি লাইব্রেরির সাথে সম্পূর্ণ পশ্চাদপদ সামঞ্জস্যপূর্ণ এবং অ্যান্ড্রয়েড প্ল্যাটফর্ম API এর সাথে আন্তঃঅপারেবিলিটি প্রদান করে।

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

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

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

কোটলিন

override fun onConnect(
  session: MediaSession,
  controller: MediaSession.ControllerInfo
): ConnectionResult {
  if (session.isMediaNotificationController(controller)) {
    val sessionCommands =
      ConnectionResult.DEFAULT_SESSION_COMMANDS.buildUpon()
        .add(customCommandSeekBackward)
        .add(customCommandSeekForward)
        .build()
    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 AcceptedResultBuilder(session)
      .setMediaButtonPreferences(
        ImmutableList.of(
          createSeekBackwardButton(customCommandSeekBackward),
          createSeekForwardButton(customCommandSeekForward))
      )
      .setAvailablePlayerCommands(playerCommands)
      .setAvailableSessionCommands(sessionCommands)
      .build()
  }
  // Default commands with default button preferences for all other controllers.
  return AcceptedResultBuilder(session).build()
}

জাভা

@Override
public ConnectionResult onConnect(
    MediaSession session, MediaSession.ControllerInfo controller) {
  if (session.isMediaNotificationController(controller)) {
    SessionCommands sessionCommands =
        ConnectionResult.DEFAULT_SESSION_COMMANDS
            .buildUpon()
            .add(customCommandSeekBackward)
            .add(customCommandSeekForward)
            .build();
    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 new AcceptedResultBuilder(session)
        .setMediaButtonPreferences(
            ImmutableList.of(
                createSeekBackwardButton(customCommandSeekBackward),
                createSeekForwardButton(customCommandSeekForward)))
        .setAvailablePlayerCommands(playerCommands)
        .setAvailableSessionCommands(sessionCommands)
        .build();
  }
  // Default commands with default button preferences for all other controllers.
  return new AcceptedResultBuilder(session).build();
}

কাস্টম কমান্ড পাঠাতে Android Auto অনুমোদন করুন

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

কোটলিন

override fun onConnect(
  session: MediaSession,
  controller: MediaSession.ControllerInfo
): ConnectionResult {
  val sessionCommands =
    ConnectionResult.DEFAULT_SESSION_AND_LIBRARY_COMMANDS.buildUpon()
      .add(customCommandSeekBackward)
      .add(customCommandSeekForward)
      .build()
  if (session.isMediaNotificationController(controller)) {
    // [...] See above.
  } else if (session.isAutoCompanionController(controller)) {
    // Available session commands to accept incoming custom commands from Auto.
    return AcceptedResultBuilder(session)
      .setAvailableSessionCommands(sessionCommands)
      .build()
  }
  // Default commands for all other controllers.
  return AcceptedResultBuilder(session).build()
}

জাভা

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

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