1 /*
2  * Copyright 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of 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,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef ANDROID_AUDIO_POWER_LOG_H
18 #define ANDROID_AUDIO_POWER_LOG_H
19 
20 #ifdef __cplusplus
21 
22 #include <mutex>
23 #include <vector>
24 #include <system/audio.h>
25 #include <utils/Errors.h>
26 
27 namespace android {
28 
29 /**
30  * PowerLogBase logs power at a given frame resolution.
31  *
32  * Generally this class is not directly accessed, rather it is embedded
33  * as a helper object in PowerLog, which uses multiple PowerLogBase objects to
34  * log at different frame resolutions.
35  *
36  * Call framesToProcess() to determine the maximum number of frames to process.
37  * Then call processEnergy() with a frame count, and the energy, and the time.
38  */
39 class PowerLogBase {
40 public:
41     PowerLogBase(uint32_t sampleRate,
42             uint32_t channelCount,
43             audio_format_t format,
44             size_t entries,
45             size_t framesPerEntry);
46 
framesToProcess(size_t frames)47     size_t framesToProcess(size_t frames) const {
48         const size_t required = mFramesPerEntry - mCurrentFrames;
49         return std::min(required, frames);
50     }
51 
52     void processEnergy(size_t frames, float energy, int64_t nowNs);
53 
54     std::string dumpToString(const char* prefix = "", size_t lines = 0, int64_t limitNs = 0,
55             bool logPlot = true) const;
56 
57 private:
58     void flushEntry();
59 
60     const uint32_t mSampleRate;   // audio data sample rate
61     const uint32_t mChannelCount; // audio data channel count
62     const audio_format_t mFormat; // audio data format
63     const size_t mFramesPerEntry; // number of audio frames per entry
64     const int64_t mEntryTimeNs;   // the entry time span in ns
65     const int64_t mMaxTimeSlipNs; // maximum time incoming audio can
66                                   // be offset by before we flush current entry
67 
68     int64_t mCurrentTime = 0;     // time of first frame in buffer
69     float mCurrentEnergy = 0.f;   // local energy accumulation
70     size_t mCurrentFrames = 0;    // number of frames in the energy
71     size_t mIdx = 0;              // next usable index in mEntries
72     size_t mConsecutiveZeroes = 1; // current run of consecutive zero entries
73     std::vector<std::pair<int64_t /* real time ns */, float /* energy */>> mEntries;
74 };
75 
76 /**
77  * PowerLog captures the audio data power (measured in dBFS) over time.
78  *
79  * For the purposes of power evaluation, the audio data is divided into "bins",
80  * and grouped by signals consisting of consecutive non-zero energy bins.
81  * The sum energy in dB of each signal is computed for comparison purposes.
82  *
83  * No distinction is made between channels in an audio frame; they are all
84  * summed together for energy purposes.
85  *
86  * The public methods are internally protected by a mutex to be thread-safe.
87  */
88 class PowerLog {
89 public:
90 
91     /**
92      * \brief Creates a PowerLog object.
93      *
94      * \param sampleRate        sample rate of the audio data.
95      * \param channelCount      channel count of the audio data.
96      * \param format            format of the audio data. It must be allowed by
97      *                          audio_utils_is_compute_power_format_supported()
98      *                          else the constructor will abort.
99      * \param entries           total number of energy entries "bins" to use.
100      * \param framesPerEntry    total number of audio frames used in each entry.
101      * \param levels            number of resolution levels for the log (typically 1 or 2).
102      */
103     PowerLog(uint32_t sampleRate,
104             uint32_t channelCount,
105             audio_format_t format,
106             size_t entries,
107             size_t framesPerEntry,
108             size_t levels = 2)
mChannelCount(channelCount)109             : mChannelCount(channelCount)
110             , mFormat(format)
111             , mSampleRate(sampleRate)
112             , mBase{[=]() {
113                 // create a vector of PowerLogBases starting from the
114                 // finest granularity to the largest granularity.
115                 std::vector<std::shared_ptr<PowerLogBase>> v(levels);
116                 size_t scale = 1;
117                 for (size_t i = 0; i < levels; ++i) {
118                     v[i] = std::make_shared<PowerLogBase>(
119                             sampleRate, channelCount, format,
120                             entries / levels, framesPerEntry * scale);
121                     scale *= 20;  // each level's entry is 20x the temporal width of the prior.
122                 }
123                 return v;
124             }()}  {}
125 
126     /**
127      * \brief Adds new audio data to the power log.
128      *
129      * \param buffer            pointer to the audio data buffer.
130      * \param frames            buffer size in audio frames.
131      * \param nowNs             current time in nanoseconds.
132      */
133     void log(const void *buffer, size_t frames, int64_t nowNs);
134 
135     /**
136      * \brief Dumps the log to a std::string.
137      *
138      * \param lines             maximum number of lines to output (0 disables).
139      * \param limitNs           limit dump to data more recent than limitNs (0 disables).
140      * \param logPlot           true if a log plot is generated. This will result in
141      *                          additional 18 lines to be output.
142      * \return the std::string for the log.
143      */
144     std::string dumpToString(const char *prefix = "", size_t lines = 0, int64_t limitNs = 0,
145             bool logPlot = true) const;
146 
147     /**
148      * \brief Dumps the log to a raw file descriptor.
149      *
150      * \param fd                file descriptor to use.
151      * \param lines             maximum number of lines to output (0 disables).
152      * \param limitNs           limit dump to data more recent than limitNs (0 disables).
153      * \param logPlot           true if a log plot is generated. This will result in
154      *                          additional 18 lines to be output.
155      * \return
156      *   NO_ERROR on success or a negative number (-errno) on failure of write().
157      */
158     status_t dump(int fd, const char *prefix = "", size_t lines = 0, int64_t limitNs = 0,
159             bool logPlot = true) const;
160 
161     const uint32_t mChannelCount; // audio data channel count
162     const audio_format_t mFormat; // audio data format
163     const uint32_t mSampleRate;
164 
165     mutable std::mutex mMutex;    // monitor mutex governs access through mBase.
166     const std::vector<std::shared_ptr<PowerLogBase>> mBase;
167 };
168 
169 } // namespace android
170 
171 #endif // __cplusplus
172 
173 /** \cond */
174 __BEGIN_DECLS
175 /** \endcond */
176 
177 // C API (see C++ api above for details)
178 
179 typedef struct power_log_t power_log_t;
180 
181 /**
182  * \brief Creates a power log object.
183  *
184  * \param sample_rate       sample rate of the audio data.
185  * \param channel_count     channel count of the audio data.
186  * \param format            format of the audio data. It must be allowed by
187  *                          audio_utils_is_compute_power_format_supported().
188  * \param entries           total number of energy entries "bins" to use.
189  * \param frames_per_entry  total number of audio frames used in each entry.
190  *
191  * \return power log object or NULL on failure.
192  */
193 power_log_t *power_log_create(uint32_t sample_rate,
194         uint32_t channel_count, audio_format_t format, size_t entries, size_t frames_per_entry);
195 
196 /**
197  * \brief Adds new audio data to the power log.
198  *
199  * \param power_log         object returned by create, if NULL nothing happens.
200  * \param buffer            pointer to the audio data buffer.
201  * \param frames            buffer size in audio frames.
202  * \param now_ns            current time in nanoseconds.
203  */
204 void power_log_log(power_log_t *power_log, const void *buffer, size_t frames, int64_t now_ns);
205 
206 /**
207  * \brief Dumps the log to a raw file descriptor.
208  *
209  * A log plot is always generated, adding 18 more lines to the dump.
210  *
211  * \param power_log         object returned by create, if NULL nothing happens.
212  * \param fd                file descriptor to use.
213  * \param prefix            displayed at start of each line.
214  * \param lines             maximum number of lines to output (0 disables).
215  * \param limit_ns          limit dump to data more recent than limit_ns (0 disables).
216  * \return
217  *   NO_ERROR on success or a negative number (-errno) on failure of write().
218  *   if power_log is NULL, BAD_VALUE is returned.
219  */
220 int power_log_dump(
221         power_log_t *power_log, int fd, const char *prefix,  size_t lines, int64_t limit_ns);
222 
223 /**
224  * \brief Destroys the power log object.
225  *
226  * \param power_log         object returned by create, if NULL nothing happens.
227  */
228 void power_log_destroy(power_log_t *power_log);
229 
230 /** \cond */
231 __END_DECLS
232 /** \endcond */
233 
234 #endif // !ANDROID_AUDIO_POWER_LOG_H
235