xref: /aosp_15_r20/frameworks/av/media/libnblog/Merger.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
1*ec779b8eSAndroid Build Coastguard Worker /*
2*ec779b8eSAndroid Build Coastguard Worker  * Copyright (C) 2018 The Android Open Source Project
3*ec779b8eSAndroid Build Coastguard Worker  *
4*ec779b8eSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*ec779b8eSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*ec779b8eSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*ec779b8eSAndroid Build Coastguard Worker  *
8*ec779b8eSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*ec779b8eSAndroid Build Coastguard Worker  *
10*ec779b8eSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*ec779b8eSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*ec779b8eSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*ec779b8eSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*ec779b8eSAndroid Build Coastguard Worker  * limitations under the License.
15*ec779b8eSAndroid Build Coastguard Worker  */
16*ec779b8eSAndroid Build Coastguard Worker 
17*ec779b8eSAndroid Build Coastguard Worker #define LOG_TAG "NBLog"
18*ec779b8eSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
19*ec779b8eSAndroid Build Coastguard Worker 
20*ec779b8eSAndroid Build Coastguard Worker #include <memory>
21*ec779b8eSAndroid Build Coastguard Worker #include <queue>
22*ec779b8eSAndroid Build Coastguard Worker #include <stddef.h>
23*ec779b8eSAndroid Build Coastguard Worker #include <stdint.h>
24*ec779b8eSAndroid Build Coastguard Worker #include <vector>
25*ec779b8eSAndroid Build Coastguard Worker 
26*ec779b8eSAndroid Build Coastguard Worker #include <audio_utils/fifo.h>
27*ec779b8eSAndroid Build Coastguard Worker #include <json/json.h>
28*ec779b8eSAndroid Build Coastguard Worker #include <media/nblog/Merger.h>
29*ec779b8eSAndroid Build Coastguard Worker #include <media/nblog/PerformanceAnalysis.h>
30*ec779b8eSAndroid Build Coastguard Worker #include <media/nblog/ReportPerformance.h>
31*ec779b8eSAndroid Build Coastguard Worker #include <media/nblog/Reader.h>
32*ec779b8eSAndroid Build Coastguard Worker #include <media/nblog/Timeline.h>
33*ec779b8eSAndroid Build Coastguard Worker #include <utils/Condition.h>
34*ec779b8eSAndroid Build Coastguard Worker #include <utils/Log.h>
35*ec779b8eSAndroid Build Coastguard Worker #include <utils/Mutex.h>
36*ec779b8eSAndroid Build Coastguard Worker #include <utils/RefBase.h>
37*ec779b8eSAndroid Build Coastguard Worker #include <utils/String16.h>
38*ec779b8eSAndroid Build Coastguard Worker #include <utils/String8.h>
39*ec779b8eSAndroid Build Coastguard Worker #include <utils/Thread.h>
40*ec779b8eSAndroid Build Coastguard Worker #include <utils/Timers.h>
41*ec779b8eSAndroid Build Coastguard Worker #include <utils/Vector.h>
42*ec779b8eSAndroid Build Coastguard Worker 
43*ec779b8eSAndroid Build Coastguard Worker namespace android {
44*ec779b8eSAndroid Build Coastguard Worker namespace NBLog {
45*ec779b8eSAndroid Build Coastguard Worker 
Merger(const void * shared,size_t size)46*ec779b8eSAndroid Build Coastguard Worker Merger::Merger(const void *shared, size_t size):
47*ec779b8eSAndroid Build Coastguard Worker       mShared((Shared *) shared),
48*ec779b8eSAndroid Build Coastguard Worker       mFifo(mShared != NULL ?
49*ec779b8eSAndroid Build Coastguard Worker         new audio_utils_fifo(size, sizeof(uint8_t),
50*ec779b8eSAndroid Build Coastguard Worker             mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
51*ec779b8eSAndroid Build Coastguard Worker       mFifoWriter(mFifo != NULL ? new audio_utils_fifo_writer(*mFifo) : NULL)
52*ec779b8eSAndroid Build Coastguard Worker {
53*ec779b8eSAndroid Build Coastguard Worker }
54*ec779b8eSAndroid Build Coastguard Worker 
addReader(const sp<Reader> & reader)55*ec779b8eSAndroid Build Coastguard Worker void Merger::addReader(const sp<Reader> &reader)
56*ec779b8eSAndroid Build Coastguard Worker {
57*ec779b8eSAndroid Build Coastguard Worker     // FIXME This is called by binder thread in MediaLogService::registerWriter
58*ec779b8eSAndroid Build Coastguard Worker     //       but the access to shared variable mReaders is not yet protected by a lock.
59*ec779b8eSAndroid Build Coastguard Worker     mReaders.push_back(reader);
60*ec779b8eSAndroid Build Coastguard Worker }
61*ec779b8eSAndroid Build Coastguard Worker 
62*ec779b8eSAndroid Build Coastguard Worker // items placed in priority queue during merge
63*ec779b8eSAndroid Build Coastguard Worker // composed by a timestamp and the index of the snapshot where the timestamp came from
64*ec779b8eSAndroid Build Coastguard Worker struct MergeItem
65*ec779b8eSAndroid Build Coastguard Worker {
66*ec779b8eSAndroid Build Coastguard Worker     int64_t ts;
67*ec779b8eSAndroid Build Coastguard Worker     int index;
MergeItemandroid::NBLog::MergeItem68*ec779b8eSAndroid Build Coastguard Worker     MergeItem(int64_t ts, int index): ts(ts), index(index) {}
69*ec779b8eSAndroid Build Coastguard Worker };
70*ec779b8eSAndroid Build Coastguard Worker 
operator >(const struct MergeItem & i1,const struct MergeItem & i2)71*ec779b8eSAndroid Build Coastguard Worker bool operator>(const struct MergeItem &i1, const struct MergeItem &i2)
72*ec779b8eSAndroid Build Coastguard Worker {
73*ec779b8eSAndroid Build Coastguard Worker     return i1.ts > i2.ts || (i1.ts == i2.ts && i1.index > i2.index);
74*ec779b8eSAndroid Build Coastguard Worker }
75*ec779b8eSAndroid Build Coastguard Worker 
76*ec779b8eSAndroid Build Coastguard Worker // Merge registered readers, sorted by timestamp, and write data to a single FIFO in local memory
merge()77*ec779b8eSAndroid Build Coastguard Worker void Merger::merge()
78*ec779b8eSAndroid Build Coastguard Worker {
79*ec779b8eSAndroid Build Coastguard Worker     if (true) return; // Merging is not necessary at the moment, so this is to disable it
80*ec779b8eSAndroid Build Coastguard Worker                       // and bypass compiler warnings about member variables not being used.
81*ec779b8eSAndroid Build Coastguard Worker     const int nLogs = mReaders.size();
82*ec779b8eSAndroid Build Coastguard Worker     std::vector<std::unique_ptr<Snapshot>> snapshots(nLogs);
83*ec779b8eSAndroid Build Coastguard Worker     std::vector<EntryIterator> offsets;
84*ec779b8eSAndroid Build Coastguard Worker     offsets.reserve(nLogs);
85*ec779b8eSAndroid Build Coastguard Worker     for (int i = 0; i < nLogs; ++i) {
86*ec779b8eSAndroid Build Coastguard Worker         snapshots[i] = mReaders[i]->getSnapshot();
87*ec779b8eSAndroid Build Coastguard Worker         offsets.push_back(snapshots[i]->begin());
88*ec779b8eSAndroid Build Coastguard Worker     }
89*ec779b8eSAndroid Build Coastguard Worker     // initialize offsets
90*ec779b8eSAndroid Build Coastguard Worker     // TODO custom heap implementation could allow to update top, improving performance
91*ec779b8eSAndroid Build Coastguard Worker     // for bursty buffers
92*ec779b8eSAndroid Build Coastguard Worker     std::priority_queue<MergeItem, std::vector<MergeItem>, std::greater<MergeItem>> timestamps;
93*ec779b8eSAndroid Build Coastguard Worker     for (int i = 0; i < nLogs; ++i)
94*ec779b8eSAndroid Build Coastguard Worker     {
95*ec779b8eSAndroid Build Coastguard Worker         if (offsets[i] != snapshots[i]->end()) {
96*ec779b8eSAndroid Build Coastguard Worker             std::unique_ptr<AbstractEntry> abstractEntry = AbstractEntry::buildEntry(offsets[i]);
97*ec779b8eSAndroid Build Coastguard Worker             if (abstractEntry == nullptr) {
98*ec779b8eSAndroid Build Coastguard Worker                 continue;
99*ec779b8eSAndroid Build Coastguard Worker             }
100*ec779b8eSAndroid Build Coastguard Worker             timestamps.emplace(abstractEntry->timestamp(), i);
101*ec779b8eSAndroid Build Coastguard Worker         }
102*ec779b8eSAndroid Build Coastguard Worker     }
103*ec779b8eSAndroid Build Coastguard Worker 
104*ec779b8eSAndroid Build Coastguard Worker     while (!timestamps.empty()) {
105*ec779b8eSAndroid Build Coastguard Worker         int index = timestamps.top().index;     // find minimum timestamp
106*ec779b8eSAndroid Build Coastguard Worker         // copy it to the log, increasing offset
107*ec779b8eSAndroid Build Coastguard Worker         offsets[index] = AbstractEntry::buildEntry(offsets[index])->
108*ec779b8eSAndroid Build Coastguard Worker             copyWithAuthor(mFifoWriter, index);
109*ec779b8eSAndroid Build Coastguard Worker         // update data structures
110*ec779b8eSAndroid Build Coastguard Worker         timestamps.pop();
111*ec779b8eSAndroid Build Coastguard Worker         if (offsets[index] != snapshots[index]->end()) {
112*ec779b8eSAndroid Build Coastguard Worker             int64_t ts = AbstractEntry::buildEntry(offsets[index])->timestamp();
113*ec779b8eSAndroid Build Coastguard Worker             timestamps.emplace(ts, index);
114*ec779b8eSAndroid Build Coastguard Worker         }
115*ec779b8eSAndroid Build Coastguard Worker     }
116*ec779b8eSAndroid Build Coastguard Worker }
117*ec779b8eSAndroid Build Coastguard Worker 
getReaders() const118*ec779b8eSAndroid Build Coastguard Worker const std::vector<sp<Reader>>& Merger::getReaders() const
119*ec779b8eSAndroid Build Coastguard Worker {
120*ec779b8eSAndroid Build Coastguard Worker     //AutoMutex _l(mLock);
121*ec779b8eSAndroid Build Coastguard Worker     return mReaders;
122*ec779b8eSAndroid Build Coastguard Worker }
123*ec779b8eSAndroid Build Coastguard Worker 
124*ec779b8eSAndroid Build Coastguard Worker // ---------------------------------------------------------------------------
125*ec779b8eSAndroid Build Coastguard Worker 
MergeReader(const void * shared,size_t size,Merger & merger)126*ec779b8eSAndroid Build Coastguard Worker MergeReader::MergeReader(const void *shared, size_t size, Merger &merger)
127*ec779b8eSAndroid Build Coastguard Worker     : Reader(shared, size, "MergeReader"), mReaders(merger.getReaders())
128*ec779b8eSAndroid Build Coastguard Worker {
129*ec779b8eSAndroid Build Coastguard Worker }
130*ec779b8eSAndroid Build Coastguard Worker 
131*ec779b8eSAndroid Build Coastguard Worker // Takes raw content of the local merger FIFO, processes log entries, and
132*ec779b8eSAndroid Build Coastguard Worker // writes the data to a map of class PerformanceAnalysis, based on their thread ID.
processSnapshot(Snapshot & snapshot,int author)133*ec779b8eSAndroid Build Coastguard Worker void MergeReader::processSnapshot(Snapshot &snapshot, int author)
134*ec779b8eSAndroid Build Coastguard Worker {
135*ec779b8eSAndroid Build Coastguard Worker     ReportPerformance::PerformanceData& data = mThreadPerformanceData[author];
136*ec779b8eSAndroid Build Coastguard Worker     // We don't do "auto it" because it reduces readability in this case.
137*ec779b8eSAndroid Build Coastguard Worker     for (EntryIterator it = snapshot.begin(); it != snapshot.end(); ++it) {
138*ec779b8eSAndroid Build Coastguard Worker         switch (it->type) {
139*ec779b8eSAndroid Build Coastguard Worker         case EVENT_HISTOGRAM_ENTRY_TS: {
140*ec779b8eSAndroid Build Coastguard Worker             const HistTsEntry payload = it.payload<HistTsEntry>();
141*ec779b8eSAndroid Build Coastguard Worker             // TODO: hash for histogram ts and audio state need to match
142*ec779b8eSAndroid Build Coastguard Worker             // and correspond to audio production source file location
143*ec779b8eSAndroid Build Coastguard Worker             mThreadPerformanceAnalysis[author][0 /*hash*/].logTsEntry(payload.ts);
144*ec779b8eSAndroid Build Coastguard Worker         } break;
145*ec779b8eSAndroid Build Coastguard Worker         case EVENT_AUDIO_STATE: {
146*ec779b8eSAndroid Build Coastguard Worker             mThreadPerformanceAnalysis[author][0 /*hash*/].handleStateChange();
147*ec779b8eSAndroid Build Coastguard Worker         } break;
148*ec779b8eSAndroid Build Coastguard Worker         case EVENT_THREAD_INFO: {
149*ec779b8eSAndroid Build Coastguard Worker             const thread_info_t info = it.payload<thread_info_t>();
150*ec779b8eSAndroid Build Coastguard Worker             data.threadInfo = info;
151*ec779b8eSAndroid Build Coastguard Worker         } break;
152*ec779b8eSAndroid Build Coastguard Worker         case EVENT_THREAD_PARAMS: {
153*ec779b8eSAndroid Build Coastguard Worker             const thread_params_t params = it.payload<thread_params_t>();
154*ec779b8eSAndroid Build Coastguard Worker             data.threadParams = params;
155*ec779b8eSAndroid Build Coastguard Worker         } break;
156*ec779b8eSAndroid Build Coastguard Worker         case EVENT_LATENCY: {
157*ec779b8eSAndroid Build Coastguard Worker             const double latencyMs = it.payload<double>();
158*ec779b8eSAndroid Build Coastguard Worker             data.latencyHist.add(latencyMs);
159*ec779b8eSAndroid Build Coastguard Worker         } break;
160*ec779b8eSAndroid Build Coastguard Worker         case EVENT_WORK_TIME: {
161*ec779b8eSAndroid Build Coastguard Worker             const int64_t monotonicNs = it.payload<int64_t>();
162*ec779b8eSAndroid Build Coastguard Worker             const double monotonicMs = monotonicNs * 1e-6;
163*ec779b8eSAndroid Build Coastguard Worker             data.workHist.add(monotonicMs);
164*ec779b8eSAndroid Build Coastguard Worker             data.active += monotonicNs;
165*ec779b8eSAndroid Build Coastguard Worker         } break;
166*ec779b8eSAndroid Build Coastguard Worker         case EVENT_WARMUP_TIME: {
167*ec779b8eSAndroid Build Coastguard Worker             const double timeMs = it.payload<double>();
168*ec779b8eSAndroid Build Coastguard Worker             data.warmupHist.add(timeMs);
169*ec779b8eSAndroid Build Coastguard Worker         } break;
170*ec779b8eSAndroid Build Coastguard Worker         case EVENT_UNDERRUN: {
171*ec779b8eSAndroid Build Coastguard Worker             const int64_t ts = it.payload<int64_t>();
172*ec779b8eSAndroid Build Coastguard Worker             data.underruns++;
173*ec779b8eSAndroid Build Coastguard Worker             data.snapshots.emplace_front(EVENT_UNDERRUN, ts);
174*ec779b8eSAndroid Build Coastguard Worker             // TODO have a data structure to automatically handle resizing
175*ec779b8eSAndroid Build Coastguard Worker             if (data.snapshots.size() > ReportPerformance::PerformanceData::kMaxSnapshotsToStore) {
176*ec779b8eSAndroid Build Coastguard Worker                 data.snapshots.pop_back();
177*ec779b8eSAndroid Build Coastguard Worker             }
178*ec779b8eSAndroid Build Coastguard Worker         } break;
179*ec779b8eSAndroid Build Coastguard Worker         case EVENT_OVERRUN: {
180*ec779b8eSAndroid Build Coastguard Worker             const int64_t ts = it.payload<int64_t>();
181*ec779b8eSAndroid Build Coastguard Worker             data.overruns++;
182*ec779b8eSAndroid Build Coastguard Worker             data.snapshots.emplace_front(EVENT_UNDERRUN, ts);
183*ec779b8eSAndroid Build Coastguard Worker             // TODO have a data structure to automatically handle resizing
184*ec779b8eSAndroid Build Coastguard Worker             if (data.snapshots.size() > ReportPerformance::PerformanceData::kMaxSnapshotsToStore) {
185*ec779b8eSAndroid Build Coastguard Worker                 data.snapshots.pop_back();
186*ec779b8eSAndroid Build Coastguard Worker             }
187*ec779b8eSAndroid Build Coastguard Worker         } break;
188*ec779b8eSAndroid Build Coastguard Worker         case EVENT_RESERVED:
189*ec779b8eSAndroid Build Coastguard Worker         case EVENT_UPPER_BOUND:
190*ec779b8eSAndroid Build Coastguard Worker             ALOGW("warning: unexpected event %d", it->type);
191*ec779b8eSAndroid Build Coastguard Worker             break;
192*ec779b8eSAndroid Build Coastguard Worker         default:
193*ec779b8eSAndroid Build Coastguard Worker             break;
194*ec779b8eSAndroid Build Coastguard Worker         }
195*ec779b8eSAndroid Build Coastguard Worker     }
196*ec779b8eSAndroid Build Coastguard Worker }
197*ec779b8eSAndroid Build Coastguard Worker 
getAndProcessSnapshot()198*ec779b8eSAndroid Build Coastguard Worker void MergeReader::getAndProcessSnapshot()
199*ec779b8eSAndroid Build Coastguard Worker {
200*ec779b8eSAndroid Build Coastguard Worker     // get a snapshot of each reader and process them
201*ec779b8eSAndroid Build Coastguard Worker     // TODO insert lock here
202*ec779b8eSAndroid Build Coastguard Worker     const size_t nLogs = mReaders.size();
203*ec779b8eSAndroid Build Coastguard Worker     std::vector<std::unique_ptr<Snapshot>> snapshots(nLogs);
204*ec779b8eSAndroid Build Coastguard Worker     for (size_t i = 0; i < nLogs; i++) {
205*ec779b8eSAndroid Build Coastguard Worker         snapshots[i] = mReaders[i]->getSnapshot();
206*ec779b8eSAndroid Build Coastguard Worker     }
207*ec779b8eSAndroid Build Coastguard Worker     // TODO unlock lock here
208*ec779b8eSAndroid Build Coastguard Worker     for (size_t i = 0; i < nLogs; i++) {
209*ec779b8eSAndroid Build Coastguard Worker         if (snapshots[i] != nullptr) {
210*ec779b8eSAndroid Build Coastguard Worker             processSnapshot(*(snapshots[i]), i);
211*ec779b8eSAndroid Build Coastguard Worker         }
212*ec779b8eSAndroid Build Coastguard Worker     }
213*ec779b8eSAndroid Build Coastguard Worker     checkPushToMediaMetrics();
214*ec779b8eSAndroid Build Coastguard Worker }
215*ec779b8eSAndroid Build Coastguard Worker 
checkPushToMediaMetrics()216*ec779b8eSAndroid Build Coastguard Worker void MergeReader::checkPushToMediaMetrics()
217*ec779b8eSAndroid Build Coastguard Worker {
218*ec779b8eSAndroid Build Coastguard Worker     const nsecs_t now = systemTime();
219*ec779b8eSAndroid Build Coastguard Worker     for (auto& item : mThreadPerformanceData) {
220*ec779b8eSAndroid Build Coastguard Worker         ReportPerformance::PerformanceData& data = item.second;
221*ec779b8eSAndroid Build Coastguard Worker         if (now - data.start >= kPeriodicMediaMetricsPush) {
222*ec779b8eSAndroid Build Coastguard Worker             (void)ReportPerformance::sendToMediaMetrics(data);
223*ec779b8eSAndroid Build Coastguard Worker             data.reset();   // data is persistent per thread
224*ec779b8eSAndroid Build Coastguard Worker         }
225*ec779b8eSAndroid Build Coastguard Worker     }
226*ec779b8eSAndroid Build Coastguard Worker }
227*ec779b8eSAndroid Build Coastguard Worker 
dump(int fd,const Vector<String16> & args)228*ec779b8eSAndroid Build Coastguard Worker void MergeReader::dump(int fd, const Vector<String16>& args)
229*ec779b8eSAndroid Build Coastguard Worker {
230*ec779b8eSAndroid Build Coastguard Worker     // TODO: add a mutex around media.log dump
231*ec779b8eSAndroid Build Coastguard Worker     // Options for dumpsys
232*ec779b8eSAndroid Build Coastguard Worker     bool pa = false, json = false, plots = false, retro = false;
233*ec779b8eSAndroid Build Coastguard Worker     for (const auto &arg : args) {
234*ec779b8eSAndroid Build Coastguard Worker         if (arg == String16("--pa")) {
235*ec779b8eSAndroid Build Coastguard Worker             pa = true;
236*ec779b8eSAndroid Build Coastguard Worker         } else if (arg == String16("--json")) {
237*ec779b8eSAndroid Build Coastguard Worker             json = true;
238*ec779b8eSAndroid Build Coastguard Worker         } else if (arg == String16("--plots")) {
239*ec779b8eSAndroid Build Coastguard Worker             plots = true;
240*ec779b8eSAndroid Build Coastguard Worker         } else if (arg == String16("--retro")) {
241*ec779b8eSAndroid Build Coastguard Worker             retro = true;
242*ec779b8eSAndroid Build Coastguard Worker         }
243*ec779b8eSAndroid Build Coastguard Worker     }
244*ec779b8eSAndroid Build Coastguard Worker     if (pa) {
245*ec779b8eSAndroid Build Coastguard Worker         ReportPerformance::dump(fd, 0 /*indent*/, mThreadPerformanceAnalysis);
246*ec779b8eSAndroid Build Coastguard Worker     }
247*ec779b8eSAndroid Build Coastguard Worker     if (json) {
248*ec779b8eSAndroid Build Coastguard Worker         ReportPerformance::dumpJson(fd, mThreadPerformanceData);
249*ec779b8eSAndroid Build Coastguard Worker     }
250*ec779b8eSAndroid Build Coastguard Worker     if (plots) {
251*ec779b8eSAndroid Build Coastguard Worker         ReportPerformance::dumpPlots(fd, mThreadPerformanceData);
252*ec779b8eSAndroid Build Coastguard Worker     }
253*ec779b8eSAndroid Build Coastguard Worker     if (retro) {
254*ec779b8eSAndroid Build Coastguard Worker         ReportPerformance::dumpRetro(fd, mThreadPerformanceData);
255*ec779b8eSAndroid Build Coastguard Worker     }
256*ec779b8eSAndroid Build Coastguard Worker }
257*ec779b8eSAndroid Build Coastguard Worker 
handleAuthor(const AbstractEntry & entry,String8 * body)258*ec779b8eSAndroid Build Coastguard Worker void MergeReader::handleAuthor(const AbstractEntry &entry, String8 *body)
259*ec779b8eSAndroid Build Coastguard Worker {
260*ec779b8eSAndroid Build Coastguard Worker     int author = entry.author();
261*ec779b8eSAndroid Build Coastguard Worker     if (author == -1) {
262*ec779b8eSAndroid Build Coastguard Worker         return;
263*ec779b8eSAndroid Build Coastguard Worker     }
264*ec779b8eSAndroid Build Coastguard Worker     // FIXME Needs a lock
265*ec779b8eSAndroid Build Coastguard Worker     const char* name = mReaders[author]->name().c_str();
266*ec779b8eSAndroid Build Coastguard Worker     body->appendFormat("%s: ", name);
267*ec779b8eSAndroid Build Coastguard Worker }
268*ec779b8eSAndroid Build Coastguard Worker 
269*ec779b8eSAndroid Build Coastguard Worker // ---------------------------------------------------------------------------
270*ec779b8eSAndroid Build Coastguard Worker 
MergeThread(Merger & merger,MergeReader & mergeReader)271*ec779b8eSAndroid Build Coastguard Worker MergeThread::MergeThread(Merger &merger, MergeReader &mergeReader)
272*ec779b8eSAndroid Build Coastguard Worker     : mMerger(merger),
273*ec779b8eSAndroid Build Coastguard Worker       mMergeReader(mergeReader),
274*ec779b8eSAndroid Build Coastguard Worker       mTimeoutUs(0)
275*ec779b8eSAndroid Build Coastguard Worker {
276*ec779b8eSAndroid Build Coastguard Worker }
277*ec779b8eSAndroid Build Coastguard Worker 
~MergeThread()278*ec779b8eSAndroid Build Coastguard Worker MergeThread::~MergeThread()
279*ec779b8eSAndroid Build Coastguard Worker {
280*ec779b8eSAndroid Build Coastguard Worker     // set exit flag, set timeout to 0 to force threadLoop to exit and wait for the thread to join
281*ec779b8eSAndroid Build Coastguard Worker     requestExit();
282*ec779b8eSAndroid Build Coastguard Worker     setTimeoutUs(0);
283*ec779b8eSAndroid Build Coastguard Worker     join();
284*ec779b8eSAndroid Build Coastguard Worker }
285*ec779b8eSAndroid Build Coastguard Worker 
threadLoop()286*ec779b8eSAndroid Build Coastguard Worker bool MergeThread::threadLoop()
287*ec779b8eSAndroid Build Coastguard Worker {
288*ec779b8eSAndroid Build Coastguard Worker     bool doMerge;
289*ec779b8eSAndroid Build Coastguard Worker     {
290*ec779b8eSAndroid Build Coastguard Worker         AutoMutex _l(mMutex);
291*ec779b8eSAndroid Build Coastguard Worker         // If mTimeoutUs is negative, wait on the condition variable until it's positive.
292*ec779b8eSAndroid Build Coastguard Worker         // If it's positive, merge. The minimum period between waking the condition variable
293*ec779b8eSAndroid Build Coastguard Worker         // is handled in AudioFlinger::MediaLogNotifier::threadLoop().
294*ec779b8eSAndroid Build Coastguard Worker         mCond.wait(mMutex);
295*ec779b8eSAndroid Build Coastguard Worker         doMerge = mTimeoutUs > 0;
296*ec779b8eSAndroid Build Coastguard Worker         mTimeoutUs -= kThreadSleepPeriodUs;
297*ec779b8eSAndroid Build Coastguard Worker     }
298*ec779b8eSAndroid Build Coastguard Worker     if (doMerge) {
299*ec779b8eSAndroid Build Coastguard Worker         // Merge data from all the readers
300*ec779b8eSAndroid Build Coastguard Worker         mMerger.merge();
301*ec779b8eSAndroid Build Coastguard Worker         // Process the data collected by mMerger and write it to PerformanceAnalysis
302*ec779b8eSAndroid Build Coastguard Worker         // FIXME: decide whether to call getAndProcessSnapshot every time
303*ec779b8eSAndroid Build Coastguard Worker         // or whether to have a separate thread that calls it with a lower frequency
304*ec779b8eSAndroid Build Coastguard Worker         mMergeReader.getAndProcessSnapshot();
305*ec779b8eSAndroid Build Coastguard Worker     }
306*ec779b8eSAndroid Build Coastguard Worker     return true;
307*ec779b8eSAndroid Build Coastguard Worker }
308*ec779b8eSAndroid Build Coastguard Worker 
wakeup()309*ec779b8eSAndroid Build Coastguard Worker void MergeThread::wakeup()
310*ec779b8eSAndroid Build Coastguard Worker {
311*ec779b8eSAndroid Build Coastguard Worker     setTimeoutUs(kThreadWakeupPeriodUs);
312*ec779b8eSAndroid Build Coastguard Worker }
313*ec779b8eSAndroid Build Coastguard Worker 
setTimeoutUs(int time)314*ec779b8eSAndroid Build Coastguard Worker void MergeThread::setTimeoutUs(int time)
315*ec779b8eSAndroid Build Coastguard Worker {
316*ec779b8eSAndroid Build Coastguard Worker     AutoMutex _l(mMutex);
317*ec779b8eSAndroid Build Coastguard Worker     mTimeoutUs = time;
318*ec779b8eSAndroid Build Coastguard Worker     mCond.signal();
319*ec779b8eSAndroid Build Coastguard Worker }
320*ec779b8eSAndroid Build Coastguard Worker 
321*ec779b8eSAndroid Build Coastguard Worker }   // namespace NBLog
322*ec779b8eSAndroid Build Coastguard Worker }   // namespace android
323