/*
 * 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.speech.tts;

import android.os.SystemClock;

Base class for storing data about a given speech synthesis request to the event logs. The data that is logged depends on actual implementation. Note that onAudioDataWritten() and onEngineComplete() must be called from a single thread (usually the audio playback thread}.
/** * Base class for storing data about a given speech synthesis request to the * event logs. The data that is logged depends on actual implementation. Note * that {@link AbstractEventLogger#onAudioDataWritten()} and * {@link AbstractEventLogger#onEngineComplete()} must be called from a single * thread (usually the audio playback thread}. */
abstract class AbstractEventLogger { protected final String mServiceApp; protected final int mCallerUid; protected final int mCallerPid; protected final long mReceivedTime; protected long mPlaybackStartTime = -1; private volatile long mRequestProcessingStartTime = -1; private volatile long mEngineStartTime = -1; private volatile long mEngineCompleteTime = -1; private boolean mLogWritten = false; AbstractEventLogger(int callerUid, int callerPid, String serviceApp) { mCallerUid = callerUid; mCallerPid = callerPid; mServiceApp = serviceApp; mReceivedTime = SystemClock.elapsedRealtime(); }
Notifies the logger that this request has been selected from the processing queue for processing. Engine latency / total time is measured from this baseline.
/** * Notifies the logger that this request has been selected from * the processing queue for processing. Engine latency / total time * is measured from this baseline. */
public void onRequestProcessingStart() { mRequestProcessingStartTime = SystemClock.elapsedRealtime(); }
Notifies the logger that a chunk of data has been received from the engine. Might be called multiple times.
/** * Notifies the logger that a chunk of data has been received from * the engine. Might be called multiple times. */
public void onEngineDataReceived() { if (mEngineStartTime == -1) { mEngineStartTime = SystemClock.elapsedRealtime(); } }
Notifies the logger that the engine has finished processing data. Will be called exactly once.
/** * Notifies the logger that the engine has finished processing data. * Will be called exactly once. */
public void onEngineComplete() { mEngineCompleteTime = SystemClock.elapsedRealtime(); }
Notifies the logger that audio playback has started for some section of the synthesis. This is normally some amount of time after the engine has synthesized data and varies depending on utterances and other audio currently in the queue.
/** * Notifies the logger that audio playback has started for some section * of the synthesis. This is normally some amount of time after the engine * has synthesized data and varies depending on utterances and * other audio currently in the queue. */
public void onAudioDataWritten() { // For now, keep track of only the first chunk of audio // that was played. if (mPlaybackStartTime == -1) { mPlaybackStartTime = SystemClock.elapsedRealtime(); } }
Notifies the logger that the current synthesis has completed. All available data is not logged.
/** * Notifies the logger that the current synthesis has completed. * All available data is not logged. */
public void onCompleted(int statusCode) { if (mLogWritten) { return; } else { mLogWritten = true; } long completionTime = SystemClock.elapsedRealtime(); // We don't report latency for stopped syntheses because their overall // total time spent will be inaccurate (will not correlate with // the length of the utterance). // onAudioDataWritten() should normally always be called, and hence mPlaybackStartTime // should be set, if an error does not occur. if (statusCode != TextToSpeech.SUCCESS || mPlaybackStartTime == -1 || mEngineCompleteTime == -1) { logFailure(statusCode); return; } final long audioLatency = mPlaybackStartTime - mReceivedTime; final long engineLatency = mEngineStartTime - mRequestProcessingStartTime; final long engineTotal = mEngineCompleteTime - mRequestProcessingStartTime; logSuccess(audioLatency, engineLatency, engineTotal); } protected abstract void logFailure(int statusCode); protected abstract void logSuccess(long audioLatency, long engineLatency, long engineTotal); }