Ya está disponible la segunda Vista previa para desarrolladores de Android 11; pruébala y comparte tus comentarios.

Devoluciones de llamada de sesiones multimedia

Las devoluciones de llamada de sesiones multimedia llaman a métodos en varias API para controlar el reproductor, administrar el foco de audio y comunicarse con la sesión multimedia y el servicio de exploración multimedia. Ten en cuenta que la lógica MediaSession que responde a las devoluciones de llamada debe ser coherente. El comportamiento de la devolución de llamada no debe depender de la identidad del emisor, que podría ser una actividad en la misma app que ejecuta el objeto MediaSession o cualquier otra app con un objeto MediaController conectado a MediaSession.

En la siguiente tabla, se resume la forma en la que se distribuyen estas tareas entre las devoluciones de llamada.

onPlay() onPause() onStop()
Foco de audio requestFocus() y pasa tu OnAudioFocusChangeListener.
Siempre llama a primero y procede solamente si se otorga el foco.
abandonAudioFocus()
Servicio startService() stopSelf()
Sesión multimedia setActive(true)
- Actualiza los metadatos y el estado
- Actualiza los metadatos y el estado setActive(false)
- Actualiza los metadatos y el estado
Implementación del reproductor Inicia el reproductor Pausa el reproductor Detén el reproductor
Demasiado ruidoso Registra tu BroadcastReceiver Anula el registro de tu BroadcastReceiver
Notificaciones startForeground(notification) stopForeground(false) stopForeground(false)

A continuación, se detalla un ejemplo de marco de trabajo para la devolución de llamada:

Kotlin

    private val intentFilter = IntentFilter(ACTION_AUDIO_BECOMING_NOISY)

    // Defined elsewhere...
    private lateinit var afChangeListener: AudioManager.OnAudioFocusChangeListener
    private val myNoisyAudioStreamReceiver = BecomingNoisyReceiver()
    private lateinit var myPlayerNotification: MediaStyleNotification
    private lateinit var mediaSession: MediaSessionCompat
    private lateinit var service: MediaBrowserService
    private lateinit var player: SomeKindOfPlayer

    private lateinit var audioFocusRequest: AudioFocusRequest

    private val callback = object: MediaSessionCompat.Callback() {
        override fun onPlay() {
            val am = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
            // Request audio focus for playback, this registers the afChangeListener

            audioFocusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN).run {
                setOnAudioFocusChangeListener(afChangeListener)
                setAudioAttributes(AudioAttributes.Builder().run {
                    setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                    build()
                })
                build()
            }
            val result = am.requestAudioFocus(audioFocusRequest)
            if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
                // Start the service
                startService(Intent(context, MediaBrowserService::class.java))
                // Set the session active  (and update metadata and state)
                mediaSession.isActive = true
                // start the player (custom call)
                player.start()
                // Register BECOME_NOISY BroadcastReceiver
                registerReceiver(myNoisyAudioStreamReceiver, intentFilter)
                // Put the service in the foreground, post notification
                service.startForeground(id, myPlayerNotification)
            }
        }
    }

    public override fun onStop() {
        val am = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
        // Abandon audio focus
        am.abandonAudioFocusRequest(audioFocusRequest)
        unregisterReceiver(myNoisyAudioStreamReceiver)
        // Stop the service
        service.stopSelf()
        // Set the session inactive  (and update metadata and state)
        mediaSession.isActive = false
        // stop the player (custom call)
        player.stop()
        // Take the service out of the foreground
        service.stopForeground(false)
    }

    public override fun onPause() {
        val am = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
        // Update metadata and state
        // pause the player (custom call)
        player.pause()
        // unregister BECOME_NOISY BroadcastReceiver
        unregisterReceiver(myNoisyAudioStreamReceiver)
        // Take the service out of the foreground, retain the notification
        service.stopForeground(false)
    }
    

Java

    private IntentFilter intentFilter = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);

    // Defined elsewhere...
    private AudioManager.OnAudioFocusChangeListener afChangeListener;
    private BecomingNoisyReceiver myNoisyAudioStreamReceiver = new BecomingNoisyReceiver();
    private MediaStyleNotification myPlayerNotification;
    private MediaSessionCompat mediaSession;
    private MediaBrowserService service;
    private SomeKindOfPlayer player;

    private AudioFocusRequest audioFocusRequest;

    MediaSessionCompat.Callback callback = new
        MediaSessionCompat.Callback() {
            @Override
            public void onPlay() {
                AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
                // Request audio focus for playback, this registers the afChangeListener
                AudioAttributes attrs = new AudioAttributes.Builder()
                        .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                        .build();
                audioFocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
                        .setOnAudioFocusChangeListener(afChangeListener)
                        .setAudioAttributes(attrs)
                        .build();
                int result = am.requestAudioFocus(audioFocusRequest);

                if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
                    // Start the service
                    startService(new Intent(context, MediaBrowserService.class));
                    // Set the session active  (and update metadata and state)
                    mediaSession.setActive(true);
                    // start the player (custom call)
                    player.start();
                    // Register BECOME_NOISY BroadcastReceiver
                    registerReceiver(myNoisyAudioStreamReceiver, intentFilter);
                    // Put the service in the foreground, post notification
                    service.startForeground(id, myPlayerNotification);
                }
            }

            @Override
            public void onStop() {
                AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
                // Abandon audio focus
                am.abandonAudioFocusRequest(audioFocusRequest);
                unregisterReceiver(myNoisyAudioStreamReceiver);
                // Stop the service
                service.stopSelf();
                // Set the session inactive  (and update metadata and state)
                mediaSession.setActive(false);
                // stop the player (custom call)
                player.stop();
                // Take the service out of the foreground
                service.stopForeground(false);
            }

            @Override
            public void onPause() {
                AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
                // Update metadata and state
                // pause the player (custom call)
                player.pause();
                // unregister BECOME_NOISY BroadcastReceiver
                unregisterReceiver(myNoisyAudioStreamReceiver);
                // Take the service out of the foreground, retain the notification
                service.stopForeground(false);
            }
        };