summaryrefslogtreecommitdiff
path: root/libaudio
diff options
context:
space:
mode:
authorEric Laurent <elaurent@google.com>2017-05-26 16:27:48 -0700
committerEric Laurent <elaurent@google.com>2017-05-30 18:11:29 -0700
commit6f62adcc453da8665c5ab2275afbf984cb8287b5 (patch)
treebf3caf0cdcb08556d8ac43e58317376b06446a20 /libaudio
parent711ffce6d81613b11963103819806ce177087d97 (diff)
downloadfugu-6f62adcc453da8665c5ab2275afbf984cb8287b5.tar.gz
audio HAL: fix supported sampling rates and channel masks
Fix implementation of supported channel masks and sampling rate to take supplied format into account and report mono for non PCM formats. Bug: 34268671 Test: play stereo PCM and multichannel AC3 contents Change-Id: Ieaa2e92cb94ea3bd206f544a68a144ea21551a05
Diffstat (limited to 'libaudio')
-rw-r--r--libaudio/AudioStreamOut.cpp39
-rw-r--r--libaudio/alsa_utils.cpp161
-rw-r--r--libaudio/alsa_utils.h6
3 files changed, 133 insertions, 73 deletions
diff --git a/libaudio/AudioStreamOut.cpp b/libaudio/AudioStreamOut.cpp
index 53a13ef..f1bdb92 100644
--- a/libaudio/AudioStreamOut.cpp
+++ b/libaudio/AudioStreamOut.cpp
@@ -265,9 +265,10 @@ void AudioStreamOut::finishedWriteOp(size_t framesWritten,
}
static const String8 keyRouting(AudioParameter::keyRouting);
-static const String8 keySupSampleRates("sup_sampling_rates");
-static const String8 keySupFormats("sup_formats");
-static const String8 keySupChannels("sup_channels");
+static const String8 keyFormat(AudioParameter::keyFormat);
+static const String8 keySupSampleRates(AudioParameter::keyStreamSupportedSamplingRates);
+static const String8 keySupFormats(AudioParameter::keyStreamSupportedFormats);
+static const String8 keySupChannels(AudioParameter::keyStreamSupportedChannels);
status_t AudioStreamOut::setParameters(__unused struct audio_stream *stream, const char *kvpairs)
{
AudioParameter param = AudioParameter(String8(kvpairs));
@@ -291,36 +292,42 @@ status_t AudioStreamOut::setParameters(__unused struct audio_stream *stream, con
char* AudioStreamOut::getParameters(const char* k)
{
AudioParameter param = AudioParameter(String8(k));
- String8 value;
+ String8 stringValue;
+ int intValue;
- if (param.get(keyRouting, value) == NO_ERROR) {
+ if (param.get(keyRouting, stringValue) == NO_ERROR) {
param.addInt(keyRouting, (int)mAudioFlingerTgtDevices);
}
HDMIAudioCaps& hdmiCaps = mOwnerHAL.getHDMIAudioCaps();
- if (param.get(keySupSampleRates, value) == NO_ERROR) {
+ if (param.get(keySupFormats, stringValue) == NO_ERROR) {
if (mIsMCOutput) {
- hdmiCaps.getRatesForAF(value);
- param.add(keySupSampleRates, value);
+ hdmiCaps.getFmtsForAF(stringValue);
+ param.add(keySupFormats, stringValue);
} else {
- param.add(keySupSampleRates, String8("48000"));
+ param.add(keySupFormats, String8("AUDIO_FORMAT_PCM_16_BIT|AUDIO_FORMAT_PCM_8_24_BIT"));
}
}
- if (param.get(keySupFormats, value) == NO_ERROR) {
+ audio_format_t format = AUDIO_FORMAT_INVALID;
+ if (param.getInt(keyFormat, intValue) == NO_ERROR) {
+ format = (audio_format_t)intValue;
+ }
+
+ if (param.get(keySupSampleRates, stringValue) == NO_ERROR) {
if (mIsMCOutput) {
- hdmiCaps.getFmtsForAF(value);
- param.add(keySupFormats, value);
+ hdmiCaps.getRatesForAF(stringValue, format);
+ param.add(keySupSampleRates, stringValue);
} else {
- param.add(keySupFormats, String8("AUDIO_FORMAT_PCM_16_BIT|AUDIO_FORMAT_PCM_8_24_BIT"));
+ param.add(keySupSampleRates, String8("48000"));
}
}
- if (param.get(keySupChannels, value) == NO_ERROR) {
+ if (param.get(keySupChannels, stringValue) == NO_ERROR) {
if (mIsMCOutput) {
- hdmiCaps.getChannelMasksForAF(value);
- param.add(keySupChannels, value);
+ hdmiCaps.getChannelMasksForAF(stringValue, format);
+ param.add(keySupChannels, stringValue);
} else {
param.add(keySupChannels, String8("AUDIO_CHANNEL_OUT_STEREO"));
}
diff --git a/libaudio/alsa_utils.cpp b/libaudio/alsa_utils.cpp
index 2062cf6..0f50848 100644
--- a/libaudio/alsa_utils.cpp
+++ b/libaudio/alsa_utils.cpp
@@ -219,33 +219,6 @@ void HDMIAudioCaps::reset_l() {
mModes.clear();
}
-void HDMIAudioCaps::getRatesForAF(String8& rates) {
- Mutex::Autolock _l(mLock);
- rates.clear();
-
- // If the sink does not support basic audio, then it supports no audio.
- if (!mBasicAudioSupported)
- return;
-
- // Basic audio always supports from 32k through 38k.
- uint32_t tmp = kSR_32000 | kSR_44100 | kSR_48000;
-
- // To keep things simple, only report mode information for the PCM mode
- // which supports the maximum number of channels.
- ssize_t ndx = getMaxChModeNdx_l();
- if (ndx >= 0)
- tmp |= mModes[ndx].sr_bitmask;
-
- bool first = true;
- for (uint32_t i = 1; tmp; i <<= 1) {
- if (i & tmp) {
- rates.appendFormat(first ? "%d" : "|%d", srMaskToSR(i));
- first = false;
- tmp &= ~i;
- }
- }
-}
-
void HDMIAudioCaps::getFmtsForAF(String8& fmts) {
Mutex::Autolock _l(mLock);
fmts.clear();
@@ -316,29 +289,117 @@ void HDMIAudioCaps::getFmtsForAF(String8& fmts) {
#endif /* ALSA_UTILS_PRINT_FORMATS */
}
-void HDMIAudioCaps::getChannelMasksForAF(String8& masks) {
+/* static */
+HDMIAudioCaps::AudFormat HDMIAudioCaps::alsaFormatFromAndroidFormat(audio_format_t format)
+{
+ AudFormat alsaFormat = kFmtInvalid;
+ switch (audio_get_main_format(format)) {
+ case AUDIO_FORMAT_PCM: alsaFormat = kFmtLPCM; break;
+ case AUDIO_FORMAT_AC3: alsaFormat = kFmtAC3; break;
+ case AUDIO_FORMAT_E_AC3: alsaFormat = kFmtAC3; break; // FIXME should this be kFmtEAC3?
+ case AUDIO_FORMAT_DTS: alsaFormat = kFmtDTS; break;
+ case AUDIO_FORMAT_DTS_HD: alsaFormat = kFmtDTSHD; break;
+ case AUDIO_FORMAT_IEC61937: alsaFormat = kFmtLPCM; break;
+ default:
+ ALOGE("supportsFormat() says format %#x not supported", format);
+ break;
+ }
+ return alsaFormat;
+}
+
+const HDMIAudioCaps::Mode *HDMIAudioCaps::getModeForFormat(HDMIAudioCaps::AudFormat format)
+{
+ for (size_t i = 0; i < mModes.size(); ++i) {
+ if (mModes[i].fmt == format) {
+ return &mModes[i];
+ }
+ }
+ return nullptr;
+}
+
+void HDMIAudioCaps::getRatesForAF(String8& rates, audio_format_t format) {
Mutex::Autolock _l(mLock);
- masks.clear();
+ rates.clear();
// If the sink does not support basic audio, then it supports no audio.
if (!mBasicAudioSupported)
return;
- masks.append("AUDIO_CHANNEL_OUT_STEREO");
+ uint32_t tmp = 0;
+ // No format provided: returns rates for format with max channels
+ if (format == AUDIO_FORMAT_INVALID) {
+ ssize_t ndx = getMaxChModeNdx_l();
+ if (ndx >= 0)
+ tmp = mModes[ndx].sr_bitmask;
+ } else {
+ AudFormat alsaFormat = alsaFormatFromAndroidFormat(format);
+ if (alsaFormat == kFmtInvalid) {
+ return;
+ }
+ const Mode *mode = getModeForFormat(alsaFormat);
+ if (mode == nullptr) {
+ return;
+ }
+ tmp = mode->sr_bitmask;
+ }
+ bool first = true;
+ for (uint32_t i = 1; tmp; i <<= 1) {
+ if (i & tmp) {
+ rates.appendFormat(first ? "%d" : "|%d", srMaskToSR(i));
+ first = false;
+ tmp &= ~i;
+ }
+ }
+}
+
+void HDMIAudioCaps::getChannelMasksForAF(String8& masks, audio_format_t format) {
+ Mutex::Autolock _l(mLock);
+ masks.clear();
+ const Mode *mode = nullptr;
- // To keep things simple, only report mode information for the mode
- // which supports the maximum number of channels.
- ssize_t ndx = getMaxChModeNdx_l();
- if (ndx < 0)
+ // If the sink does not support basic audio, then it supports no audio.
+ if (!mBasicAudioSupported)
return;
- if (mModes[ndx].max_ch >= 6) {
- if (masks.length())
- masks.append("|");
+ if (format == AUDIO_FORMAT_INVALID) {
+ // To keep things simple, only report mode information for the mode
+ // which supports the maximum number of channels.
+ ssize_t ndx = getMaxChModeNdx_l();
+ if (ndx < 0)
+ return;
+ mode = &mModes[ndx];
+ } else {
+ AudFormat alsaFormat = alsaFormatFromAndroidFormat(format);
+ if (alsaFormat == kFmtInvalid) {
+ return;
+ }
+ mode = getModeForFormat(alsaFormat);
+ if (mode == nullptr) {
+ return;
+ }
+ }
- masks.append((mModes[ndx].max_ch >= 8)
- ? "AUDIO_CHANNEL_OUT_5POINT1|AUDIO_CHANNEL_OUT_7POINT1"
- : "AUDIO_CHANNEL_OUT_5POINT1");
+ if (mode != nullptr) {
+ // allow mono for non-pcm formats, e.g. AC3
+ if (mode->max_ch >= 1 && mode->fmt != kFmtLPCM) {
+ masks.append("AUDIO_CHANNEL_OUT_MONO");
+ }
+ if (mode->max_ch >= 2) {
+ if (masks.length()) masks.append("|");
+ masks.append("AUDIO_CHANNEL_OUT_STEREO");
+ }
+ if (mode->max_ch >= 4) {
+ if (masks.length()) masks.append("|");
+ masks.append("AUDIO_CHANNEL_OUT_QUAD");
+ }
+ if (mode->max_ch >= 6) {
+ if (masks.length()) masks.append("|");
+ masks.append("AUDIO_CHANNEL_OUT_5POINT1");
+ }
+ if (mode->max_ch >= 8) {
+ if (masks.length()) masks.append("|");
+ masks.append("AUDIO_CHANNEL_OUT_7POINT1");
+ }
}
}
@@ -368,21 +429,11 @@ bool HDMIAudioCaps::supportsFormat(audio_format_t format,
if (!mBasicAudioSupported)
return false;
- AudFormat alsaFormat;
- switch (audio_get_main_format(format)) {
- case AUDIO_FORMAT_PCM: alsaFormat = kFmtLPCM; break;
- case AUDIO_FORMAT_AC3: alsaFormat = kFmtAC3; break;
- case AUDIO_FORMAT_E_AC3: alsaFormat = kFmtAC3; break; // FIXME should this be kFmtEAC3?
- case AUDIO_FORMAT_DTS: alsaFormat = kFmtDTS; break;
- case AUDIO_FORMAT_DTS_HD: alsaFormat = kFmtDTSHD; break;
- case AUDIO_FORMAT_IEC61937:
- alsaFormat = kFmtLPCM;
- isIec958NonAudio = true;
- break;
- default:
- ALOGE("supportsFormat() says format %#x not supported", format);
- return false;
- }
+ AudFormat alsaFormat = alsaFormatFromAndroidFormat(format);
+ if (alsaFormat == kFmtInvalid)
+ return false;
+
+ isIec958NonAudio |= (format == AUDIO_FORMAT_IEC61937);
// EAC3 uses a PCM sample rate of 4X the base rate.
// We try to detect that situation and allow 4X rate even if the
diff --git a/libaudio/alsa_utils.h b/libaudio/alsa_utils.h
index f0f1b21..d61fa5a 100644
--- a/libaudio/alsa_utils.h
+++ b/libaudio/alsa_utils.h
@@ -103,9 +103,9 @@ class HDMIAudioCaps {
bool loadCaps(int ALSADeviceID);
void reset();
- void getRatesForAF(String8& rates);
+ void getRatesForAF(String8& rates, audio_format_t format);
void getFmtsForAF(String8& fmts);
- void getChannelMasksForAF(String8& masks);
+ void getChannelMasksForAF(String8& masks, audio_format_t format);
bool supportsFormat(audio_format_t format,
uint32_t sampleRate,
uint32_t channelCount,
@@ -130,6 +130,8 @@ class HDMIAudioCaps {
void reset_l();
ssize_t getMaxChModeNdx_l();
static bool sanityCheckMode(const Mode& m);
+ static AudFormat alsaFormatFromAndroidFormat(audio_format_t format);
+ const Mode *getModeForFormat(AudFormat format);
};
} // namespace android
#endif // __cplusplus