blob: 841b06ac24e678f16c59bdeb6324451c38083a4f [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
Glenn Kasten21e8c502012-04-12 09:39:42 -0700133 // FIXME consider checking previous state and only perform if previous != COLD_IDLE
Glenn Kasten97b5d0d2012-03-23 18:54:19 -0700134 if (current->mColdGen != coldGen) {
135 int32_t *coldFutexAddr = current->mColdFutexAddr;
136 ALOG_ASSERT(coldFutexAddr != NULL);
137 int32_t old = android_atomic_dec(coldFutexAddr);
138 if (old <= 0) {
139 __futex_syscall4(coldFutexAddr, FUTEX_WAIT_PRIVATE, old - 1, NULL);
140 }
141 sleepNs = -1;
142 coldGen = current->mColdGen;
143 } else {
144 sleepNs = FAST_HOT_IDLE_NS;
145 }
146 continue;
147 case FastMixerState::EXIT:
148 delete mixer;
149 delete[] mixBuffer;
150 return false;
151 case FastMixerState::MIX:
152 case FastMixerState::WRITE:
153 case FastMixerState::MIX_WRITE:
154 break;
155 default:
156 LOG_FATAL("bad command %d", command);
157 }
158
159 // there is a non-idle state available to us; did the state change?
160 size_t frameCount = current->mFrameCount;
161 if (current != previous) {
162
163 // handle state change here, but since we want to diff the state,
164 // we're prepared for previous == &initial the first time through
165 unsigned previousTrackMask;
166
167 // check for change in output HAL configuration
168 NBAIO_Format previousFormat = format;
169 if (current->mOutputSinkGen != outputSinkGen) {
170 outputSink = current->mOutputSink;
171 outputSinkGen = current->mOutputSinkGen;
172 if (outputSink == NULL) {
173 format = Format_Invalid;
174 sampleRate = 0;
175 } else {
176 format = outputSink->format();
177 sampleRate = Format_sampleRate(format);
178 ALOG_ASSERT(Format_channelCount(format) == 2);
179 }
Glenn Kasten21e8c502012-04-12 09:39:42 -0700180 dumpState->mSampleRate = sampleRate;
Glenn Kasten97b5d0d2012-03-23 18:54:19 -0700181 }
182
183 if ((format != previousFormat) || (frameCount != previous->mFrameCount)) {
184 // FIXME to avoid priority inversion, don't delete here
185 delete mixer;
186 mixer = NULL;
187 delete[] mixBuffer;
188 mixBuffer = NULL;
189 if (frameCount > 0 && sampleRate > 0) {
190 // FIXME new may block for unbounded time at internal mutex of the heap
191 // implementation; it would be better to have normal mixer allocate for us
192 // to avoid blocking here and to prevent possible priority inversion
193 mixer = new AudioMixer(frameCount, sampleRate, FastMixerState::kMaxFastTracks);
194 mixBuffer = new short[frameCount * 2];
195 periodNs = (frameCount * 1000000000LL) / sampleRate; // 1.00
196 underrunNs = (frameCount * 1750000000LL) / sampleRate; // 1.75
197 overrunNs = (frameCount * 250000000LL) / sampleRate; // 0.25
198 } else {
199 periodNs = 0;
200 underrunNs = 0;
201 overrunNs = 0;
202 }
203 mixBufferState = UNDEFINED;
204#if !LOG_NDEBUG
205 for (i = 0; i < FastMixerState::kMaxFastTracks; ++i) {
206 fastTrackNames[i] = -1;
207 }
208#endif
209 // we need to reconfigure all active tracks
210 previousTrackMask = 0;
211 fastTracksGen = current->mFastTracksGen - 1;
Glenn Kasten21e8c502012-04-12 09:39:42 -0700212 dumpState->mFrameCount = frameCount;
Glenn Kasten97b5d0d2012-03-23 18:54:19 -0700213 } else {
214 previousTrackMask = previous->mTrackMask;
215 }
216
217 // check for change in active track set
218 unsigned currentTrackMask = current->mTrackMask;
219 if (current->mFastTracksGen != fastTracksGen) {
220 ALOG_ASSERT(mixBuffer != NULL);
221 int name;
222
223 // process removed tracks first to avoid running out of track names
224 unsigned removedTracks = previousTrackMask & ~currentTrackMask;
225 while (removedTracks != 0) {
226 i = __builtin_ctz(removedTracks);
227 removedTracks &= ~(1 << i);
228 const FastTrack* fastTrack = &current->mFastTracks[i];
229 if (mixer != NULL) {
230 name = fastTrackNames[i];
231 ALOG_ASSERT(name >= 0);
232 mixer->deleteTrackName(name);
233 }
234#if !LOG_NDEBUG
235 fastTrackNames[i] = -1;
236#endif
237 generations[i] = fastTrack->mGeneration;
238 }
239
240 // now process added tracks
241 unsigned addedTracks = currentTrackMask & ~previousTrackMask;
242 while (addedTracks != 0) {
243 i = __builtin_ctz(addedTracks);
244 addedTracks &= ~(1 << i);
245 const FastTrack* fastTrack = &current->mFastTracks[i];
246 AudioBufferProvider *bufferProvider = fastTrack->mBufferProvider;
247 ALOG_ASSERT(bufferProvider != NULL && fastTrackNames[i] == -1);
248 if (mixer != NULL) {
Jean-Michel Trivi9bd23222012-04-16 13:43:48 -0700249 // calling getTrackName with default channel mask
250 name = mixer->getTrackName(AUDIO_CHANNEL_OUT_STEREO);
Glenn Kasten97b5d0d2012-03-23 18:54:19 -0700251 ALOG_ASSERT(name >= 0);
252 fastTrackNames[i] = name;
253 mixer->setBufferProvider(name, bufferProvider);
254 mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER,
255 (void *) mixBuffer);
256 // newly allocated track names default to full scale volume
Glenn Kasten21e8c502012-04-12 09:39:42 -0700257 if (fastTrack->mSampleRate != 0 && fastTrack->mSampleRate != sampleRate) {
258 mixer->setParameter(name, AudioMixer::RESAMPLE,
259 AudioMixer::SAMPLE_RATE, (void*) fastTrack->mSampleRate);
260 }
261 mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK,
262 (void *) fastTrack->mChannelMask);
Glenn Kasten97b5d0d2012-03-23 18:54:19 -0700263 mixer->enable(name);
264 }
265 generations[i] = fastTrack->mGeneration;
266 }
267
268 // finally process modified tracks; these use the same slot
269 // but may have a different buffer provider or volume provider
270 unsigned modifiedTracks = currentTrackMask & previousTrackMask;
271 while (modifiedTracks != 0) {
272 i = __builtin_ctz(modifiedTracks);
273 modifiedTracks &= ~(1 << i);
274 const FastTrack* fastTrack = &current->mFastTracks[i];
275 if (fastTrack->mGeneration != generations[i]) {
276 AudioBufferProvider *bufferProvider = fastTrack->mBufferProvider;
277 ALOG_ASSERT(bufferProvider != NULL);
278 if (mixer != NULL) {
279 name = fastTrackNames[i];
280 ALOG_ASSERT(name >= 0);
281 mixer->setBufferProvider(name, bufferProvider);
282 if (fastTrack->mVolumeProvider == NULL) {
283 mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0,
284 (void *)0x1000);
285 mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1,
286 (void *)0x1000);
287 }
Glenn Kasten21e8c502012-04-12 09:39:42 -0700288 if (fastTrack->mSampleRate != 0 &&
289 fastTrack->mSampleRate != sampleRate) {
290 mixer->setParameter(name, AudioMixer::RESAMPLE,
291 AudioMixer::SAMPLE_RATE, (void*) fastTrack->mSampleRate);
292 } else {
293 mixer->setParameter(name, AudioMixer::RESAMPLE,
294 AudioMixer::REMOVE, NULL);
295 }
296 mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK,
297 (void *) fastTrack->mChannelMask);
Glenn Kasten97b5d0d2012-03-23 18:54:19 -0700298 // already enabled
299 }
300 generations[i] = fastTrack->mGeneration;
301 }
302 }
303
304 fastTracksGen = current->mFastTracksGen;
305
306 dumpState->mNumTracks = popcount(currentTrackMask);
307 }
308
309#if 1 // FIXME shouldn't need this
310 // only process state change once
311 previous = current;
312#endif
313 }
314
315 // do work using current state here
316 if ((command & FastMixerState::MIX) && (mixer != NULL)) {
317 ALOG_ASSERT(mixBuffer != NULL);
318 // update volumes
319 unsigned volumeTracks = current->mTrackMask;
320 while (volumeTracks != 0) {
321 i = __builtin_ctz(volumeTracks);
322 volumeTracks &= ~(1 << i);
323 const FastTrack* fastTrack = &current->mFastTracks[i];
324 int name = fastTrackNames[i];
325 ALOG_ASSERT(name >= 0);
326 if (fastTrack->mVolumeProvider != NULL) {
327 uint32_t vlr = fastTrack->mVolumeProvider->getVolumeLR();
328 mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0,
329 (void *)(vlr & 0xFFFF));
330 mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1,
331 (void *)(vlr >> 16));
332 }
333 }
334 // process() is CPU-bound
335 mixer->process(AudioBufferProvider::kInvalidPTS);
336 mixBufferState = MIXED;
337 } else if (mixBufferState == MIXED) {
338 mixBufferState = UNDEFINED;
339 }
340 if ((command & FastMixerState::WRITE) && (outputSink != NULL) && (mixBuffer != NULL)) {
341 if (mixBufferState == UNDEFINED) {
342 memset(mixBuffer, 0, frameCount * 2 * sizeof(short));
343 mixBufferState = ZEROED;
344 }
345 // FIXME write() is non-blocking and lock-free for a properly implemented NBAIO sink,
346 // but this code should be modified to handle both non-blocking and blocking sinks
347 dumpState->mWriteSequence++;
348 ssize_t framesWritten = outputSink->write(mixBuffer, frameCount);
349 dumpState->mWriteSequence++;
350 if (framesWritten >= 0) {
351 dumpState->mFramesWritten += framesWritten;
352 } else {
353 dumpState->mWriteErrors++;
354 }
355 // FIXME count # of writes blocked excessively, CPU usage, etc. for dump
356 }
357
358 // To be exactly periodic, compute the next sleep time based on current time.
359 // This code doesn't have long-term stability when the sink is non-blocking.
360 // FIXME To avoid drift, use the local audio clock or watch the sink's fill status.
361 struct timespec newTs;
362 int rc = clock_gettime(CLOCK_MONOTONIC, &newTs);
363 if (rc == 0) {
364 if (oldTsValid) {
365 time_t sec = newTs.tv_sec - oldTs.tv_sec;
366 long nsec = newTs.tv_nsec - oldTs.tv_nsec;
367 if (nsec < 0) {
368 --sec;
369 nsec += 1000000000;
370 }
371 if (sec > 0 || nsec > underrunNs) {
372 // FIXME only log occasionally
373 ALOGV("underrun: time since last cycle %d.%03ld sec",
374 (int) sec, nsec / 1000000L);
375 dumpState->mUnderruns++;
376 sleepNs = -1;
377 ignoreNextOverrun = true;
378 } else if (nsec < overrunNs) {
379 if (ignoreNextOverrun) {
380 ignoreNextOverrun = false;
381 } else {
382 // FIXME only log occasionally
383 ALOGV("overrun: time since last cycle %d.%03ld sec",
384 (int) sec, nsec / 1000000L);
385 dumpState->mOverruns++;
386 }
387 sleepNs = periodNs - overrunNs;
388 } else {
389 sleepNs = -1;
390 ignoreNextOverrun = false;
391 }
392#ifdef FAST_MIXER_STATISTICS
393 // long-term statistics
394 cts.sample(sec + nsec * 1e-9);
395 if (cts.n() >= kMaxSamples) {
396 dumpState->mMean = cts.mean();
397 dumpState->mMinimum = cts.minimum();
398 dumpState->mMaximum = cts.maximum();
399 dumpState->mStddev = cts.stddev();
400 cts.reset();
401 }
402#endif
403 } else {
404 // first time through the loop
405 oldTsValid = true;
406 sleepNs = periodNs;
407 ignoreNextOverrun = true;
408 }
409 oldTs = newTs;
410 } else {
411 // monotonic clock is broken
412 oldTsValid = false;
413 sleepNs = periodNs;
414 }
415
416 } // for (;;)
417
418 // never return 'true'; Thread::_threadLoop() locks mutex which can result in priority inversion
419}
420
421FastMixerDumpState::FastMixerDumpState() :
422 mCommand(FastMixerState::INITIAL), mWriteSequence(0), mFramesWritten(0),
Glenn Kasten21e8c502012-04-12 09:39:42 -0700423 mNumTracks(0), mWriteErrors(0), mUnderruns(0), mOverruns(0),
424 mSampleRate(0), mFrameCount(0)
Glenn Kasten97b5d0d2012-03-23 18:54:19 -0700425#ifdef FAST_MIXER_STATISTICS
426 , mMean(0.0), mMinimum(0.0), mMaximum(0.0), mStddev(0.0)
427#endif
428{
429}
430
431FastMixerDumpState::~FastMixerDumpState()
432{
433}
434
435void FastMixerDumpState::dump(int fd)
436{
437#define COMMAND_MAX 32
438 char string[COMMAND_MAX];
439 switch (mCommand) {
440 case FastMixerState::INITIAL:
441 strcpy(string, "INITIAL");
442 break;
443 case FastMixerState::HOT_IDLE:
444 strcpy(string, "HOT_IDLE");
445 break;
446 case FastMixerState::COLD_IDLE:
447 strcpy(string, "COLD_IDLE");
448 break;
449 case FastMixerState::EXIT:
450 strcpy(string, "EXIT");
451 break;
452 case FastMixerState::MIX:
453 strcpy(string, "MIX");
454 break;
455 case FastMixerState::WRITE:
456 strcpy(string, "WRITE");
457 break;
458 case FastMixerState::MIX_WRITE:
459 strcpy(string, "MIX_WRITE");
460 break;
461 default:
462 snprintf(string, COMMAND_MAX, "%d", mCommand);
463 break;
464 }
465 fdprintf(fd, "FastMixer command=%s writeSequence=%u framesWritten=%u\n"
Glenn Kasten21e8c502012-04-12 09:39:42 -0700466 " numTracks=%u writeErrors=%u underruns=%u overruns=%u\n"
467 " sampleRate=%u frameCount=%u\n",
Glenn Kasten97b5d0d2012-03-23 18:54:19 -0700468 string, mWriteSequence, mFramesWritten,
Glenn Kasten21e8c502012-04-12 09:39:42 -0700469 mNumTracks, mWriteErrors, mUnderruns, mOverruns,
470 mSampleRate, mFrameCount);
Glenn Kasten97b5d0d2012-03-23 18:54:19 -0700471#ifdef FAST_MIXER_STATISTICS
472 fdprintf(fd, " cycle time in ms: mean=%.1f min=%.1f max=%.1f stddev=%.1f\n",
473 mMean*1e3, mMinimum*1e3, mMaximum*1e3, mStddev*1e3);
474#endif
475}
476
477} // namespace android