Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 58822bec authored by Previr Rangroo's avatar Previr Rangroo Committed by Mikhail Naganov
Browse files

Add audio presentation interface to Java API



In order to enable applications to query audio sub-selection
information of one audio programme delivered by Next Generation Audio
streams, implement presentation API in MediaExtractor.

Bug: 63901775
Test: make
Change-Id: I2b0bfc5d1089614aa93d58fec99324d7a0ed464b
Signed-off-by: default avatarPrevir Rangroo <prang@dolby.com>
parent 1a68be0f
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -22073,6 +22073,20 @@ package android.media {
    field public static final android.os.Parcelable.Creator<android.media.AudioPlaybackConfiguration> CREATOR;
  }
  public final class AudioPresentation {
    method public java.util.Map<java.util.Locale, java.lang.String> getLabels();
    method public java.util.Locale getLocale();
    method public int getMasteringIndication();
    method public boolean hasAudioDescription();
    method public boolean hasDialogueEnhancement();
    method public boolean hasSpokenSubtitles();
    field public static final int MASTERED_FOR_3D = 3; // 0x3
    field public static final int MASTERED_FOR_HEADPHONE = 4; // 0x4
    field public static final int MASTERED_FOR_STEREO = 1; // 0x1
    field public static final int MASTERED_FOR_SURROUND = 2; // 0x2
    field public static final int MASTERING_NOT_INDICATED = 0; // 0x0
  }
  public class AudioRecord implements android.media.AudioRouting {
    ctor public AudioRecord(int, int, int, int, int) throws java.lang.IllegalArgumentException;
    method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
@@ -22228,6 +22242,7 @@ package android.media {
    method public int setPlaybackRate(int);
    method public int setPositionNotificationPeriod(int);
    method public boolean setPreferredDevice(android.media.AudioDeviceInfo);
    method public int setPresentation(android.media.AudioPresentation);
    method protected deprecated void setState(int);
    method public deprecated int setStereoVolume(float, float);
    method public void setStreamEventCallback(java.util.concurrent.Executor, android.media.AudioTrack.StreamEventCallback);
@@ -23293,6 +23308,7 @@ package android.media {
    ctor public MediaExtractor();
    method public boolean advance();
    method protected void finalize();
    method public java.util.List<android.media.AudioPresentation> getAudioPresentations(int);
    method public long getCachedDuration();
    method public android.media.MediaExtractor.CasInfo getCasInfo(int);
    method public android.media.DrmInitData getDrmInitData();
+13 −0
Original line number Diff line number Diff line
@@ -1228,6 +1228,18 @@ static jobject android_media_AudioTrack_get_volume_shaper_state(JNIEnv *env, job
    return VolumeShaperHelper::convertStateToJobject(env, gVolumeShaperFields, state);
}

static int android_media_AudioTrack_setPresentation(
                                JNIEnv *env,  jobject thiz, jint presentationId, jint programId) {
    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
    if (lpTrack == NULL) {
        jniThrowException(env, "java/lang/IllegalStateException",
            "AudioTrack not initialized");
        return (jint)AUDIO_JAVA_ERROR;
    }

    return (jint)lpTrack->selectPresentation((int)presentationId, (int)programId);
}

// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
static const JNINativeMethod gMethods[] = {
@@ -1297,6 +1309,7 @@ static const JNINativeMethod gMethods[] = {
    {"native_getVolumeShaperState",
            "(I)Landroid/media/VolumeShaper$State;",
                                        (void *)android_media_AudioTrack_get_volume_shaper_state},
    {"native_setPresentation", "(II)I", (void *)android_media_AudioTrack_setPresentation},
};


+181 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.media;

import android.annotation.IntDef;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

import java.util.HashMap;
import java.util.Locale;
import java.util.Map;


/**
 * The AudioPresentation class encapsulates the information that describes an audio presentation
 * which is available in next generation audio content.
 *
 * Used by {@link MediaExtractor} {@link MediaExtractor#getAudioPresentations(int)} and
 * {@link AudioTrack} {@link AudioTrack#setPresentation(AudioPresentation)} to query available
 * presentations and to select one.
 *
 * A list of available audio presentations in a media source can be queried using
 * {@link MediaExtractor#getAudioPresentations(int)}. This list can be presented to a user for
 * selection.
 * An AudioPresentation can be passed to an offloaded audio decoder via
 * {@link AudioTrack#setPresentation(AudioPresentation)} to request decoding of the selected
 * presentation. An audio stream may contain multiple presentations that differ by language,
 * accessibility, end point mastering and dialogue enhancement. An audio presentation may also have
 * a set of description labels in different languages to help the user to make an informed
 * selection.
 */
public final class AudioPresentation {
    private final int mPresentationId;
    private final int mProgramId;
    private final Map<String, String> mLabels;
    private final String mLanguage;

    /** @hide */
    @IntDef(
        value = {
            MASTERING_NOT_INDICATED,
            MASTERED_FOR_STEREO,
            MASTERED_FOR_SURROUND,
            MASTERED_FOR_3D,
            MASTERED_FOR_HEADPHONE,
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface MasteringIndicationType {}

    private final @MasteringIndicationType int mMasteringIndication;
    private final boolean mAudioDescriptionAvailable;
    private final boolean mSpokenSubtitlesAvailable;
    private final boolean mDialogueEnhancementAvailable;

    /**
     * No preferred reproduction channel layout.
     */
    public static final int MASTERING_NOT_INDICATED         = 0;
    /**
     * Stereo speaker layout.
     */
    public static final int MASTERED_FOR_STEREO             = 1;
    /**
     * Two-dimensional (e.g. 5.1) speaker layout.
     */
    public static final int MASTERED_FOR_SURROUND           = 2;
    /**
     * Three-dimensional (e.g. 5.1.2) speaker layout.
     */
    public static final int MASTERED_FOR_3D                 = 3;
    /**
     * Prerendered for headphone playback.
     */
    public static final int MASTERED_FOR_HEADPHONE          = 4;

    AudioPresentation(int presentationId,
                        int programId,
                        Map<String, String> labels,
                        String language,
                        @MasteringIndicationType int masteringIndication,
                        boolean audioDescriptionAvailable,
                        boolean spokenSubtitlesAvailable,
                        boolean dialogueEnhancementAvailable) {
        this.mPresentationId = presentationId;
        this.mProgramId = programId;
        this.mLanguage = language;
        this.mMasteringIndication = masteringIndication;
        this.mAudioDescriptionAvailable = audioDescriptionAvailable;
        this.mSpokenSubtitlesAvailable = spokenSubtitlesAvailable;
        this.mDialogueEnhancementAvailable = dialogueEnhancementAvailable;

        this.mLabels = new HashMap<String, String>(labels);
    }

    /**
     * The framework uses this presentation id to select an audio presentation rendered by a
     * decoder. Presentation id is typically sequential, but does not have to be.
     * @hide
     */
    public int getPresentationId() {
        return mPresentationId;
    }

    /**
     * The framework uses this program id to select an audio presentation rendered by a decoder.
     * Program id can be used to further uniquely identify the presentation to a decoder.
     * @hide
     */
    public int getProgramId() {
        return mProgramId;
    }

    /**
     * @return a map of available text labels for this presentation. Each label is indexed by its
     * locale corresponding to the language code as specified by ISO 639-2 [42]. Either ISO 639-2/B
     * or ISO 639-2/T could be used.
     */
    public Map<Locale, String> getLabels() {
        Map<Locale, String> localeLabels = new HashMap<>();
        for (Map.Entry<String, String> entry : mLabels.entrySet()) {
            localeLabels.put(new Locale(entry.getKey()), entry.getValue());
        }
        return localeLabels;
    }

    /**
     * @return the locale corresponding to audio presentation's ISO 639-1/639-2 language code.
     */
    public Locale getLocale() {
        return new Locale(mLanguage);
    }

    /**
     * @return the mastering indication of the audio presentation.
     * See {@link #MASTERING_NOT_INDICATED}, {@link #MASTERED_FOR_STEREO},
     * {@link #MASTERED_FOR_SURROUND}, {@link #MASTERED_FOR_3D}, {@link #MASTERED_FOR_HEADPHONE}
     */
    @MasteringIndicationType
    public int getMasteringIndication() {
        return mMasteringIndication;
    }

    /**
     * Indicates whether an audio description for the visually impaired is available.
     * @return {@code true} if audio description is available.
     */
    public boolean hasAudioDescription() {
        return mAudioDescriptionAvailable;
    }

    /**
     * Indicates whether spoken subtitles for the visually impaired are available.
     * @return {@code true} if spoken subtitles are available.
     */
    public boolean hasSpokenSubtitles() {
        return mSpokenSubtitlesAvailable;
    }

    /**
     * Indicates whether dialogue enhancement is available.
     * @return {@code true} if dialogue enhancement is available.
     */
    public boolean hasDialogueEnhancement() {
        return mDialogueEnhancementAvailable;
    }
}
+20 −0
Original line number Diff line number Diff line
@@ -1989,6 +1989,25 @@ public class AudioTrack extends PlayerBase
        return native_set_loop(startInFrames, endInFrames, loopCount);
    }

    /**
     * Sets the audio presentation.
     * If the audio presentation is invalid then {@link #ERROR_BAD_VALUE} will be returned.
     * If a multi-stream decoder (MSD) is not present, or the format does not support
     * multiple presentations, then {@link #ERROR_INVALID_OPERATION} will be returned.
     * @param presentation see {@link AudioPresentation}. In particular, id should be set.
     * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
     *    {@link #ERROR_INVALID_OPERATION}
     * @throws IllegalArgumentException if the audio presentation is null.
     * @throws IllegalStateException if track is not initialized.
     */
    public int setPresentation(@NonNull AudioPresentation presentation) {
        if (presentation == null) {
            throw new IllegalArgumentException("audio presentation is null");
        }
        return native_setPresentation(presentation.getPresentationId(),
                presentation.getProgramId());
    }

    /**
     * Sets the initialization state of the instance. This method was originally intended to be used
     * in an AudioTrack subclass constructor to set a subclass-specific post-initialization state.
@@ -3227,6 +3246,7 @@ public class AudioTrack extends PlayerBase
            @NonNull VolumeShaper.Operation operation);

    private native @Nullable VolumeShaper.State native_getVolumeShaperState(int id);
    private native final int native_setPresentation(int presentationId, int programId);

    //---------------------------------------------------------
    // Utility methods
+13 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.annotation.Nullable;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.media.AudioPresentation;
import android.media.MediaCodec;
import android.media.MediaFormat;
import android.media.MediaHTTPService;
@@ -40,6 +41,7 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

@@ -395,6 +397,17 @@ final public class MediaExtractor {
        return null;
    }

    /**
     * Get the list of available audio presentations for the track.
     * @param trackIndex index of the track.
     * @return a list of available audio presentations for a given valid audio track index.
     * The list will be empty if the source does not contain any audio presentations.
     */
    @NonNull
    public List<AudioPresentation> getAudioPresentations(int trackIndex) {
        return new ArrayList<AudioPresentation>();
    }

    /**
     * Get the PSSH info if present.
     * @return a map of uuid-to-bytes, with the uuid specifying
Loading