This code is part of an Android application that manages video playback with different audio tracks and playback qualities. It uses the NewPipe Extractor library to extract audio and video streams.

Explanation of the main parts of the code:

1. Definition and initialization of context menus

private static final int POPUP_MENU_ID_AUDIO_TRACK = 70;
private PopupMenu audioTrackPopupMenu;
audioTrackPopupMenu = new PopupMenu(themeWrapper, binding.audioTrackTextView);
binding.audioTrackTextView.setOnClickListener(
                makeOnClickListener(this::onAudioTracksClicked));
binding.audioTrackTextView.setOnClickListener(null);
  • Defines a constant ID for the audio track menu.
  • Initializes a PopupMenu for selecting audio tracks.
  • Attaches an event handler to audioTrackTextView to open the menu when clicked.
  • There is redundancy in setOnClickListener, as the second line cancels the listener.

2. Setting margins and sizes for interface elements

protected void setupElementsSize(final int buttonsMinWidth,
                                 final int playerTopPad,
                                 final int controlsPad,
                                 final int buttonsPad) {
    binding.topControls.setPaddingRelative(controlsPad, playerTopPad, controlsPad, 0);
    binding.bottomControls.setPaddingRelative(controlsPad, 0, controlsPad, 0);
    binding.qualityTextView.setPadding(buttonsPad, buttonsPad, buttonsPad, buttonsPad);
    binding.audioTrackTextView.setPadding(buttonsPad, buttonsPad, buttonsPad, buttonsPad);
    binding.playbackSpeed.setPadding(buttonsPad, buttonsPad, buttonsPad, buttonsPad);
    binding.playbackSpeed.setMinimumWidth(buttonsMinWidth);
    binding.captionTextView.setPadding(buttonsPad, buttonsPad, buttonsPad, buttonsPad);
}
  • Configures the spacing and minimum size for user interface elements, including buttons and text related to video quality, playback speed, subtitles, and audio track selection.

3. Building the audio track menu

private void buildAudioTrackMenu() {
    if (audioTrackPopupMenu == null) {
        return;
    }
    audioTrackPopupMenu.getMenu().removeGroup(POPUP_MENU_ID_AUDIO_TRACK);
  • Checks if the menu is initialized. If not, it does nothing.
  • Removes old entries from the menu to avoid duplicates.
    final List<AudioStream> availableStreams = Optional.ofNullable(player.getCurrentMetadata())
            .flatMap(MediaItemTag::getMaybeAudioTrack)
            .map(MediaItemTag.AudioTrack::getAudioStreams)
            .orElse(null);
    if (availableStreams == null || availableStreams.size() < 2) {
        return;
    }
  • Retrieves the available audio tracks through the player's metadata.
  • If fewer than 2 tracks are available, the menu is not displayed.
    for (int i = 0; i < availableStreams.size(); i++) {
        final AudioStream audioStream = availableStreams.get(i);
        audioTrackPopupMenu.getMenu().add(POPUP_MENU_ID_AUDIO_TRACK, i, Menu.NONE,
                Localization.audioTrackName(context, audioStream));
    }
  • Adds each audio track to the context menu.
    player.getSelectedAudioStream()
            .ifPresent(s -> binding.audioTrackTextView.setText(
                    Localization.audioTrackName(context, s)));
    binding.audioTrackTextView.setVisibility(View.VISIBLE);
    audioTrackPopupMenu.setOnMenuItemClickListener(this);
    audioTrackPopupMenu.setOnDismissListener(this);
}
  • Displays the selected audio track in audioTrackTextView.
  • Makes the menu visible and attaches listeners to handle interactions.

4. Displaying the audio track selection menu

private void onAudioTracksClicked() {
    audioTrackPopupMenu.show();
    isSomePopupMenuVisible = true;
}
  • Displays the context menu when the audio track button is clicked.

⚠️ Error in the code: onAudioTracksClicked() is defined twice, which is redundant.


5. Changing video quality

private void onQualityItemClick(@NonNull final MenuItem menuItem) {
    final int menuItemIndex = menuItem.getItemId();
    @Nullable final MediaItemTag currentMetadata = player.getCurrentMetadata();
    if (currentMetadata == null || currentMetadata.getMaybeQuality().isEmpty()) {
        return;
    }
  • Checks if video quality metadata is available.
    final MediaItemTag.Quality quality = currentMetadata.getMaybeQuality().get();
    final List<VideoStream> availableStreams = quality.getSortedVideoStreams();
    final int selectedStreamIndex = quality.getSelectedVideoStreamIndex();
    if (selectedStreamIndex == menuItemIndex || availableStreams.size() <= menuItemIndex) {
        return;
    }
  • Retrieves the list of available video qualities and prevents selecting the already active quality.
    final String newResolution = availableStreams.get(menuItemIndex).getResolution();
    player.setPlaybackQuality(newResolution);
    binding.qualityTextView.setText(menuItem.getTitle());
}
  • Changes the playback quality and updates the display.

6. Changing audio track

private void onAudioTrackItemClick(@NonNull final MenuItem menuItem) {
    final int menuItemIndex = menuItem.getItemId();
    @Nullable final MediaItemTag currentMetadata = player.getCurrentMetadata();
    if (currentMetadata == null || currentMetadata.getMaybeAudioTrack().isEmpty()) {
        return;
    }
  • Checks if audio track metadata is available.
    final MediaItemTag.AudioTrack audioTrack =
            currentMetadata.getMaybeAudioTrack().get();
    final List<AudioStream> availableStreams = audioTrack.getAudioStreams();
    final int selectedStreamIndex = audioTrack.getSelectedAudioStreamIndex();
    if (selectedStreamIndex == menuItemIndex || availableStreams.size() <= menuItemIndex) {
        return;
    }
  • Retrieves the available audio tracks and prevents selecting the already active track.
    final String newAudioTrack = availableStreams.get(menuItemIndex).getAudioTrackId();
    player.setAudioTrack(newAudioTrack);
    binding.audioTrackTextView.setText(menuItem.getTitle());
}
  • Changes the audio track and updates the display.

General Summary

  • Managing the audio track context menu: opening, adding available tracks, and selecting.
  • Managing video quality change: selecting a different resolution.
  • User interaction: clicks on elements to open menus and select an option.
  • Using metadata: retrieving available audio and video tracks for dynamic updates.

Errors and possible improvements:

  1. Duplication of the onAudioTracksClicked() method → to be removed.
  2. Check if setOnClickListener(null); is necessary after its initialization.
  3. Better error handling in case of unavailable metadata.

Ce code fait partie d'une application Android qui gère la lecture de vidéos avec différentes pistes audio et qualités de lecture. Il utilise la bibliothèque NewPipe Extractor pour extraire les flux audio et vidéo.

Explication des principales parties du code :

1. Définition et initialisation des menus contextuels

private static final int POPUP_MENU_ID_AUDIO_TRACK = 70;
private PopupMenu audioTrackPopupMenu;
audioTrackPopupMenu = new PopupMenu(themeWrapper, binding.audioTrackTextView);
binding.audioTrackTextView.setOnClickListener(
                makeOnClickListener(this::onAudioTracksClicked));
binding.audioTrackTextView.setOnClickListener(null);
  • Définit un ID constant pour le menu des pistes audio.
  • Initialise un PopupMenu pour la sélection des pistes audio.
  • Attache un gestionnaire d'événements à audioTrackTextView pour ouvrir le menu quand on clique dessus.
  • Il y a une redondance dans setOnClickListener, la deuxième ligne annule l'écouteur.

2. Configuration des marges et tailles des éléments de l'interface

protected void setupElementsSize(final int buttonsMinWidth,
                                 final int playerTopPad,
                                 final int controlsPad,
                                 final int buttonsPad) {
    binding.topControls.setPaddingRelative(controlsPad, playerTopPad, controlsPad, 0);
    binding.bottomControls.setPaddingRelative(controlsPad, 0, controlsPad, 0);
    binding.qualityTextView.setPadding(buttonsPad, buttonsPad, buttonsPad, buttonsPad);
    binding.audioTrackTextView.setPadding(buttonsPad, buttonsPad, buttonsPad, buttonsPad);
    binding.playbackSpeed.setPadding(buttonsPad, buttonsPad, buttonsPad, buttonsPad);
    binding.playbackSpeed.setMinimumWidth(buttonsMinWidth);
    binding.captionTextView.setPadding(buttonsPad, buttonsPad, buttonsPad, buttonsPad);
}
  • Configure l'espacement et la taille minimale des éléments de l'interface utilisateur, notamment les boutons et les textes liés à la qualité vidéo, la vitesse de lecture, les sous-titres et la sélection de piste audio.

3. Construction du menu des pistes audio

private void buildAudioTrackMenu() {
    if (audioTrackPopupMenu == null) {
        return;
    }
    audioTrackPopupMenu.getMenu().removeGroup(POPUP_MENU_ID_AUDIO_TRACK);
  • Vérifie si le menu est initialisé. Si ce n'est pas le cas, il ne fait rien.
  • Supprime les anciennes entrées du menu pour éviter les doublons.
    final List<AudioStream> availableStreams = Optional.ofNullable(player.getCurrentMetadata())
            .flatMap(MediaItemTag::getMaybeAudioTrack)
            .map(MediaItemTag.AudioTrack::getAudioStreams)
            .orElse(null);
    if (availableStreams == null || availableStreams.size() < 2) {
        return;
    }
  • Récupère les pistes audio disponibles via les métadonnées du lecteur.
  • Si moins de 2 pistes sont disponibles, le menu ne s'affiche pas.
    for (int i = 0; i < availableStreams.size(); i++) {
        final AudioStream audioStream = availableStreams.get(i);
        audioTrackPopupMenu.getMenu().add(POPUP_MENU_ID_AUDIO_TRACK, i, Menu.NONE,
                Localization.audioTrackName(context, audioStream));
    }
  • Ajoute chaque piste audio au menu contextuel.
    player.getSelectedAudioStream()
            .ifPresent(s -> binding.audioTrackTextView.setText(
                    Localization.audioTrackName(context, s)));
    binding.audioTrackTextView.setVisibility(View.VISIBLE);
    audioTrackPopupMenu.setOnMenuItemClickListener(this);
    audioTrackPopupMenu.setOnDismissListener(this);
}
  • Affiche la piste audio sélectionnée dans audioTrackTextView.
  • Rend le menu visible et attache des écouteurs pour gérer les interactions.

4. Affichage du menu de sélection des pistes audio

private void onAudioTracksClicked() {
    audioTrackPopupMenu.show();
    isSomePopupMenuVisible = true;
}
  • Affiche le menu contextuel lorsqu'on clique sur le bouton des pistes audio.

⚠️ Erreur dans le code : onAudioTracksClicked() est défini deux fois, ce qui est redondant.


5. Changement de qualité vidéo

private void onQualityItemClick(@NonNull final MenuItem menuItem) {
    final int menuItemIndex = menuItem.getItemId();
    @Nullable final MediaItemTag currentMetadata = player.getCurrentMetadata();
    if (currentMetadata == null || currentMetadata.getMaybeQuality().isEmpty()) {
        return;
    }
  • Vérifie si les métadonnées de qualité vidéo sont disponibles.
    final MediaItemTag.Quality quality = currentMetadata.getMaybeQuality().get();
    final List<VideoStream> availableStreams = quality.getSortedVideoStreams();
    final int selectedStreamIndex = quality.getSelectedVideoStreamIndex();
    if (selectedStreamIndex == menuItemIndex || availableStreams.size() <= menuItemIndex) {
        return;
    }
  • Récupère la liste des qualités vidéo disponibles et empêche de sélectionner la qualité déjà active.
    final String newResolution = availableStreams.get(menuItemIndex).getResolution();
    player.setPlaybackQuality(newResolution);
    binding.qualityTextView.setText(menuItem.getTitle());
}
  • Change la qualité de lecture et met à jour l'affichage.

6. Changement de piste audio

private void onAudioTrackItemClick(@NonNull final MenuItem menuItem) {
    final int menuItemIndex = menuItem.getItemId();
    @Nullable final MediaItemTag currentMetadata = player.getCurrentMetadata();
    if (currentMetadata == null || currentMetadata.getMaybeAudioTrack().isEmpty()) {
        return;
    }
  • Vérifie si les métadonnées des pistes audio sont disponibles.
    final MediaItemTag.AudioTrack audioTrack =
            currentMetadata.getMaybeAudioTrack().get();
    final List<AudioStream> availableStreams = audioTrack.getAudioStreams();
    final int selectedStreamIndex = audioTrack.getSelectedAudioStreamIndex();
    if (selectedStreamIndex == menuItemIndex || availableStreams.size() <= menuItemIndex) {
        return;
    }
  • Récupère les pistes audio disponibles et empêche de sélectionner la piste déjà active.
    final String newAudioTrack = availableStreams.get(menuItemIndex).getAudioTrackId();
    player.setAudioTrack(newAudioTrack);
    binding.audioTrackTextView.setText(menuItem.getTitle());
}
  • Change la piste audio et met à jour l'affichage.

Résumé général

  • Gestion du menu contextuel des pistes audio : ouverture, ajout des pistes disponibles, et sélection.
  • Gestion du changement de qualité vidéo : sélection d'une résolution différente.
  • Interaction utilisateur : clics sur les éléments pour ouvrir les menus et sélectionner une option.
  • Utilisation de métadonnées : récupération des pistes audio et vidéo disponibles pour mise à jour dynamique.

Erreurs et améliorations possibles :

  1. Duplication de la méthode onAudioTracksClicked() → à supprimer.
  2. Vérifier si setOnClickListener(null); est nécessaire après son initialisation.
  3. Meilleure gestion des erreurs en cas de métadonnées indisponibles.