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

Commit 0ad99c05 authored by Andy Hung's avatar Andy Hung
Browse files

Add AudioRecord timestamps

API change

Bug: 13569372
Bug: 22886739
Change-Id: Ic250fd0c39901f4e99c58281e371f27c241b6bed
parent 3ca8b122
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -19419,6 +19419,7 @@ package android.media {
    method public android.media.AudioDeviceInfo getRoutedDevice();
    method public int getSampleRate();
    method public int getState();
    method public int getTimestamp(android.media.AudioTimestamp, int);
    method public int read(byte[], int, int);
    method public int read(byte[], int, int, int);
    method public int read(short[], int, int);
@@ -19467,6 +19468,8 @@ package android.media {
  public final class AudioTimestamp {
    ctor public AudioTimestamp();
    field public static final int TIMEBASE_BOOTTIME = 1; // 0x1
    field public static final int TIMEBASE_MONOTONIC = 0; // 0x0
    field public long framePosition;
    field public long nanoTime;
  }
+3 −0
Original line number Diff line number Diff line
@@ -20724,6 +20724,7 @@ package android.media {
    method public android.media.AudioDeviceInfo getRoutedDevice();
    method public int getSampleRate();
    method public int getState();
    method public int getTimestamp(android.media.AudioTimestamp, int);
    method public int read(byte[], int, int);
    method public int read(byte[], int, int, int);
    method public int read(short[], int, int);
@@ -20774,6 +20775,8 @@ package android.media {
  public final class AudioTimestamp {
    ctor public AudioTimestamp();
    field public static final int TIMEBASE_BOOTTIME = 1; // 0x1
    field public static final int TIMEBASE_MONOTONIC = 0; // 0x0
    field public long framePosition;
    field public long nanoTime;
  }
+3 −0
Original line number Diff line number Diff line
@@ -19427,6 +19427,7 @@ package android.media {
    method public android.media.AudioDeviceInfo getRoutedDevice();
    method public int getSampleRate();
    method public int getState();
    method public int getTimestamp(android.media.AudioTimestamp, int);
    method public int read(byte[], int, int);
    method public int read(byte[], int, int, int);
    method public int read(short[], int, int);
@@ -19475,6 +19476,8 @@ package android.media {
  public final class AudioTimestamp {
    ctor public AudioTimestamp();
    field public static final int TIMEBASE_BOOTTIME = 1; // 0x1
    field public static final int TIMEBASE_MONOTONIC = 0; // 0x0
    field public long framePosition;
    field public long nanoTime;
  }
+46 −0
Original line number Diff line number Diff line
@@ -54,6 +54,10 @@ struct audio_attributes_fields_t {
};
static audio_attributes_fields_t javaAudioAttrFields;
static audio_record_fields_t     javaAudioRecordFields;
static struct {
    jfieldID  fieldFramePosition;     // AudioTimestamp.framePosition
    jfieldID  fieldNanoTime;          // AudioTimestamp.nanoTime
} javaAudioTimestampFields;

struct audiorecord_callback_cookie {
    jclass      audioRecord_class;
@@ -678,7 +682,40 @@ static void android_media_AudioRecord_disableDeviceCallback(
    }
}

// ----------------------------------------------------------------------------
static jint android_media_AudioRecord_get_timestamp(JNIEnv *env, jobject thiz,
        jobject timestamp, jint timebase) {
    sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);

    if (lpRecorder == NULL) {
        jniThrowException(env, "java/lang/IllegalStateException",
            "Unable to retrieve AudioRecord pointer for getTimestamp()");
        return (jint)AUDIO_JAVA_ERROR;
    }

    // TODO Enable.
#if 0
    // get the record timestamp
    ExtendedTimestamp ts;
    jint status = nativeToJavaStatus(lpRecorder->getExtendedTimestamp(&ts));

    if (status == AUDIO_JAVA_SUCCESS) {
        // set the data
        int64_t position, time;

        status = nativeToJavaStatus(ts.getBestTimestamp(&position, &time, timebase));
        if (status == AUDIO_JAVA_SUCCESS) {
            env->SetLongField(
                    timestamp, javaAudioTimestampFields.fieldFramePosition, position);
            env->SetLongField(
                    timestamp, javaAudioTimestampFields.fieldNanoTime, time);
        }
    }
    return status;
#else
    return (jint)AUDIO_JAVA_INVALID_OPERATION;
#endif
}

// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
@@ -716,6 +753,8 @@ static const JNINativeMethod gMethods[] = {
    {"native_enableDeviceCallback", "()V", (void *)android_media_AudioRecord_enableDeviceCallback},
    {"native_disableDeviceCallback", "()V",
                                        (void *)android_media_AudioRecord_disableDeviceCallback},
    {"native_get_timestamp", "(Landroid/media/AudioTimestamp;I)I",
                                       (void *)android_media_AudioRecord_get_timestamp},
};

// field names found in android/media/AudioRecord.java
@@ -758,6 +797,13 @@ int register_android_media_AudioRecord(JNIEnv *env)
    javaAudioAttrFields.fieldFormattedTags = GetFieldIDOrDie(env,
            audioAttrClass, "mFormattedTags", "Ljava/lang/String;");

    // Get the RecordTimestamp class and fields
    jclass audioTimestampClass = FindClassOrDie(env, "android/media/AudioTimestamp");
    javaAudioTimestampFields.fieldFramePosition =
            GetFieldIDOrDie(env, audioTimestampClass, "framePosition", "J");
    javaAudioTimestampFields.fieldNanoTime =
            GetFieldIDOrDie(env, audioTimestampClass, "nanoTime", "J");

    return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
}

+30 −0
Original line number Diff line number Diff line
@@ -811,6 +811,33 @@ public class AudioRecord
        return native_get_pos_update_period();
    }

    /**
     * Poll for an {@link AudioTimestamp} on demand.
     * <p>
     * The AudioTimestamp reflects the frame delivery information at
     * the earliest point available in the capture pipeline.
     * <p>
     * Calling {@link #startRecording()} following a {@link #stop()} will reset
     * the frame count to 0.
     *
     * @param timestamp a reference to a non-null AudioTimestamp instance.
     * @param timebase one of
     *        {@link AudioTimestamp#TIMEBASE_BOOTTIME AudioTimestamp.TIMEBASE_BOOTTIME} or
     *        {@link AudioTimestamp#TIMEBASE_MONOTONIC AudioTimestamp.TIMEBASE_MONOTONIC}.
     * @return {@link #SUCCESS} if a timestamp is available,
     *         or {@link #ERROR_INVALID_OPERATION} if a timestamp not available.
     */
     public int getTimestamp(@NonNull AudioTimestamp timestamp,
             @AudioTimestamp.Timebase int timebase)
     {
         if (timestamp == null ||
                 (timebase != AudioTimestamp.TIMEBASE_BOOTTIME
                 && timebase != AudioTimestamp.TIMEBASE_MONOTONIC)) {
             throw new IllegalArgumentException();
         }
         return native_get_timestamp(timestamp, timebase);
     }

    /**
     * Returns the minimum buffer size required for the successful creation of an AudioRecord
     * object, in byte units.
@@ -1566,6 +1593,9 @@ public class AudioRecord
    private native final void native_enableDeviceCallback();
    private native final void native_disableDeviceCallback();

    private native final int native_get_timestamp(@NonNull AudioTimestamp timestamp,
            @AudioTimestamp.Timebase int timebase);

    //---------------------------------------------------------
    // Utility methods
    //------------------
Loading