blob: 14954f747b17bf72e52d704ccaba018f2b9e7f77 [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) {
Jean-Michel Trivi9bd23222012-04-16 13:43:48 -0700246 // calling getTrackName with default channel mask
247 name = mixer->getTrackName(AUDIO_CHANNEL_OUT_STEREO);
Glenn Kasten97b5d0d2012-03-23 18:54:19 -0700248 ALOG_ASSERT(name >= 0);
249 fastTrackNames[i] = name;
250 mixer->setBufferProvider(name, bufferProvider);
251 mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER,
252 (void *) mixBuffer);
253 // newly allocated track names default to full scale volume
254 mixer->enable(name);
255 }
256 generations[i] = fastTrack->mGeneration;
257 }
258
259 // finally process modified tracks; these use the same slot
260 // but may have a different buffer provider or volume provider
261 unsigned modifiedTracks = currentTrackMask & previousTrackMask;
262 while (modifiedTracks != 0) {
263 i = __builtin_ctz(modifiedTracks);
264 modifiedTracks &= ~(1 << i);
265 const FastTrack* fastTrack = &current->mFastTracks[i];
266 if (fastTrack->mGeneration != generations[i]) {
267 AudioBufferProvider *bufferProvider = fastTrack->mBufferProvider;
268 ALOG_ASSERT(bufferProvider != NULL);
269 if (mixer != NULL) {
270 name = fastTrackNames[i];
271 ALOG_ASSERT(name >= 0);
272 mixer->setBufferProvider(name, bufferProvider);
273 if (fastTrack->mVolumeProvider == NULL) {
274 mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0,
275 (void *)0x1000);
276 mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1,
277 (void *)0x1000);
278 }
279 // already enabled
280 }
281 generations[i] = fastTrack->mGeneration;
282 }
283 }
284
285 fastTracksGen = current->mFastTracksGen;
286
287 dumpState->mNumTracks = popcount(currentTrackMask);
288 }
289
290#if 1 // FIXME shouldn't need this
291 // only process state change once
292 previous = current;
293#endif
294 }
295
296 // do work using current state here
297 if ((command & FastMixerState::MIX) && (mixer != NULL)) {
298 ALOG_ASSERT(mixBuffer != NULL);
299 // update volumes
300 unsigned volumeTracks = current->mTrackMask;
301 while (volumeTracks != 0) {
302 i = __builtin_ctz(volumeTracks);
303 volumeTracks &= ~(1 << i);
304 const FastTrack* fastTrack = &current->mFastTracks[i];
305 int name = fastTrackNames[i];
306 ALOG_ASSERT(name >= 0);
307 if (fastTrack->mVolumeProvider != NULL) {
308 uint32_t vlr = fastTrack->mVolumeProvider->getVolumeLR();
309 mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0,
310 (void *)(vlr & 0xFFFF));
311 mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1,
312 (void *)(vlr >> 16));
313 }
314 }
315 // process() is CPU-bound
316 mixer->process(AudioBufferProvider::kInvalidPTS);
317 mixBufferState = MIXED;
318 } else if (mixBufferState == MIXED) {
319 mixBufferState = UNDEFINED;
320 }
321 if ((command & FastMixerState::WRITE) && (outputSink != NULL) && (mixBuffer != NULL)) {
322 if (mixBufferState == UNDEFINED) {
323 memset(mixBuffer, 0, frameCount * 2 * sizeof(short));
324 mixBufferState = ZEROED;
325 }
326 // FIXME write() is non-blocking and lock-free for a properly implemented NBAIO sink,
327 // but this code should be modified to handle both non-blocking and blocking sinks
328 dumpState->mWriteSequence++;
329 ssize_t framesWritten = outputSink->write(mixBuffer, frameCount);
330 dumpState->mWriteSequence++;
331 if (framesWritten >= 0) {
332 dumpState->mFramesWritten += framesWritten;
333 } else {
334 dumpState->mWriteErrors++;
335 }
336 // FIXME count # of writes blocked excessively, CPU usage, etc. for dump
337 }
338
339 // To be exactly periodic, compute the next sleep time based on current time.
340 // This code doesn't have long-term stability when the sink is non-blocking.
341 // FIXME To avoid drift, use the local audio clock or watch the sink's fill status.
342 struct timespec newTs;
343 int rc = clock_gettime(CLOCK_MONOTONIC, &newTs);
344 if (rc == 0) {
345 if (oldTsValid) {
346 time_t sec = newTs.tv_sec - oldTs.tv_sec;
347 long nsec = newTs.tv_nsec - oldTs.tv_nsec;
348 if (nsec < 0) {
349 --sec;
350 nsec += 1000000000;
351 }
352 if (sec > 0 || nsec > underrunNs) {
353 // FIXME only log occasionally
354 ALOGV("underrun: time since last cycle %d.%03ld sec",
355 (int) sec, nsec / 1000000L);
356 dumpState->mUnderruns++;
357 sleepNs = -1;
358 ignoreNextOverrun = true;
359 } else if (nsec < overrunNs) {
360 if (ignoreNextOverrun) {
361 ignoreNextOverrun = false;
362 } else {
363 // FIXME only log occasionally
364 ALOGV("overrun: time since last cycle %d.%03ld sec",
365 (int) sec, nsec / 1000000L);
366 dumpState->mOverruns++;
367 }
368 sleepNs = periodNs - overrunNs;
369 } else {
370 sleepNs = -1;
371 ignoreNextOverrun = false;
372 }
373#ifdef FAST_MIXER_STATISTICS
374 // long-term statistics
375 cts.sample(sec + nsec * 1e-9);
376 if (cts.n() >= kMaxSamples) {
377 dumpState->mMean = cts.mean();
378 dumpState->mMinimum = cts.minimum();
379 dumpState->mMaximum = cts.maximum();
380 dumpState->mStddev = cts.stddev();
381 cts.reset();
382 }
383#endif
384 } else {
385 // first time through the loop
386 oldTsValid = true;
387 sleepNs = periodNs;
388 ignoreNextOverrun = true;
389 }
390 oldTs = newTs;
391 } else {
392 // monotonic clock is broken
393 oldTsValid = false;
394 sleepNs = periodNs;
395 }
396
397 } // for (;;)
398
399 // never return 'true'; Thread::_threadLoop() locks mutex which can result in priority inversion
400}
401
402FastMixerDumpState::FastMixerDumpState() :
403 mCommand(FastMixerState::INITIAL), mWriteSequence(0), mFramesWritten(0),
404 mNumTracks(0), mWriteErrors(0), mUnderruns(0), mOverruns(0)
405#ifdef FAST_MIXER_STATISTICS
406 , mMean(0.0), mMinimum(0.0), mMaximum(0.0), mStddev(0.0)
407#endif
408{
409}
410
411FastMixerDumpState::~FastMixerDumpState()
412{
413}
414
415void FastMixerDumpState::dump(int fd)
416{
417#define COMMAND_MAX 32
418 char string[COMMAND_MAX];
419 switch (mCommand) {
420 case FastMixerState::INITIAL:
421 strcpy(string, "INITIAL");
422 break;
423 case FastMixerState::HOT_IDLE:
424 strcpy(string, "HOT_IDLE");
425 break;
426 case FastMixerState::COLD_IDLE:
427 strcpy(string, "COLD_IDLE");
428 break;
429 case FastMixerState::EXIT:
430 strcpy(string, "EXIT");
431 break;
432 case FastMixerState::MIX:
433 strcpy(string, "MIX");
434 break;
435 case FastMixerState::WRITE:
436 strcpy(string, "WRITE");
437 break;
438 case FastMixerState::MIX_WRITE:
439 strcpy(string, "MIX_WRITE");
440 break;
441 default:
442 snprintf(string, COMMAND_MAX, "%d", mCommand);
443 break;
444 }
445 fdprintf(fd, "FastMixer command=%s writeSequence=%u framesWritten=%u\n"
446 " numTracks=%u writeErrors=%u underruns=%u overruns=%u\n",
447 string, mWriteSequence, mFramesWritten,
448 mNumTracks, mWriteErrors, mUnderruns, mOverruns);
449#ifdef FAST_MIXER_STATISTICS
450 fdprintf(fd, " cycle time in ms: mean=%.1f min=%.1f max=%.1f stddev=%.1f\n",
451 mMean*1e3, mMinimum*1e3, mMaximum*1e3, mStddev*1e3);
452#endif
453}
454
455} // namespace android