1 /*
2 **
3 ** Copyright 2014, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 ** http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17
18 #define LOG_TAG "AudioHAL:AudioHardwareOutput"
19
20 #include <utils/Log.h>
21
22 #include <stdint.h>
23 #include <limits.h>
24 #include <math.h>
25
26 #include <common_time/local_clock.h>
27 #include <cutils/properties.h>
28
29 #include "AudioHardwareOutput.h"
30 #include "AudioStreamOut.h"
31 #include "HDMIAudioOutput.h"
32
33 namespace android {
34
35 // Global singleton.
36 AudioHardwareOutput gAudioHardwareOutput;
37
38 // HDMI options.
39 const String8 AudioHardwareOutput::kHDMIAllowedParamKey(
40 "atv.hdmi_audio.allowed");
41 const String8 AudioHardwareOutput::kHDMIDelayCompParamKey(
42 "atv.hdmi.audio_delay");
43 const String8 AudioHardwareOutput::kFixedHDMIOutputParamKey(
44 "atv.hdmi.fixed_volume");
45 const String8 AudioHardwareOutput::kFixedHDMIOutputLevelParamKey(
46 "atv.hdmi.fixed_level");
47
48 // Video delay comp hack options (not exposed to user level)
49 const String8 AudioHardwareOutput::kVideoDelayCompParamKey(
50 "atv.video.delay_comp");
51
52 // Defaults for settings.
setDefaults()53 void AudioHardwareOutput::OutputSettings::setDefaults()
54 {
55 allowed = true;
56 delayCompUsec = 0;
57 isFixed = false;
58 fixedLvl = 0.0f;
59 }
60
setDefaults()61 void AudioHardwareOutput::Settings::setDefaults() {
62 hdmi.setDefaults();
63
64 masterVolume = 0.60;
65 masterMute = false;
66
67 // Default this to 16mSec or so. Since audio start times are not sync'ed to
68 // to the VBI, there should be a +/-0.5 output frame rate error in the AV
69 // sync, even under the best of circumstances.
70 //
71 // In practice, the android core seems to have a hard time hitting its frame
72 // cadence consistently. Sometimes the frames are on time, and sometimes
73 // they are even a little early, but more often than not, the frames are
74 // late by about a full output frame time.
75 //
76 // ATV pretty much always uses a 60fps output rate, and the only thing
77 // consuming the latency estimate provided by the HAL is the path handling
78 // AV sync. For now, we can fudge this number to move things back in the
79 // direction of correct by providing a setting for video delay compensation
80 // which will be subtracted from the latency estimate and defaulting it to
81 // a reasonable middle gound (12mSec in this case).
82 videoDelayCompUsec = 12000;
83 }
84
AudioHardwareOutput()85 AudioHardwareOutput::AudioHardwareOutput()
86 : mMainOutput(NULL)
87 , mMCOutput(NULL)
88 , mHDMIConnected(false)
89 , mMaxDelayCompUsec(0)
90 {
91 mSettings.setDefaults();
92 mHDMICardID = find_alsa_card_by_name(kHDMI_ALSADeviceName);
93 }
94
~AudioHardwareOutput()95 AudioHardwareOutput::~AudioHardwareOutput()
96 {
97 closeOutputStream(mMainOutput);
98 closeOutputStream(mMCOutput);
99 }
100
initCheck()101 status_t AudioHardwareOutput::initCheck() {
102 return NO_ERROR;
103 }
104
openOutputStream(uint32_t devices,audio_format_t * format,uint32_t * channels,uint32_t * sampleRate,audio_output_flags_t flags,status_t * status)105 AudioStreamOut* AudioHardwareOutput::openOutputStream(
106 uint32_t devices,
107 audio_format_t *format,
108 uint32_t *channels,
109 uint32_t *sampleRate,
110 audio_output_flags_t flags,
111 status_t *status) {
112 (void) devices;
113 AutoMutex lock(mStreamLock);
114
115 AudioStreamOut** pp_out;
116 AudioStreamOut* out;
117
118 if (!(flags & AUDIO_OUTPUT_FLAG_DIRECT)) {
119 pp_out = &mMainOutput;
120 out = new AudioStreamOut(*this, false);
121 } else {
122 pp_out = &mMCOutput;
123 out = new AudioStreamOut(*this, true);
124 }
125
126 if (out == NULL) {
127 *status = NO_MEMORY;
128 return NULL;
129 }
130
131 *status = out->set(format, channels, sampleRate);
132
133 if (*status == NO_ERROR) {
134 *pp_out = out;
135 updateTgtDevices_l();
136 } else {
137 delete out;
138 }
139
140 return *pp_out;
141 }
142
closeOutputStream(AudioStreamOut * out)143 void AudioHardwareOutput::closeOutputStream(AudioStreamOut* out) {
144 if (out == NULL)
145 return;
146
147 // Putting the stream into "standby" should cause it to release all of its
148 // physical outputs.
149 out->standby();
150
151 {
152 Mutex::Autolock _l(mStreamLock);
153 if (mMainOutput && out == mMainOutput) {
154 delete mMainOutput;
155 mMainOutput = NULL;
156 } else if (mMCOutput && out == mMCOutput) {
157 delete mMCOutput;
158 mMCOutput = NULL;
159 }
160
161 updateTgtDevices_l();
162 }
163 }
164
setMasterVolume(float volume)165 status_t AudioHardwareOutput::setMasterVolume(float volume)
166 {
167 Mutex::Autolock _l1(mOutputLock);
168 Mutex::Autolock _l2(mSettingsLock);
169
170 mSettings.masterVolume = volume;
171
172 AudioOutputList::iterator I;
173 for (I = mPhysOutputs.begin(); I != mPhysOutputs.end(); ++I)
174 (*I)->setVolume(mSettings.masterVolume);
175
176 return NO_ERROR;
177 }
178
getMasterVolume(float * volume)179 status_t AudioHardwareOutput::getMasterVolume(float* volume) {
180
181 if (NULL == volume)
182 return BAD_VALUE;
183
184 // Explicit scope for auto-lock pattern.
185 {
186 Mutex::Autolock _l(mSettingsLock);
187 *volume = mSettings.masterVolume;
188 }
189
190 return NO_ERROR;
191 }
192
setMasterMute(bool muted)193 status_t AudioHardwareOutput::setMasterMute(bool muted)
194 {
195 Mutex::Autolock _l1(mOutputLock);
196 Mutex::Autolock _l2(mSettingsLock);
197
198 mSettings.masterMute = muted;
199
200 AudioOutputList::iterator I;
201 for (I = mPhysOutputs.begin(); I != mPhysOutputs.end(); ++I)
202 (*I)->setMute(mSettings.masterMute);
203
204 return NO_ERROR;
205 }
206
getMasterMute(bool * muted)207 status_t AudioHardwareOutput::getMasterMute(bool* muted) {
208 if (NULL == muted)
209 return BAD_VALUE;
210
211 // Explicit scope for auto-lock pattern.
212 {
213 Mutex::Autolock _l(mSettingsLock);
214 *muted = mSettings.masterMute;
215 }
216
217 return NO_ERROR;
218 }
219
setParameters(const char * kvpairs)220 status_t AudioHardwareOutput::setParameters(const char* kvpairs) {
221 AudioParameter param = AudioParameter(String8(kvpairs));
222 status_t status = NO_ERROR;
223 float floatVal;
224 int intVal;
225 Settings initial, s;
226
227 {
228 // Record the initial state of the settings from inside the lock. Then
229 // leave the lock in order to parse the changes to be made.
230 Mutex::Autolock _l(mSettingsLock);
231 initial = s = mSettings;
232 }
233
234 /***************************************************************
235 * HDMI Audio Options *
236 ***************************************************************/
237 if (param.getInt(kHDMIAllowedParamKey, intVal) == NO_ERROR) {
238 s.hdmi.allowed = (intVal != 0);
239 param.remove(kHDMIAllowedParamKey);
240 }
241
242 if ((param.getFloat(kHDMIDelayCompParamKey, floatVal) == NO_ERROR) &&
243 (floatVal >= 0.0) &&
244 (floatVal <= AudioOutput::kMaxDelayCompensationMSec)) {
245 uint32_t delay_comp = static_cast<uint32_t>(floatVal * 1000.0);
246 s.hdmi.delayCompUsec = delay_comp;
247 param.remove(kHDMIDelayCompParamKey);
248 }
249
250 if (param.getInt(kFixedHDMIOutputParamKey, intVal) == NO_ERROR) {
251 s.hdmi.isFixed = (intVal != 0);
252 param.remove(kFixedHDMIOutputParamKey);
253 }
254
255 if ((param.getFloat(kFixedHDMIOutputLevelParamKey, floatVal) == NO_ERROR)
256 && (floatVal <= 0.0)) {
257 s.hdmi.fixedLvl = floatVal;
258 param.remove(kFixedHDMIOutputLevelParamKey);
259 }
260
261 /***************************************************************
262 * Other Options *
263 ***************************************************************/
264 if ((param.getFloat(kVideoDelayCompParamKey, floatVal) == NO_ERROR) &&
265 (floatVal >= 0.0) &&
266 (floatVal <= AudioOutput::kMaxDelayCompensationMSec)) {
267 s.videoDelayCompUsec = static_cast<uint32_t>(floatVal * 1000.0);
268 param.remove(kVideoDelayCompParamKey);
269 }
270
271 if (param.size())
272 status = BAD_VALUE;
273
274 // If there was a change made to settings, go ahead and apply it now.
275 bool allowedOutputsChanged = false;
276 if (memcmp(&initial, &s, sizeof(initial))) {
277 Mutex::Autolock _l1(mOutputLock);
278 Mutex::Autolock _l2(mSettingsLock);
279
280 if (memcmp(&initial.hdmi, &s.hdmi, sizeof(initial.hdmi)))
281 allowedOutputsChanged = allowedOutputsChanged ||
282 applyOutputSettings_l(initial.hdmi, s.hdmi, mSettings.hdmi,
283 HDMIAudioOutput::classDevMask());
284
285 if (initial.videoDelayCompUsec != s.videoDelayCompUsec)
286 mSettings.videoDelayCompUsec = s.videoDelayCompUsec;
287
288 uint32_t tmp = 0;
289 if (mSettings.hdmi.allowed && (tmp < mSettings.hdmi.delayCompUsec))
290 tmp = mSettings.hdmi.delayCompUsec;
291 if (mMaxDelayCompUsec != tmp)
292 mMaxDelayCompUsec = tmp;
293 }
294
295 if (allowedOutputsChanged) {
296 Mutex::Autolock _l(mStreamLock);
297 updateTgtDevices_l();
298 }
299
300 return status;
301 }
302
applyOutputSettings_l(const AudioHardwareOutput::OutputSettings & initial,const AudioHardwareOutput::OutputSettings & current,AudioHardwareOutput::OutputSettings & updateMe,uint32_t outDevMask)303 bool AudioHardwareOutput::applyOutputSettings_l(
304 const AudioHardwareOutput::OutputSettings& initial,
305 const AudioHardwareOutput::OutputSettings& current,
306 AudioHardwareOutput::OutputSettings& updateMe,
307 uint32_t outDevMask) {
308 // ASSERT(holding mOutputLock and mSettingsLock)
309 sp<AudioOutput> out;
310
311 // Check for a change in the allowed/not-allowed state. Update if needed
312 // and return true if there was a change made.
313 bool ret = false;
314 if (initial.allowed != current.allowed) {
315 updateMe.allowed = current.allowed;
316 ret = true;
317 }
318
319 // Look for an instance of the output to be updated in case other changes
320 // were made.
321 AudioOutputList::iterator I;
322 for (I = mPhysOutputs.begin(); I != mPhysOutputs.end(); ++I) {
323 if (outDevMask == (*I)->devMask()) {
324 out = (*I);
325 break;
326 }
327 }
328
329 // Update the other settings, if needed.
330 if (initial.delayCompUsec != current.delayCompUsec) {
331 updateMe.delayCompUsec = current.delayCompUsec;
332 if (out != NULL)
333 out->setExternalDelay_uSec(current.delayCompUsec);
334 }
335
336 if (initial.isFixed != current.isFixed) {
337 updateMe.isFixed = current.isFixed;
338 if (out != NULL)
339 out->setOutputIsFixed(current.isFixed);
340 }
341
342 if (initial.fixedLvl != current.fixedLvl) {
343 updateMe.fixedLvl = current.fixedLvl;
344 if (out != NULL)
345 out->setFixedOutputLevel(current.fixedLvl);
346 }
347
348 return ret;
349 }
350
351
getParameters(const char * keys)352 char* AudioHardwareOutput::getParameters(const char* keys) {
353 Settings s;
354
355 // Explicit scope for auto-lock pattern.
356 {
357 // Snapshot the current settings so we don't have to hold the settings
358 // lock while formatting the results.
359 Mutex::Autolock _l(mSettingsLock);
360 s = mSettings;
361 }
362
363 AudioParameter param = AudioParameter(String8(keys));
364 String8 tmp;
365
366 /***************************************************************
367 * HDMI Audio Options *
368 ***************************************************************/
369 if (param.get(kHDMIAllowedParamKey, tmp) == NO_ERROR)
370 param.addInt(kHDMIAllowedParamKey, s.hdmi.allowed ? 1 : 0);
371
372 if (param.get(kHDMIDelayCompParamKey, tmp) == NO_ERROR)
373 param.addFloat(kHDMIDelayCompParamKey,
374 static_cast<float>(s.hdmi.delayCompUsec) / 1000.0);
375
376 if (param.get(kFixedHDMIOutputParamKey, tmp) == NO_ERROR)
377 param.addInt(kFixedHDMIOutputParamKey, s.hdmi.isFixed ? 1 : 0);
378
379 if (param.get(kFixedHDMIOutputLevelParamKey, tmp) == NO_ERROR)
380 param.addFloat(kFixedHDMIOutputLevelParamKey, s.hdmi.fixedLvl);
381
382 /***************************************************************
383 * Other Options *
384 ***************************************************************/
385 if (param.get(kVideoDelayCompParamKey, tmp) == NO_ERROR)
386 param.addFloat(kVideoDelayCompParamKey,
387 static_cast<float>(s.videoDelayCompUsec) / 1000.0);
388
389 return strdup(param.toString().string());
390 }
391
updateRouting(uint32_t devMask)392 void AudioHardwareOutput::updateRouting(uint32_t devMask) {
393 Mutex::Autolock _l(mStreamLock);
394
395 bool hasHDMI = 0 != (devMask & HDMIAudioOutput::classDevMask());
396 ALOGI("%s: hasHDMI = %d, mHDMIConnected = %d", __func__, hasHDMI, mHDMIConnected);
397 if (mHDMIConnected != hasHDMI) {
398 mHDMIConnected = hasHDMI;
399
400 if (mHDMIConnected)
401 mHDMIAudioCaps.loadCaps(mHDMICardID);
402 else
403 mHDMIAudioCaps.reset();
404
405 updateTgtDevices_l();
406 }
407 }
408
obtainOutput(const AudioStreamOut & tgtStream,uint32_t devMask,sp<AudioOutput> * newOutput)409 status_t AudioHardwareOutput::obtainOutput(const AudioStreamOut& tgtStream,
410 uint32_t devMask,
411 sp<AudioOutput>* newOutput) {
412 Mutex::Autolock _l1(mOutputLock);
413
414 // Sanity check the device mask passed to us. There should exactly one bit
415 // set, no less, no more.
416 if (popcount(devMask) != 1) {
417 ALOGW("bad device mask in obtainOutput, %08x", devMask);
418 return INVALID_OPERATION;
419 }
420
421 // Start by checking to see if the requested output is currently busy.
422 AudioOutputList::iterator I;
423 for (I = mPhysOutputs.begin(); I != mPhysOutputs.end(); ++I)
424 if (devMask & (*I)->devMask())
425 return OK; // Yup; its busy.
426
427 // Looks like we don't currently have an output of the requested type.
428 // Figure out which type is being requested and try to construct one.
429 OutputSettings* S = NULL;
430 if (devMask & HDMIAudioOutput::classDevMask()) {
431 *newOutput = new HDMIAudioOutput();
432 S = &mSettings.hdmi;
433 }
434 else {
435 ALOGW("%s stream out requested output of unknown type %08x",
436 tgtStream.getName(), devMask);
437 return BAD_VALUE;
438 }
439
440 if (*newOutput == NULL)
441 return NO_MEMORY;
442
443 status_t res = (*newOutput)->setupForStream(tgtStream);
444 if (res != OK) {
445 ALOGE("%s setupForStream() returned %d",
446 tgtStream.getName(), res);
447 *newOutput = NULL;
448 } else {
449 ALOGI("%s stream out adding %s output.",
450 tgtStream.getName(), (*newOutput)->getOutputName());
451 mPhysOutputs.push_back(*newOutput);
452
453 { // Apply current settings
454 Mutex::Autolock _l2(mSettingsLock);
455 (*newOutput)->setVolume(mSettings.masterVolume);
456 (*newOutput)->setMute(mSettings.masterMute);
457 (*newOutput)->setExternalDelay_uSec(S->delayCompUsec);
458 (*newOutput)->setOutputIsFixed(S->isFixed);
459 (*newOutput)->setFixedOutputLevel(S->fixedLvl);
460 }
461 }
462
463 return res;
464 }
465
releaseOutput(const AudioStreamOut & tgtStream,const sp<AudioOutput> & releaseMe)466 void AudioHardwareOutput::releaseOutput(const AudioStreamOut& tgtStream,
467 const sp<AudioOutput>& releaseMe) {
468 Mutex::Autolock _l(mOutputLock);
469
470 ALOGI("%s stream out removing %s output.",
471 tgtStream.getName(), releaseMe->getOutputName());
472
473 // Immediately release any resources associated with this output (In
474 // particular, make sure to close any ALSA device driver handles ASAP)
475 releaseMe->cleanupResources();
476
477 // Now, clear our internal bookkeeping.
478 AudioOutputList::iterator I;
479 for (I = mPhysOutputs.begin(); I != mPhysOutputs.end(); ++I) {
480 if (releaseMe.get() == (*I).get()) {
481 mPhysOutputs.erase(I);
482 break;
483 }
484 }
485 }
486
updateTgtDevices_l()487 void AudioHardwareOutput::updateTgtDevices_l() {
488 // ASSERT(holding mStreamLock)
489 uint32_t mcMask = 0;
490 uint32_t mainMask = 0;
491
492 {
493 Mutex::Autolock _l(mSettingsLock);
494 if (mSettings.hdmi.allowed && mHDMIConnected) {
495 if (NULL != mMCOutput)
496 mcMask |= HDMIAudioOutput::classDevMask();
497 else
498 mainMask |= HDMIAudioOutput::classDevMask();
499 }
500 }
501
502 if (NULL != mMainOutput)
503 mMainOutput->setTgtDevices(mainMask);
504
505 if (NULL != mMCOutput)
506 mMCOutput->setTgtDevices(mcMask);
507 }
508
standbyStatusUpdate(bool isInStandby,bool isMCStream)509 void AudioHardwareOutput::standbyStatusUpdate(bool isInStandby, bool isMCStream) {
510
511 Mutex::Autolock _l1(mStreamLock);
512 bool hdmiAllowed;
513 {
514 Mutex::Autolock _l2(mSettingsLock);
515 hdmiAllowed = mSettings.hdmi.allowed;
516 }
517 // If there is no HDMI, do nothing
518 if (hdmiAllowed && mHDMIConnected) {
519 // If a multi-channel stream goes to standy state, we must switch
520 // to stereo stream. If MC comes out of standby, we must switch
521 // back to MC. No special processing needed for main stream.
522 // AudioStreamOut class handles that correctly
523 if (isMCStream) {
524 uint32_t mcMask;
525 uint32_t mainMask;
526 if (isInStandby) {
527 mainMask = HDMIAudioOutput::classDevMask();
528 mcMask = 0;
529 } else {
530 mainMask = 0;
531 mcMask = HDMIAudioOutput::classDevMask();
532 }
533
534 if (NULL != mMainOutput)
535 mMainOutput->setTgtDevices(mainMask);
536
537 if (NULL != mMCOutput)
538 mMCOutput->setTgtDevices(mcMask);
539 }
540 }
541 }
542
543 #define DUMP(a...) \
544 snprintf(buffer, SIZE, a); \
545 buffer[SIZE - 1] = 0; \
546 result.append(buffer);
547 #define B2STR(b) b ? "true" : "false"
548
dump(int fd)549 status_t AudioHardwareOutput::dump(int fd)
550 {
551 const size_t SIZE = 256;
552 char buffer[SIZE];
553 String8 result;
554 Settings s;
555
556 // Explicit scope for auto-lock pattern.
557 {
558 // Snapshot the current settings so we don't have to hold the settings
559 // lock while formatting the results.
560 Mutex::Autolock _l(mSettingsLock);
561 s = mSettings;
562 }
563
564 DUMP("AudioHardwareOutput::dump\n");
565 DUMP("\tMaster Volume : %0.3f\n", s.masterVolume);
566 DUMP("\tMaster Mute : %s\n", B2STR(s.masterMute));
567 DUMP("\tHDMI Output Allowed : %s\n", B2STR(s.hdmi.allowed));
568 DUMP("\tHDMI Delay Comp : %u uSec\n", s.hdmi.delayCompUsec);
569 DUMP("\tHDMI Output Fixed : %s\n", B2STR(s.hdmi.isFixed));
570 DUMP("\tHDMI Fixed Level : %.1f dB\n", s.hdmi.fixedLvl);
571 DUMP("\tVideo Delay Comp : %u uSec\n", s.videoDelayCompUsec);
572
573 ::write(fd, result.string(), result.size());
574
575 // Explicit scope for auto-lock pattern.
576 {
577 Mutex::Autolock _l(mOutputLock);
578 if (mMainOutput)
579 mMainOutput->dump(fd);
580
581 if (mMCOutput)
582 mMCOutput->dump(fd);
583 }
584
585 return NO_ERROR;
586 }
587
588 #undef B2STR
589 #undef DUMP
590
591 }; // namespace android
592