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

Commit 948c2e6f authored by Glenn Kasten's avatar Glenn Kasten
Browse files

Java API for AudioTrack timestamps

This change adds android.media.AudioTimestamp and
android.media.AudioTrack.getTimestamp, with implementation, but hidden.

Change-Id: Ic314f04ff775baca05c57d19b5ea91133dbd0be1
parent e57d1174
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -741,6 +741,30 @@ static jint android_media_AudioTrack_get_latency(JNIEnv *env, jobject thiz) {
}


// ----------------------------------------------------------------------------
static jint android_media_AudioTrack_get_timestamp(JNIEnv *env,  jobject thiz, jlongArray jTimestamp) {
    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);

    if (lpTrack == NULL) {
        ALOGE("Unable to retrieve AudioTrack pointer for getTimestamp()");
        return AUDIOTRACK_ERROR;
    }
    AudioTimestamp timestamp;
    status_t status = lpTrack->getTimestamp(timestamp);
    if (status == OK) {
        jlong* nTimestamp = (jlong *) env->GetPrimitiveArrayCritical(jTimestamp, NULL);
        if (nTimestamp == NULL) {
            ALOGE("Unable to get array for getTimestamp()");
            return AUDIOTRACK_ERROR;
        }
        nTimestamp[0] = (jlong) timestamp.mPosition;
        nTimestamp[1] = (jlong) ((timestamp.mTime.tv_sec * 1000000000LL) + timestamp.mTime.tv_nsec);
        env->ReleasePrimitiveArrayCritical(jTimestamp, nTimestamp, 0);
    }
    return (jint) android_media_translateErrorCode(status);
}


// ----------------------------------------------------------------------------
static jint android_media_AudioTrack_set_loop(JNIEnv *env,  jobject thiz,
        jint loopStart, jint loopEnd, jint loopCount) {
@@ -869,6 +893,7 @@ static JNINativeMethod gMethods[] = {
    {"native_set_position",  "(I)I",     (void *)android_media_AudioTrack_set_position},
    {"native_get_position",  "()I",      (void *)android_media_AudioTrack_get_position},
    {"native_get_latency",   "()I",      (void *)android_media_AudioTrack_get_latency},
    {"native_get_timestamp", "([J)I",    (void *)android_media_AudioTrack_get_timestamp},
    {"native_set_loop",      "(III)I",   (void *)android_media_AudioTrack_set_loop},
    {"native_reload_static", "()I",      (void *)android_media_AudioTrack_reload},
    {"native_get_output_sample_rate",
+47 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2013 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;

/**
 * Structure that groups a position in frame units relative to an assumed audio stream,
 * together with the estimated time when that frame was presented or is committed to be
 * presented.
 * In the case of audio output, "present" means that audio produced on device
 * is detectable by an external observer off device.
 * The time is based on the implementation's best effort, using whatever knowledge
 * is available to the system, but cannot account for any delay unknown to the implementation.
 *
 * @see AudioTrack#getTimestamp
 * @see AudioTrack.TimestampListener
 *
 * @hide
 */
public final class AudioTimestamp
{
    /**
     * Position in frames relative to start of an assumed audio stream.
     * The low-order 32 bits of position is in wrapping frame units similar to
     * {@link AudioTrack#getPlaybackHeadPosition}.
     */
    public long framePosition;

    /**
     * The estimated time when frame was presented or is committed to be presented,
     * in the same units and timebase as {@link java.lang.System#nanoTime}.
     */
    public long nanoTime;
}
+50 −0
Original line number Diff line number Diff line
@@ -732,6 +732,51 @@ public class AudioTrack
        return mSessionId;
    }

   /**
    * Poll for a timestamp on demand.
    *
    * Use if {@link TimestampListener} is not delivered often enough for your needs,
    * or if you need to get the most recent timestamp outside of the event callback handler.
    * Calling this method too often may be inefficient;
    * if you need a high-resolution mapping between frame position and presentation time,
    * consider implementing that at application level, based on low-resolution timestamps.
    * The audio data at the returned position may either already have been
    * presented, or may have not yet been presented but is committed to be presented.
    * It is not possible to request the time corresponding to a particular position,
    * or to request the (fractional) position corresponding to a particular time.
    * If you need such features, consider implementing them at application level.
    *
    * @param timestamp a reference to a non-null AudioTimestamp instance allocated
    *        and owned by caller, or null.
    * @return that same instance if timestamp parameter is non-null and a timestamp is available,
    *         or a reference to a new AudioTimestamp instance which is now owned by caller
    *         if timestamp parameter is null and a timestamp is available,
    *         or null if no timestamp is available.  In either successful case,
    *         the AudioTimestamp instance is filled in with a position in frame units, together
    *         with the estimated time when that frame was presented or is committed to
    *         be presented.
    *         In the case that no timestamp is available, any supplied instance is left unaltered.
    *
    * @hide
    */
    public AudioTimestamp getTimestamp(AudioTimestamp timestamp)
    {
        // It's unfortunate, but we have to either create garbage every time or use synchronized
        long[] longArray = new long[2];
        int ret = native_get_timestamp(longArray);
        if (ret == SUCCESS) {
            if (timestamp == null) {
                timestamp = new AudioTimestamp();
            }
            timestamp.framePosition = longArray[0];
            timestamp.nanoTime = longArray[1];
        } else {
            timestamp = null;
        }
        return timestamp;
    }


    //--------------------------------------------------------------------------
    // Initialization / configuration
    //--------------------
@@ -1321,6 +1366,11 @@ public class AudioTrack

    private native final int native_get_latency();

    // longArray must be a non-null array of length >= 2
    // [0] is assigned the frame position
    // [1] is assigned the time in CLOCK_MONOTONIC nanoseconds
    private native final int native_get_timestamp(long[] longArray);

    private native final int native_set_loop(int start, int end, int loopCount);

    static private native final int native_get_output_sample_rate(int streamType);