summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/media/AudioResamplerPublic.h19
-rw-r--r--media/libmedia/AudioRecord.cpp10
-rw-r--r--services/audioflinger/AudioFlinger.cpp56
-rw-r--r--services/audioflinger/Threads.cpp13
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 <stdint.h>
+
// 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 <media/AudioResamplerPublic.h>
+
#include <media/EffectsFactoryApi.h>
#include <audio_effects/effect_visualizer.h>
#include <audio_effects/effect_ns.h>
@@ -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<IAudioRecord> 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::RecordThread> 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 <typename T>
+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);