blob: b652f602cca2967dad7f2b46d7c4e5117baa4b51 [file] [log] [blame]
/*
* Copyright 2019 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 com.android.tv.settings.system.development.audio;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import java.util.Optional;
/** Stores audio recording metrics. Sends metrics updates through a callback. */
public class AudioMetrics {
private static final String TAG = "AudioMetrics";
private Optional<Long> mStartTs = Optional.empty();
private Data mData = new Data();
private final UpdateMetricsCallback mCallback;
/** Contains data to be exposed via the callback. */
public static class Data {
public Optional<Long> timeToStartReadMs = Optional.empty();
public Optional<Long> timeToValidAudioMs = Optional.empty();
public Optional<Long> emptyAudioDurationMs = Optional.empty();
public Data() {
}
public Data(Data data) {
this.timeToStartReadMs = data.timeToStartReadMs;
this.timeToValidAudioMs = data.timeToValidAudioMs;
this.emptyAudioDurationMs = data.emptyAudioDurationMs;
}
}
/** Interface for receiving metrics updates. */
public interface UpdateMetricsCallback {
/** Callback for receiving metrics updates. */
void onUpdateMetrics(AudioMetrics.Data data);
}
/**
* @param callback Callback for updates.
*/
public AudioMetrics(UpdateMetricsCallback callback) {
this.mCallback = callback;
}
/** Records the beginning of the audio recording process. */
public void start() {
mData = new Data();
mStartTs = Optional.of(System.currentTimeMillis());
updateMetrics();
}
/** Records that we have started monitoring a buffer for incoming audio data. */
public void startedReading() throws IllegalStateException {
long startTs = this.mStartTs
.orElseThrow(() -> new IllegalStateException(
"Started reading before recording started"));
long currentTs = System.currentTimeMillis();
mData = new Data(mData);
mData.timeToStartReadMs = Optional.of(currentTs - startTs);
updateMetrics();
}
/** Records that we have started receiving non-zero audio data */
public void receivedValidAudio() throws IllegalStateException {
long startTs = this.mStartTs
.orElseThrow(() -> new IllegalStateException(
"Received audio data before recording started"));
long currentTs = System.currentTimeMillis();
mData = new Data(mData);
mData.timeToValidAudioMs = Optional.of(currentTs - startTs);
updateMetrics();
}
/** Records the duration of empty audio received before valid audio */
public void setEmptyAudioDurationMs(long emptyAudioMs) {
mData = new Data(mData);
mData.emptyAudioDurationMs = Optional.of(emptyAudioMs);
updateMetrics();
}
/** Sends updated data through the callback */
private void updateMetrics() {
Handler mainHandler = new Handler(Looper.getMainLooper());
mainHandler.post(() -> mCallback.onUpdateMetrics(mData));
Log.i(TAG, String.format("Time to start reading: %s",
msTimestampToString(mData.timeToStartReadMs)));
Log.i(TAG, String.format("Time to valid audio data: %s",
msTimestampToString(mData.timeToValidAudioMs)));
Log.i(TAG, String.format("Empty audio duration: %s",
msTimestampToString(mData.emptyAudioDurationMs)));
}
/** Converts a possible timestamp in milliseconds to its string representation. */
public static String msTimestampToString(Optional<Long> optL) {
return optL.map((Long l) -> String.format("%s ms", l)).orElse("");
}
}