From 6770c6faa3467c92eabc5ec9b23d60eb556a0d03 Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Tue, 7 Apr 2015 13:43:36 -0700 Subject: Enable 8 bit and float pcm record formats for AudioFlinger Update sampling rate handling as well. Bug: 19570772 Change-Id: I872248e64c0578b2e48869a68fee0d51bd0640c3 --- include/media/AudioResamplerPublic.h | 19 ++++++++++++ media/libmedia/AudioRecord.cpp | 10 ++---- services/audioflinger/AudioFlinger.cpp | 56 +++++++++++++++++++++++++--------- services/audioflinger/Threads.cpp | 13 ++++++++ 4 files changed, 77 insertions(+), 21 deletions(-) diff --git a/include/media/AudioResamplerPublic.h b/include/media/AudioResamplerPublic.h index b705efa..0634741 100644 --- a/include/media/AudioResamplerPublic.h +++ b/include/media/AudioResamplerPublic.h @@ -17,6 +17,8 @@ #ifndef ANDROID_AUDIO_RESAMPLER_PUBLIC_H #define ANDROID_AUDIO_RESAMPLER_PUBLIC_H +#include + // AUDIO_RESAMPLER_DOWN_RATIO_MAX is the maximum ratio between the original // audio sample rate and the target rate when downsampling, // as permitted in the audio framework, e.g. AudioTrack and AudioFlinger. @@ -26,6 +28,12 @@ // TODO: replace with an API #define AUDIO_RESAMPLER_DOWN_RATIO_MAX 256 +// AUDIO_RESAMPLER_UP_RATIO_MAX is the maximum suggested ratio between the original +// audio sample rate and the target rate when upsampling. It is loosely enforced by +// the system. One issue with large upsampling ratios is the approximation by +// an int32_t of the phase increments, making the resulting sample rate inexact. +#define AUDIO_RESAMPLER_UP_RATIO_MAX 65536 + // Returns the source frames needed to resample to destination frames. This is not a precise // value and depends on the resampler (and possibly how it handles rounding internally). // Nevertheless, this should be an upper bound on the requirements of the resampler. @@ -39,4 +47,15 @@ static inline size_t sourceFramesNeeded( size_t((uint64_t)dstFramesRequired * srcSampleRate / dstSampleRate + 1 + 1); } +// An upper bound for the number of destination frames possible from srcFrames +// after sample rate conversion. This may be used for buffer sizing. +static inline size_t destinationFramesPossible(size_t srcFrames, uint32_t srcSampleRate, + uint32_t dstSampleRate) { + if (srcSampleRate == dstSampleRate) { + return srcFrames; + } + uint64_t dstFrames = (uint64_t)srcFrames * dstSampleRate / srcSampleRate; + return dstFrames > 2 ? dstFrames - 2 : 0; +} + #endif // ANDROID_AUDIO_RESAMPLER_PUBLIC_H diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 100a914..f4cdde2 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -189,13 +189,9 @@ status_t AudioRecord::set( } // validate parameters - if (!audio_is_valid_format(format)) { - ALOGE("Invalid format %#x", format); - return BAD_VALUE; - } - // Temporary restriction: AudioFlinger currently supports 16-bit PCM only - if (format != AUDIO_FORMAT_PCM_16_BIT) { - ALOGE("Format %#x is not supported", format); + // AudioFlinger capture only supports linear PCM + if (!audio_is_valid_format(format) || !audio_is_linear_pcm(format)) { + ALOGE("Format %#x is not linear pcm", format); return BAD_VALUE; } mFormat = format; diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index f3206cb..5002099 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -45,6 +45,8 @@ #include "AudioFlinger.h" #include "ServiceUtilities.h" +#include + #include #include #include @@ -1140,19 +1142,46 @@ size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, audio_format_t form if (ret != NO_ERROR) { return 0; } + if (!audio_is_valid_format(format) || !audio_is_linear_pcm(format)) { + return 0; + } AutoMutex lock(mHardwareLock); mHardwareStatus = AUDIO_HW_GET_INPUT_BUFFER_SIZE; - audio_config_t config; - memset(&config, 0, sizeof(config)); - config.sample_rate = sampleRate; - config.channel_mask = channelMask; - config.format = format; + audio_config_t config, proposed; + memset(&proposed, 0, sizeof(proposed)); + proposed.sample_rate = sampleRate; + proposed.channel_mask = channelMask; + proposed.format = format; audio_hw_device_t *dev = mPrimaryHardwareDev->hwDevice(); - size_t size = dev->get_input_buffer_size(dev, &config); + size_t frames; + for (;;) { + // Note: config is currently a const parameter for get_input_buffer_size() + // but we use a copy from proposed in case config changes from the call. + config = proposed; + frames = dev->get_input_buffer_size(dev, &config); + if (frames != 0) { + break; // hal success, config is the result + } + // change one parameter of the configuration each iteration to a more "common" value + // to see if the device will support it. + if (proposed.format != AUDIO_FORMAT_PCM_16_BIT) { + proposed.format = AUDIO_FORMAT_PCM_16_BIT; + } else if (proposed.sample_rate != 44100) { // 44.1 is claimed as must in CDD as well as + proposed.sample_rate = 44100; // legacy AudioRecord.java. TODO: Query hw? + } else { + ALOGW("getInputBufferSize failed with minimum buffer size sampleRate %u, " + "format %#x, channelMask 0x%X", + sampleRate, format, channelMask); + break; // retries failed, break out of loop with frames == 0. + } + } mHardwareStatus = AUDIO_HW_IDLE; - return size; + if (frames > 0 && config.sample_rate != sampleRate) { + frames = destinationFramesPossible(frames, sampleRate, config.sample_rate); + } + return frames; // may be converted to bytes at the Java level. } uint32_t AudioFlinger::getInputFramesLost(audio_io_handle_t ioHandle) const @@ -1419,9 +1448,8 @@ sp AudioFlinger::openRecord( goto Exit; } - // we don't yet support anything other than 16-bit PCM - if (!(audio_is_valid_format(format) && - audio_is_linear_pcm(format) && format == AUDIO_FORMAT_PCM_16_BIT)) { + // we don't yet support anything other than linear PCM + if (!audio_is_valid_format(format) || !audio_is_linear_pcm(format)) { ALOGE("openRecord() invalid format %#x", format); lStatus = BAD_VALUE; goto Exit; @@ -2002,11 +2030,11 @@ sp AudioFlinger::openInput_l(audio_module_handle_t m status, address.string()); // If the input could not be opened with the requested parameters and we can handle the - // conversion internally, try to open again with the proposed parameters. The AudioFlinger can - // resample the input and do mono to stereo or stereo to mono conversions on 16 bit PCM inputs. + // conversion internally, try to open again with the proposed parameters. if (status == BAD_VALUE && - config->format == halconfig.format && halconfig.format == AUDIO_FORMAT_PCM_16_BIT && - (halconfig.sample_rate <= 2 * config->sample_rate) && + audio_is_linear_pcm(config->format) && + audio_is_linear_pcm(halconfig.format) && + (halconfig.sample_rate <= AUDIO_RESAMPLER_DOWN_RATIO_MAX * config->sample_rate) && (audio_channel_count_from_in_mask(halconfig.channel_mask) <= FCC_2) && (audio_channel_count_from_in_mask(config->channel_mask) <= FCC_2)) { // FIXME describe the change proposed by HAL (save old values so we can log them here) diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index c096bdd..1a20fae 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -86,7 +86,13 @@ #define ALOGVV(a...) do { } while(0) #endif +// TODO: Move these macro/inlines to a header file. #define max(a, b) ((a) > (b) ? (a) : (b)) +template +static inline T min(const T& a, const T& b) +{ + return a < b ? a : b; +} namespace android { @@ -5622,6 +5628,13 @@ reacquire_wakelock: break; } + // Don't allow framesOut to be larger than what is possible with resampling + // from framesIn. + // This isn't strictly necessary but helps limit buffer resizing in + // RecordBufferConverter. TODO: remove when no longer needed. + framesOut = min(framesOut, + destinationFramesPossible( + framesIn, mSampleRate, activeTrack->mSampleRate)); // process frames from the RecordThread buffer provider to the RecordTrack buffer framesOut = activeTrack->mRecordBufferConverter->convert( activeTrack->mSink.raw, activeTrack->mResamplerBufferProvider, framesOut); -- cgit v1.1