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

Commit b5ebe300 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "AudioTrack: support for offloaded playback"

parents db28e90b 980d38ff
Loading
Loading
Loading
Loading
+30 −0
Original line number Diff line number Diff line
@@ -33,6 +33,8 @@
#define ENCODING_AAC_HE_V2      12
#define ENCODING_IEC61937       13
#define ENCODING_DOLBY_TRUEHD   14
#define ENCODING_AAC_ELD        15
#define ENCODING_AAC_XHE        16

#define ENCODING_INVALID    0
#define ENCODING_DEFAULT    1
@@ -71,6 +73,10 @@ static inline audio_format_t audioFormatToNative(int audioFormat)
        return AUDIO_FORMAT_DOLBY_TRUEHD;
    case ENCODING_IEC61937:
        return AUDIO_FORMAT_IEC61937;
    case ENCODING_AAC_ELD:
        return AUDIO_FORMAT_AAC_ELD;
    case ENCODING_AAC_XHE:
        return AUDIO_FORMAT_AAC; // FIXME temporary value, needs addition of xHE-AAC
    case ENCODING_DEFAULT:
        return AUDIO_FORMAT_DEFAULT;
    default:
@@ -114,6 +120,11 @@ static inline int audioFormatFromNative(audio_format_t nativeFormat)
        return ENCODING_IEC61937;
    case AUDIO_FORMAT_DOLBY_TRUEHD:
        return ENCODING_DOLBY_TRUEHD;
    case AUDIO_FORMAT_AAC_ELD:
            return ENCODING_AAC_ELD;
    // FIXME needs addition of AUDIO_FORMAT_AAC_XHE
    //case AUDIO_FORMAT_AAC_XHE:
    //    return ENCODING_AAC_XHE;
    case AUDIO_FORMAT_DEFAULT:
        return ENCODING_DEFAULT;
    default:
@@ -121,6 +132,25 @@ static inline int audioFormatFromNative(audio_format_t nativeFormat)
    }
}

// This function converts Java channel masks to a native channel mask.
// validity should be checked with audio_is_output_channel().
static inline audio_channel_mask_t nativeChannelMaskFromJavaChannelMasks(
        jint channelPositionMask, jint channelIndexMask)
{
    // 0 is the java android.media.AudioFormat.CHANNEL_INVALID value
    if (channelIndexMask != 0) {  // channel index mask takes priority
        // To convert to a native channel mask, the Java channel index mask
        // requires adding the index representation.
        return audio_channel_mask_from_representation_and_bits(
                        AUDIO_CHANNEL_REPRESENTATION_INDEX,
                        channelIndexMask);
    }
    // To convert to a native channel mask, the Java channel position mask
    // requires a shift by 2 to skip the two deprecated channel
    // configurations "default" and "mono".
    return (audio_channel_mask_t)((uint32_t)channelPositionMask >> 2);
}

static inline audio_channel_mask_t outChannelMaskToNative(int channelMask)
{
    switch (channelMask) {
+19 −0
Original line number Diff line number Diff line
@@ -1770,6 +1770,24 @@ android_media_AudioSystem_getStreamVolumeDB(JNIEnv *env, jobject thiz,
                                                  (audio_devices_t)device);
}

static jboolean
android_media_AudioSystem_isOffloadSupported(JNIEnv *env, jobject thiz,
        jint encoding, jint sampleRate, jint channelMask, jint channelIndexMask)
{
    audio_offload_info_t format = AUDIO_INFO_INITIALIZER;
    format.format = (audio_format_t) audioFormatToNative(encoding);
    format.sample_rate = (uint32_t) sampleRate;
    format.channel_mask = nativeChannelMaskFromJavaChannelMasks(channelMask, channelIndexMask);
    format.stream_type = AUDIO_STREAM_MUSIC;
    format.has_video = false;
    format.is_streaming = false;
    // offload duration unknown at this point:
    // client side code cannot access "audio.offload.min.duration.secs" property to make a query
    // agnostic of duration, so using acceptable estimate of 2mn
    format.duration_us = 120 * 1000000;
    return AudioSystem::isOffloadSupported(format);
}

// ----------------------------------------------------------------------------

static const JNINativeMethod gMethods[] = {
@@ -1823,6 +1841,7 @@ static const JNINativeMethod gMethods[] = {
                                    (void *)android_media_AudioSystem_registerRecordingCallback},
    {"systemReady", "()I", (void *)android_media_AudioSystem_systemReady},
    {"getStreamVolumeDB", "(III)F", (void *)android_media_AudioSystem_getStreamVolumeDB},
    {"native_is_offload_supported", "(IIII)Z", (void *)android_media_AudioSystem_isOffloadSupported},
};


+37 −35
Original line number Diff line number Diff line
@@ -73,6 +73,7 @@ struct audiotrack_callback_cookie {
    jobject     audioTrack_ref;
    bool        busy;
    Condition   cond;
    bool        isOffload;
};

// keep these values in sync with AudioTrack.java
@@ -90,6 +91,7 @@ class AudioTrackJniStorage {
    AudioTrackJniStorage() {
        mCallbackData.audioTrack_class = 0;
        mCallbackData.audioTrack_ref = 0;
        mCallbackData.isOffload = false;
    }

    ~AudioTrackJniStorage() {
@@ -132,7 +134,12 @@ static void audioCallback(int event, void* user, void *info) {
    }

    switch (event) {
    case AudioTrack::EVENT_MARKER: {
    // Offload only events
    case AudioTrack::EVENT_STREAM_END:
    case AudioTrack::EVENT_MORE_DATA:
    // a.k.a. tear down
    case AudioTrack::EVENT_NEW_IAUDIOTRACK:
        if (callbackInfo->isOffload) {
            JNIEnv *env = AndroidRuntime::getJNIEnv();
            if (user != NULL && env != NULL) {
                env->CallStaticVoidMethod(
@@ -146,6 +153,8 @@ static void audioCallback(int event, void* user, void *info) {
            }
        } break;

    // PCM and offload events
    case AudioTrack::EVENT_MARKER:
    case AudioTrack::EVENT_NEW_POS: {
        JNIEnv *env = AndroidRuntime::getJNIEnv();
        if (user != NULL && env != NULL) {
@@ -198,30 +207,12 @@ sp<AudioTrack> android_media_AudioTrack_getAudioTrack(JNIEnv* env, jobject audio
    return getAudioTrack(env, audioTrackObj);
}

// This function converts Java channel masks to a native channel mask.
// validity should be checked with audio_is_output_channel().
static inline audio_channel_mask_t nativeChannelMaskFromJavaChannelMasks(
        jint channelPositionMask, jint channelIndexMask)
{
    if (channelIndexMask != 0) {  // channel index mask takes priority
        // To convert to a native channel mask, the Java channel index mask
        // requires adding the index representation.
        return audio_channel_mask_from_representation_and_bits(
                        AUDIO_CHANNEL_REPRESENTATION_INDEX,
                        channelIndexMask);
    }
    // To convert to a native channel mask, the Java channel position mask
    // requires a shift by 2 to skip the two deprecated channel
    // configurations "default" and "mono".
    return (audio_channel_mask_t)(channelPositionMask >> 2);
}

// ----------------------------------------------------------------------------
static jint
android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this, jobject jaa,
        jintArray jSampleRate, jint channelPositionMask, jint channelIndexMask,
        jint audioFormat, jint buffSizeInBytes, jint memoryMode, jintArray jSession,
        jlong nativeAudioTrack) {
        jlong nativeAudioTrack, jboolean offload) {

    ALOGV("sampleRates=%p, channel mask=%x, index mask=%x, audioFormat(Java)=%d, buffSize=%d"
        "nativeAudioTrack=0x%" PRIX64,
@@ -322,8 +313,19 @@ android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this, job
        lpJniStorage->mCallbackData.audioTrack_class = (jclass)env->NewGlobalRef(clazz);
        // we use a weak reference so the AudioTrack object can be garbage collected.
        lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
        lpJniStorage->mCallbackData.isOffload = offload;
        lpJniStorage->mCallbackData.busy = false;

        audio_offload_info_t offloadInfo;
        if (offload) {
            offloadInfo = AUDIO_INFO_INITIALIZER;
            offloadInfo.format = format;
            offloadInfo.sample_rate = sampleRateInHertz;
            offloadInfo.channel_mask = nativeChannelMask;
            offloadInfo.has_video = false;
            offloadInfo.stream_type = AUDIO_STREAM_MUSIC; //required for offload
        }

        // initialize the native AudioTrack object
        status_t status = NO_ERROR;
        switch (memoryMode) {
@@ -342,7 +344,7 @@ android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this, job
                    true,// thread can call Java
                    sessionId,// audio session ID
                    AudioTrack::TRANSFER_SYNC,
                    NULL,                         // default offloadInfo
                    offload ? &offloadInfo : NULL,
                    -1, -1,                       // default uid, pid values
                    paa);
            break;
@@ -1234,7 +1236,7 @@ static const JNINativeMethod gMethods[] = {
    {"native_stop",          "()V",      (void *)android_media_AudioTrack_stop},
    {"native_pause",         "()V",      (void *)android_media_AudioTrack_pause},
    {"native_flush",         "()V",      (void *)android_media_AudioTrack_flush},
    {"native_setup",     "(Ljava/lang/Object;Ljava/lang/Object;[IIIIII[IJ)I",
    {"native_setup",     "(Ljava/lang/Object;Ljava/lang/Object;[IIIIII[IJZ)I",
                                         (void *)android_media_AudioTrack_setup},
    {"native_finalize",      "()V",      (void *)android_media_AudioTrack_finalize},
    {"native_release",       "()V",      (void *)android_media_AudioTrack_release},
+42 −11
Original line number Diff line number Diff line
@@ -240,20 +240,25 @@ public final class AudioFormat implements Parcelable {
    public static final int ENCODING_DTS_HD = 8;
    /** Audio data format: MP3 compressed
     * @hide
     * TODO unhide and add to @Encoding (intentional white space   
     * */
    public static final int ENCODING_MP3 = 9;
    /** Audio data format: AAC LC compressed
     * @hide
     * TODO unhide and add to @Encoding (intentional white space   
     * */
    public static final int ENCODING_AAC_LC = 10;
    /** Audio data format: AAC HE V1 compressed
     * @hide
     * TODO unhide and add to @Encoding (intentional white space   
     * */
    public static final int ENCODING_AAC_HE_V1 = 11;
    /** Audio data format: AAC HE V2 compressed
     * @hide
     * TODO unhide and add to @Encoding (intentional white space   
     * */
    public static final int ENCODING_AAC_HE_V2 = 12;

    /** Audio data format: compressed audio wrapped in PCM for HDMI
     * or S/PDIF passthrough.
     * IEC61937 uses a stereo stream of 16-bit samples as the wrapper.
@@ -266,6 +271,16 @@ public final class AudioFormat implements Parcelable {
    /** Audio data format: DOLBY TRUEHD compressed
     **/
    public static final int ENCODING_DOLBY_TRUEHD = 14;
    /** Audio data format: AAC ELD compressed
     * @hide
     * TODO unhide and add to @Encoding (intentional white space   
     * */
    public static final int ENCODING_AAC_ELD = 15;
    /** Audio data format: AAC xHE compressed
     * @hide
     * TODO unhide and add to @Encoding (intentional white space   
     * */
    public static final int ENCODING_AAC_XHE = 16;

    /** @hide */
    public static String toLogFriendlyEncoding(int enc) {
@@ -298,6 +313,10 @@ public final class AudioFormat implements Parcelable {
                return "ENCODING_IEC61937";
            case ENCODING_DOLBY_TRUEHD:
                return "ENCODING_DOLBY_TRUEHD";
            case ENCODING_AAC_ELD:
                return "ENCODING_AAC_ELD";
            case ENCODING_AAC_XHE:
                return "ENCODING_AAC_XHE";
            default :
                return "invalid encoding " + enc;
        }
@@ -514,6 +533,8 @@ public final class AudioFormat implements Parcelable {
        case ENCODING_AAC_HE_V1:
        case ENCODING_AAC_HE_V2:
        case ENCODING_IEC61937:
        case ENCODING_AAC_ELD:
        case ENCODING_AAC_XHE:
            return true;
        default:
            return false;
@@ -532,6 +553,13 @@ public final class AudioFormat implements Parcelable {
        case ENCODING_DTS:
        case ENCODING_DTS_HD:
        case ENCODING_IEC61937:
            //TODO not true yet (intended white space     
        case ENCODING_MP3:
        case ENCODING_AAC_LC:
        case ENCODING_AAC_HE_V1:
        case ENCODING_AAC_HE_V2:
        case ENCODING_AAC_ELD:
        case ENCODING_AAC_XHE:
            return true;
        default:
            return false;
@@ -556,6 +584,8 @@ public final class AudioFormat implements Parcelable {
        case ENCODING_AAC_HE_V1:
        case ENCODING_AAC_HE_V2:
        case ENCODING_IEC61937: // wrapped in PCM but compressed
        case ENCODING_AAC_ELD:
        case ENCODING_AAC_XHE:
            return false;
        case ENCODING_INVALID:
        default:
@@ -581,6 +611,8 @@ public final class AudioFormat implements Parcelable {
        case ENCODING_AAC_LC:
        case ENCODING_AAC_HE_V1:
        case ENCODING_AAC_HE_V2:
        case ENCODING_AAC_ELD:
        case ENCODING_AAC_XHE:
            return false;
        case ENCODING_INVALID:
        default:
@@ -794,14 +826,7 @@ public final class AudioFormat implements Parcelable {

        /**
         * Sets the data encoding format.
         * @param encoding one of {@link AudioFormat#ENCODING_DEFAULT},
         *     {@link AudioFormat#ENCODING_PCM_8BIT},
         *     {@link AudioFormat#ENCODING_PCM_16BIT},
         *     {@link AudioFormat#ENCODING_PCM_FLOAT},
         *     {@link AudioFormat#ENCODING_AC3},
         *     {@link AudioFormat#ENCODING_E_AC3}.
         *     {@link AudioFormat#ENCODING_DTS},
         *     {@link AudioFormat#ENCODING_DTS_HD}.
         * @param encoding the specified encoding or default.
         * @return the same Builder instance.
         * @throws java.lang.IllegalArgumentException
         */
@@ -818,6 +843,12 @@ public final class AudioFormat implements Parcelable {
                case ENCODING_DTS:
                case ENCODING_DTS_HD:
                case ENCODING_IEC61937:
                case ENCODING_MP3:
                case ENCODING_AAC_LC:
                case ENCODING_AAC_HE_V1:
                case ENCODING_AAC_HE_V2:
                case ENCODING_AAC_ELD:
                case ENCODING_AAC_XHE:
                    mEncoding = encoding;
                    break;
                case ENCODING_INVALID:
@@ -1016,7 +1047,7 @@ public final class AudioFormat implements Parcelable {
    }

    /** @hide */
    @IntDef({
    @IntDef(flag = false, prefix = "ENCODING", value = {
        ENCODING_DEFAULT,
        ENCODING_PCM_8BIT,
        ENCODING_PCM_16BIT,
@@ -1025,8 +1056,8 @@ public final class AudioFormat implements Parcelable {
        ENCODING_E_AC3,
        ENCODING_DTS,
        ENCODING_DTS_HD,
        ENCODING_IEC61937
    })
        ENCODING_IEC61937 }
    )
    @Retention(RetentionPolicy.SOURCE)
    public @interface Encoding {}

+15 −0
Original line number Diff line number Diff line
@@ -1328,6 +1328,21 @@ public class AudioManager {
        }
     }

    //====================================================================
    // Offload query
    /**
     * @hide
     * TODO unhide (intentional white space to attract attention:    
     * Returns whether offloaded playback of an audio format is supported on the device.
     * Offloaded playback is where the decoding of an audio stream is not competing with other
     * software resources. In general, it is supported by dedicated hardware, such as audio DSPs.
     * @param format the audio format (codec, sample rate, channels) being checked.
     * @return true if the given audio format can be offloaded.
     */
    public static boolean isOffloadedPlaybackSupported(@NonNull AudioFormat format) {
        return AudioSystem.isOffloadSupported(format);
    }

    //====================================================================
    // Bluetooth SCO control
    /**
Loading