blob: 15431529522937f696e57147604e1b67a5c7203c [file] [log] [blame]
Glenn Kasten97b5d0d2012-03-23 18:54:19 -07001/*
2 * Copyright (C) 2012 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#define LOG_TAG "FastMixer"
18//#define LOG_NDEBUG 0
19
20#include <sys/atomics.h>
21#include <time.h>
22#include <utils/Log.h>
23#include <system/audio.h>
24#ifdef FAST_MIXER_STATISTICS
25#include <cpustats/CentralTendencyStatistics.h>
26#endif
27#include "AudioMixer.h"
28#include "FastMixer.h"
29
30#define FAST_HOT_IDLE_NS 1000000L // 1 ms: time to sleep while hot idling
31#define FAST_DEFAULT_NS 999999999L // ~1 sec: default time to sleep
32
33namespace android {
34
35// Fast mixer thread
36bool FastMixer::threadLoop()
37{
38 static const FastMixerState initial;
39 const FastMixerState *previous = &initial, *current = &initial;
40 FastMixerState preIdle; // copy of state before we went into idle
41 struct timespec oldTs = {0, 0};
42 bool oldTsValid = false;
43 long slopNs = 0; // accumulated time we've woken up too early (> 0) or too late (< 0)
44 long sleepNs = -1; // -1: busy wait, 0: sched_yield, > 0: nanosleep
45 int fastTrackNames[FastMixerState::kMaxFastTracks]; // handles used by mixer to identify tracks
46 int generations[FastMixerState::kMaxFastTracks]; // last observed mFastTracks[i].mGeneration
47 unsigned i;
48 for (i = 0; i < FastMixerState::kMaxFastTracks; ++i) {
49 fastTrackNames[i] = -1;
50 generations[i] = 0;
51 }
52 NBAIO_Sink *outputSink = NULL;
53 int outputSinkGen = 0;
54 AudioMixer* mixer = NULL;
55 short *mixBuffer = NULL;
56 enum {UNDEFINED, MIXED, ZEROED} mixBufferState = UNDEFINED;
57 NBAIO_Format format = Format_Invalid;
58 unsigned sampleRate = 0;
59 int fastTracksGen = 0;
60 long periodNs = 0; // expected period; the time required to render one mix buffer
61 long underrunNs = 0; // an underrun is likely if an actual cycle is greater than this value
62 long overrunNs = 0; // an overrun is likely if an actual cycle if less than this value
63 FastMixerDumpState dummyDumpState, *dumpState = &dummyDumpState;
64 bool ignoreNextOverrun = true; // used to ignore initial overrun and first after an underrun
65#ifdef FAST_MIXER_STATISTICS
66 CentralTendencyStatistics cts; // cycle times in seconds
67 static const unsigned kMaxSamples = 1000;
68#endif
69 unsigned coldGen = 0; // last observed mColdGen
70
71 for (;;) {
72
73 // either nanosleep, sched_yield, or busy wait
74 if (sleepNs >= 0) {
75 if (sleepNs > 0) {
76 ALOG_ASSERT(sleepNs < 1000000000);
77 const struct timespec req = {0, sleepNs};
78 nanosleep(&req, NULL);
79 } else {
80 sched_yield();
81 }
82 }
83 // default to long sleep for next cycle
84 sleepNs = FAST_DEFAULT_NS;
85
86 // poll for state change
87 const FastMixerState *next = mSQ.poll();
88 if (next == NULL) {
89 // continue to use the default initial state until a real state is available
90 ALOG_ASSERT(current == &initial && previous == &initial);
91 next = current;
92 }
93
94 FastMixerState::Command command = next->mCommand;
95 if (next != current) {
96
97 // As soon as possible of learning of a new dump area, start using it
98 dumpState = next->mDumpState != NULL ? next->mDumpState : &dummyDumpState;
99
100 // We want to always have a valid reference to the previous (non-idle) state.
101 // However, the state queue only guarantees access to current and previous states.
102 // So when there is a transition from a non-idle state into an idle state, we make a
103 // copy of the last known non-idle state so it is still available on return from idle.
104 // The possible transitions are:
105 // non-idle -> non-idle update previous from current in-place
106 // non-idle -> idle update previous from copy of current
107 // idle -> idle don't update previous
108 // idle -> non-idle don't update previous
109 if (!(current->mCommand & FastMixerState::IDLE)) {
110 if (command & FastMixerState::IDLE) {
111 preIdle = *current;
112 current = &preIdle;
113 oldTsValid = false;
114 ignoreNextOverrun = true;
115 }
116 previous = current;
117 }
118 current = next;
119 }
120#if !LOG_NDEBUG
121 next = NULL; // not referenced again
122#endif
123
124 dumpState->mCommand = command;
125
126 switch (command) {
127 case FastMixerState::INITIAL:
128 case FastMixerState::HOT_IDLE:
129 sleepNs = FAST_HOT_IDLE_NS;
130 continue;
131 case FastMixerState::COLD_IDLE:
132 // only perform a cold idle command once
133 if (current->mColdGen != coldGen) {
134 int32_t *coldFutexAddr = current->mColdFutexAddr;
135 ALOG_ASSERT(coldFutexAddr != NULL);
136 int32_t old = android_atomic_dec(coldFutexAddr);
137 if (old <= 0) {
138 __futex_syscall4(coldFutexAddr, FUTEX_WAIT_PRIVATE, old - 1, NULL);
139 }
140 sleepNs = -1;
141 coldGen = current->mColdGen;
142 } else {
143 sleepNs = FAST_HOT_IDLE_NS;
144 }
145 continue;
146 case FastMixerState::EXIT:
147 delete mixer;
148 delete[] mixBuffer;
149 return false;
150 case FastMixerState::MIX:
151 case FastMixerState::WRITE:
152 case FastMixerState::MIX_WRITE:
153 break;
154 default:
155 LOG_FATAL("bad command %d", command);
156 }
157
158 // there is a non-idle state available to us; did the state change?
159 size_t frameCount = current->mFrameCount;
160 if (current != previous) {
161
162 // handle state change here, but since we want to diff the state,
163 // we're prepared for previous == &initial the first time through
164 unsigned previousTrackMask;
165
166 // check for change in output HAL configuration
167 NBAIO_Format previousFormat = format;
168 if (current->mOutputSinkGen != outputSinkGen) {
169 outputSink = current->mOutputSink;
170 outputSinkGen = current->mOutputSinkGen;
171 if (outputSink == NULL) {
172 format = Format_Invalid;
173 sampleRate = 0;
174 } else {
175 format = outputSink->format();
176 sampleRate = Format_sampleRate(format);
177 ALOG_ASSERT(Format_channelCount(format) == 2);
178 }
179 }
180
181 if ((format != previousFormat) || (frameCount != previous->mFrameCount)) {
182 // FIXME to avoid priority inversion, don't delete here
183 delete mixer;
184 mixer = NULL;
185 delete[] mixBuffer;
186 mixBuffer = NULL;
187 if (frameCount > 0 && sampleRate > 0) {
188 // FIXME new may block for unbounded time at internal mutex of the heap
189 // implementation; it would be better to have normal mixer allocate for us
190 // to avoid blocking here and to prevent possible priority inversion
191 mixer = new AudioMixer(frameCount, sampleRate, FastMixerState::kMaxFastTracks);
192 mixBuffer = new short[frameCount * 2];
193 periodNs = (frameCount * 1000000000LL) / sampleRate; // 1.00
194 underrunNs = (frameCount * 1750000000LL) / sampleRate; // 1.75
195 overrunNs = (frameCount * 250000000LL) / sampleRate; // 0.25
196 } else {
197 periodNs = 0;
198 underrunNs = 0;
199 overrunNs = 0;
200 }
201 mixBufferState = UNDEFINED;
202#if !LOG_NDEBUG
203 for (i = 0; i < FastMixerState::kMaxFastTracks; ++i) {
204 fastTrackNames[i] = -1;
205 }
206#endif
207 // we need to reconfigure all active tracks
208 previousTrackMask = 0;
209 fastTracksGen = current->mFastTracksGen - 1;
210 } else {
211 previousTrackMask = previous->mTrackMask;
212 }
213
214 // check for change in active track set
215 unsigned currentTrackMask = current->mTrackMask;
216 if (current->mFastTracksGen != fastTracksGen) {
217 ALOG_ASSERT(mixBuffer != NULL);
218 int name;
219
220 // process removed tracks first to avoid running out of track names
221 unsigned removedTracks = previousTrackMask & ~currentTrackMask;
222 while (removedTracks != 0) {
223 i = __builtin_ctz(removedTracks);
224 removedTracks &= ~(1 << i);
225 const FastTrack* fastTrack = &current->mFastTracks[i];
226 if (mixer != NULL) {
227 name = fastTrackNames[i];
228 ALOG_ASSERT(name >= 0);
229 mixer->deleteTrackName(name);
230 }
231#if !LOG_NDEBUG
232 fastTrackNames[i] = -1;
233#endif
234 generations[i] = fastTrack->mGeneration;
235 }
236
237 // now process added tracks
238 unsigned addedTracks = currentTrackMask & ~previousTrackMask;
239 while (addedTracks != 0) {
240 i = __builtin_ctz(addedTracks);
241 addedTracks &= ~(1 << i);
242 const FastTrack* fastTrack = &current->mFastTracks[i];
243 AudioBufferProvider *bufferProvider = fastTrack->mBufferProvider;
244 ALOG_ASSERT(bufferProvider != NULL && fastTrackNames[i] == -1);
245 if (mixer != NULL) {
246 name = mixer->getTrackName();
247 ALOG_ASSERT(name >= 0);
248 fastTrackNames[i] = name;
249 mixer->setBufferProvider(name, bufferProvider);
250 mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER,
251 (void *) mixBuffer);
252 // newly allocated track names default to full scale volume
253 mixer->enable(name);
254 }
255 generations[i] = fastTrack->mGeneration;
256 }
257
258 // finally process modified tracks; these use the same slot
259 // but may have a different buffer provider or volume provider
260 unsigned modifiedTracks = currentTrackMask & previousTrackMask;
261 while (modifiedTracks != 0) {
262 i = __builtin_ctz(modifiedTracks);
263 modifiedTracks &= ~(1 << i);
264 const FastTrack* fastTrack = &current->mFastTracks[i];
265 if (fastTrack->mGeneration != generations[i]) {
266 AudioBufferProvider *bufferProvider = fastTrack->mBufferProvider;
267 ALOG_ASSERT(bufferProvider != NULL);
268 if (mixer != NULL) {
269 name = fastTrackNames[i];
270 ALOG_ASSERT(name >= 0);
271 mixer->setBufferProvider(name, bufferProvider);
272 if (fastTrack->mVolumeProvider == NULL) {
273 mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0,
274 (void *)0x1000);
275 mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1,
276 (void *)0x1000);
277 }
278 // already enabled
279 }
280 generations[i] = fastTrack->mGeneration;
281 }
282 }
283
284 fastTracksGen = current->mFastTracksGen;
285
286 dumpState->mNumTracks = popcount(currentTrackMask);
287 }
288
289#if 1 // FIXME shouldn't need this
290 // only process state change once
291 previous = current;
292#endif
293 }
294
295 // do work using current state here
296 if ((command & FastMixerState::MIX) && (mixer != NULL)) {
297 ALOG_ASSERT(mixBuffer != NULL);
298 // update volumes
299 unsigned volumeTracks = current->mTrackMask;
300 while (volumeTracks != 0) {
301 i = __builtin_ctz(volumeTracks);
302 volumeTracks &= ~(1 << i);
303 const FastTrack* fastTrack = &current->mFastTracks[i];
304 int name = fastTrackNames[i];
305 ALOG_ASSERT(name >= 0);
306 if (fastTrack->mVolumeProvider != NULL) {
307 uint32_t vlr = fastTrack->mVolumeProvider->getVolumeLR();
308 mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0,
309 (void *)(vlr & 0xFFFF));
310 mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1,
311 (void *)(vlr >> 16));
312 }
313 }
314 // process() is CPU-bound
315 mixer->process(AudioBufferProvider::kInvalidPTS);
316 mixBufferState = MIXED;
317 } else if (mixBufferState == MIXED) {
318 mixBufferState = UNDEFINED;
319 }
320 if ((command & FastMixerState::WRITE) && (outputSink != NULL) && (mixBuffer != NULL)) {
321 if (mixBufferState == UNDEFINED) {
322 memset(mixBuffer, 0, frameCount * 2 * sizeof(short));
323 mixBufferState = ZEROED;
324 }
325 // FIXME write() is non-blocking and lock-free for a properly implemented NBAIO sink,
326 // but this code should be modified to handle both non-blocking and blocking sinks
327 dumpState->mWriteSequence++;
328 ssize_t framesWritten = outputSink->write(mixBuffer, frameCount);
329 dumpState->mWriteSequence++;
330 if (framesWritten >= 0) {
331 dumpState->mFramesWritten += framesWritten;
332 } else {
333 dumpState->mWriteErrors++;
334 }
335 // FIXME count # of writes blocked excessively, CPU usage, etc. for dump
336 }
337
338 // To be exactly periodic, compute the next sleep time based on current time.
339 // This code doesn't have long-term stability when the sink is non-blocking.
340 // FIXME To avoid drift, use the local audio clock or watch the sink's fill status.
341 struct timespec newTs;
342 int rc = clock_gettime(CLOCK_MONOTONIC, &newTs);
343 if (rc == 0) {
344 if (oldTsValid) {
345 time_t sec = newTs.tv_sec - oldTs.tv_sec;
346 long nsec = newTs.tv_nsec - oldTs.tv_nsec;
347 if (nsec < 0) {
348 --sec;
349 nsec += 1000000000;
350 }
351 if (sec > 0 || nsec > underrunNs) {
352 // FIXME only log occasionally
353 ALOGV("underrun: time since last cycle %d.%03ld sec",
354 (int) sec, nsec / 1000000L);
355 dumpState->mUnderruns++;
356 sleepNs = -1;
357 ignoreNextOverrun = true;
358 } else if (nsec < overrunNs) {
359 if (ignoreNextOverrun) {
360 ignoreNextOverrun = false;
361 } else {
362 // FIXME only log occasionally
363 ALOGV("overrun: time since last cycle %d.%03ld sec",
364 (int) sec, nsec / 1000000L);
365 dumpState->mOverruns++;
366 }
367 sleepNs = periodNs - overrunNs;
368 } else {
369 sleepNs = -1;
370 ignoreNextOverrun = false;
371 }
372#ifdef FAST_MIXER_STATISTICS
373 // long-term statistics
374 cts.sample(sec + nsec * 1e-9);
375 if (cts.n() >= kMaxSamples) {
376 dumpState->mMean = cts.mean();
377 dumpState->mMinimum = cts.minimum();
378 dumpState->mMaximum = cts.maximum();
379 dumpState->mStddev = cts.stddev();
380 cts.reset();
381 }
382#endif
383 } else {
384 // first time through the loop
385 oldTsValid = true;
386 sleepNs = periodNs;
387 ignoreNextOverrun = true;
388 }
389 oldTs = newTs;
390 } else {
391 // monotonic clock is broken
392 oldTsValid = false;
393 sleepNs = periodNs;
394 }
395
396 } // for (;;)
397
398 // never return 'true'; Thread::_threadLoop() locks mutex which can result in priority inversion
399}
400
401FastMixerDumpState::FastMixerDumpState() :
402 mCommand(FastMixerState::INITIAL), mWriteSequence(0), mFramesWritten(0),
403 mNumTracks(0), mWriteErrors(0), mUnderruns(0), mOverruns(0)
404#ifdef FAST_MIXER_STATISTICS
405 , mMean(0.0), mMinimum(0.0), mMaximum(0.0), mStddev(0.0)
406#endif
407{
408}
409
410FastMixerDumpState::~FastMixerDumpState()
411{
412}
413
414void FastMixerDumpState::dump(int fd)
415{
416#define COMMAND_MAX 32
417 char string[COMMAND_MAX];
418 switch (mCommand) {
419 case FastMixerState::INITIAL:
420 strcpy(string, "INITIAL");
421 break;
422 case FastMixerState::HOT_IDLE:
423 strcpy(string, "HOT_IDLE");
424 break;
425 case FastMixerState::COLD_IDLE:
426 strcpy(string, "COLD_IDLE");
427 break;
428 case FastMixerState::EXIT:
429 strcpy(string, "EXIT");
430 break;
431 case FastMixerState::MIX:
432 strcpy(string, "MIX");
433 break;
434 case FastMixerState::WRITE:
435 strcpy(string, "WRITE");
436 break;
437 case FastMixerState::MIX_WRITE:
438 strcpy(string, "MIX_WRITE");
439 break;
440 default:
441 snprintf(string, COMMAND_MAX, "%d", mCommand);
442 break;
443 }
444 fdprintf(fd, "FastMixer command=%s writeSequence=%u framesWritten=%u\n"
445 " numTracks=%u writeErrors=%u underruns=%u overruns=%u\n",
446 string, mWriteSequence, mFramesWritten,
447 mNumTracks, mWriteErrors, mUnderruns, mOverruns);
448#ifdef FAST_MIXER_STATISTICS
449 fdprintf(fd, " cycle time in ms: mean=%.1f min=%.1f max=%.1f stddev=%.1f\n",
450 mMean*1e3, mMinimum*1e3, mMaximum*1e3, mStddev*1e3);
451#endif
452}
453
454} // namespace android