You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何使用Media3(搭配ExoPlayer + MediaSessionService)?基于Media3实现MediaSessionService搭建简易音频播放应用遇阻求助

Hey there! Let me walk you through building a minimal audio playback app with Media3's ExoPlayer and MediaSessionService step by step — I’ve struggled with the sparse docs too, so I’ll keep this as straightforward as possible.

1. Add Media3 Dependencies

First, add the necessary Media3 libraries to your app-level build.gradle (or build.gradle.kts):

dependencies {
    // Media3 core components
    implementation "androidx.media3:media3-exoplayer:1.2.1"
    implementation "androidx.media3:media3-session:1.2.1"
    implementation "androidx.media3:media3-common:1.2.1"
}

(Note: Use the latest version number instead of 1.2.1 if available)

2. Implement the MediaSessionService

Create a custom service that extends MediaSessionService — this is the core of your media session handling:

import android.content.Intent
import androidx.media3.common.MediaItem
import androidx.media3.common.Player
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.session.MediaSession
import androidx.media3.session.MediaSessionService

class MyMediaSessionService : MediaSessionService() {
    private lateinit var player: ExoPlayer
    private lateinit var mediaSession: MediaSession

    override fun onCreate() {
        super.onCreate()
        // Initialize ExoPlayer with proper audio attributes
        player = ExoPlayer.Builder(this).build()
        player.setAudioAttributes(
            androidx.media3.common.AudioAttributes.Builder()
                .setContentType(androidx.media3.common.C.AUDIO_CONTENT_TYPE_MUSIC)
                .setUsage(androidx.media3.common.C.USAGE_MEDIA)
                .build(),
            true
        )

        // Link ExoPlayer to MediaSession
        mediaSession = MediaSession.Builder(this, player).build()
        // Handle core playback commands via session callback
        mediaSession.setCallback(object : MediaSession.Callback {
            override fun onPlay() {
                player.play()
                // Start foreground service to avoid being killed on Android 8.0+
                startForeground(1, 
                    androidx.core.app.NotificationCompat.Builder(this@MyMediaSessionService, "media_playback_channel")
                        .setContentTitle("Now Playing")
                        .setSmallIcon(R.drawable.ic_music_note)
                        .setStyle(androidx.media3.session.MediaStyleNotificationHelper.MediaStyle(mediaSession))
                        .build()
                )
            }

            override fun onPause() {
                player.pause()
                stopForeground(STOP_FOREGROUND_REMOVE)
            }

            override fun onAddMediaItems(
                mediaSession: MediaSession,
                controller: MediaSession.ControllerInfo,
                mediaItems: MutableList<MediaItem>
            ): MediaSession.MediaItemsHolder {
                // Replace with your actual audio URI (local file or remote URL)
                val updatedItems = mediaItems.map {
                    it.buildUpon().setUri("https://example.com/your-audio-file.mp3").build()
                }
                return MediaSession.MediaItemsHolder(updatedItems)
            }
        })
    }

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

    override fun onDestroy() {
        mediaSession.release()
        player.release()
        super.onDestroy()
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        return START_STICKY
    }
}

Key Takeaways:

  • Audio attributes ensure proper handling of audio focus (e.g., pausing when a call comes in).
  • The foreground service is mandatory for background playback on newer Android versions.
  • The callback bridges user commands (play/pause) to ExoPlayer actions.

3. Configure the Service in AndroidManifest.xml

Don’t forget to register your service and add required permissions:

<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
<uses-permission android:name="android.permission.INTERNET" /> <!-- Required for remote audio -->

<application ...>
    <service
        android:name=".MyMediaSessionService"
        android:foregroundServiceType="mediaPlayback"
        android:exported="true">
        <intent-filter>
            <action android:name="androidx.media3.session.MediaSessionService" />
        </intent-filter>
    </service>
</application>

(Note: For Android 8.0+, you’ll need to create a notification channel — add this snippet to your app’s Application class or initial activity)

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    val channel = NotificationChannel(
        "media_playback_channel",
        "Media Playback",
        NotificationManager.IMPORTANCE_LOW
    )
    getSystemService(NotificationManager::class.java).createNotificationChannel(channel)
}

4. Build a Minimal UI Activity

Create a simple activity with play/pause buttons to control playback via MediaController:

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.media3.session.MediaController
import androidx.media3.session.SessionToken
import com.google.common.util.concurrent.ListenableFuture
import com.google.common.util.concurrent.MoreExecutors
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {
    private lateinit var controllerFuture: ListenableFuture<MediaController>

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Connect to the MediaSessionService
        val sessionToken = SessionToken(this, ComponentName(this, MyMediaSessionService::class.java))
        controllerFuture = MediaController.Builder(this, sessionToken).buildAsync()
        
        controllerFuture.addListener({
            val controller = controllerFuture.get()
            // Link buttons to controller commands
            btn_play.setOnClickListener {
                controller.play()
            }
            btn_pause.setOnClickListener {
                controller.pause()
            }
            // Add your audio media item to the queue
            controller.addMediaItem(MediaItem.fromUri("https://example.com/your-audio-file.mp3"))
        }, MoreExecutors.directExecutor())
    }

    override fun onDestroy() {
        MediaController.releaseFuture(controllerFuture)
        super.onDestroy()
    }
}

The corresponding layout (activity_main.xml) only needs two buttons with IDs btn_play and btn_pause.

Common Troubleshooting Tips

  • Service not connecting? Double-check the SessionToken uses the correct service class name, and the manifest intent-filter is set properly.
  • Audio not playing? Verify your audio URI is valid, and you’ve added the INTERNET permission for remote files.
  • Foreground notification missing? Ensure you’ve created the required notification channel for Android 8.0+.
  • Player crashing on release? Make sure you only call player.release() in the service’s onDestroy() method, not elsewhere.

That’s it! This should give you a working minimal audio app with Media3’s ExoPlayer and MediaSessionService. Let me know if you hit any specific snags — I’m happy to help debug further.

内容的提问来源于stack exchange,提问作者max

火山引擎 最新活动