1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 package android.speech.tts; 17 18 import android.os.SystemClock; 19 20 /** 21 * Base class for storing data about a given speech synthesis request to the 22 * event logs. The data that is logged depends on actual implementation. Note 23 * that {@link AbstractEventLogger#onAudioDataWritten()} and 24 * {@link AbstractEventLogger#onEngineComplete()} must be called from a single 25 * thread (usually the audio playback thread}. 26 */ 27 abstract class AbstractEventLogger { 28 protected final String mServiceApp; 29 protected final int mCallerUid; 30 protected final int mCallerPid; 31 protected final long mReceivedTime; 32 protected long mPlaybackStartTime = -1; 33 34 private volatile long mRequestProcessingStartTime = -1; 35 private volatile long mEngineStartTime = -1; 36 private volatile long mEngineCompleteTime = -1; 37 38 private boolean mLogWritten = false; 39 AbstractEventLogger(int callerUid, int callerPid, String serviceApp)40 AbstractEventLogger(int callerUid, int callerPid, String serviceApp) { 41 mCallerUid = callerUid; 42 mCallerPid = callerPid; 43 mServiceApp = serviceApp; 44 mReceivedTime = SystemClock.elapsedRealtime(); 45 } 46 47 /** 48 * Notifies the logger that this request has been selected from 49 * the processing queue for processing. Engine latency / total time 50 * is measured from this baseline. 51 */ onRequestProcessingStart()52 public void onRequestProcessingStart() { 53 mRequestProcessingStartTime = SystemClock.elapsedRealtime(); 54 } 55 56 /** 57 * Notifies the logger that a chunk of data has been received from 58 * the engine. Might be called multiple times. 59 */ onEngineDataReceived()60 public void onEngineDataReceived() { 61 if (mEngineStartTime == -1) { 62 mEngineStartTime = SystemClock.elapsedRealtime(); 63 } 64 } 65 66 /** 67 * Notifies the logger that the engine has finished processing data. 68 * Will be called exactly once. 69 */ onEngineComplete()70 public void onEngineComplete() { 71 mEngineCompleteTime = SystemClock.elapsedRealtime(); 72 } 73 74 /** 75 * Notifies the logger that audio playback has started for some section 76 * of the synthesis. This is normally some amount of time after the engine 77 * has synthesized data and varies depending on utterances and 78 * other audio currently in the queue. 79 */ onAudioDataWritten()80 public void onAudioDataWritten() { 81 // For now, keep track of only the first chunk of audio 82 // that was played. 83 if (mPlaybackStartTime == -1) { 84 mPlaybackStartTime = SystemClock.elapsedRealtime(); 85 } 86 } 87 88 /** 89 * Notifies the logger that the current synthesis has completed. 90 * All available data is not logged. 91 */ onCompleted(int statusCode)92 public void onCompleted(int statusCode) { 93 if (mLogWritten) { 94 return; 95 } else { 96 mLogWritten = true; 97 } 98 99 long completionTime = SystemClock.elapsedRealtime(); 100 101 // We don't report latency for stopped syntheses because their overall 102 // total time spent will be inaccurate (will not correlate with 103 // the length of the utterance). 104 105 // onAudioDataWritten() should normally always be called, and hence mPlaybackStartTime 106 // should be set, if an error does not occur. 107 if (statusCode != TextToSpeech.SUCCESS 108 || mPlaybackStartTime == -1 || mEngineCompleteTime == -1) { 109 logFailure(statusCode); 110 return; 111 } 112 113 final long audioLatency = mPlaybackStartTime - mReceivedTime; 114 final long engineLatency = mEngineStartTime - mRequestProcessingStartTime; 115 final long engineTotal = mEngineCompleteTime - mRequestProcessingStartTime; 116 logSuccess(audioLatency, engineLatency, engineTotal); 117 } 118 logFailure(int statusCode)119 protected abstract void logFailure(int statusCode); logSuccess(long audioLatency, long engineLatency, long engineTotal)120 protected abstract void logSuccess(long audioLatency, long engineLatency, 121 long engineTotal); 122 123 124 } 125