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 */
16package android.speech.tts;
17
18import 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 */
27abstract 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
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     */
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     */
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     */
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     */
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     */
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
119    protected abstract void logFailure(int statusCode);
120    protected abstract void logSuccess(long audioLatency, long engineLatency,
121            long engineTotal);
122
123
124}
125