summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorRicardo Garcia <rago@google.com>2015-04-22 18:47:32 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2015-04-22 18:47:33 +0000
commit983f2e02b342ef3ac4004471cbfd4cd8d5aecf7d (patch)
tree7c2ec64cc3034b84348e96cfe120a9c87efe92e3 /services
parentd54514d5e4b326e5dcaaf8b3f336ef31e447f355 (diff)
parent5a8a95de6dad1a3bcf3da5a37b35766e89086e13 (diff)
downloadframeworks_av-983f2e02b342ef3ac4004471cbfd4cd8d5aecf7d.zip
frameworks_av-983f2e02b342ef3ac4004471cbfd4cd8d5aecf7d.tar.gz
frameworks_av-983f2e02b342ef3ac4004471cbfd4cd8d5aecf7d.tar.bz2
Merge "Use AudioPlaybackRate to hold TimestretchBufferProvider parameters"
Diffstat (limited to 'services')
-rw-r--r--services/audioflinger/AudioMixer.cpp46
-rw-r--r--services/audioflinger/AudioMixer.h6
-rw-r--r--services/audioflinger/BufferProviders.cpp105
-rw-r--r--services/audioflinger/BufferProviders.h21
-rw-r--r--services/audioflinger/Threads.cpp12
-rw-r--r--services/audioflinger/Tracks.cpp8
6 files changed, 118 insertions, 80 deletions
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index c2c791f..18ce1d0 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -38,7 +38,6 @@
#include <audio_utils/format.h>
#include <common_time/local_clock.h>
#include <common_time/cc_helper.h>
-#include <media/AudioResamplerPublic.h>
#include "AudioMixerOps.h"
#include "AudioMixer.h"
@@ -223,8 +222,7 @@ int AudioMixer::getTrackName(audio_channel_mask_t channelMask,
t->mMixerChannelMask = audio_channel_mask_from_representation_and_bits(
AUDIO_CHANNEL_REPRESENTATION_POSITION, AUDIO_CHANNEL_OUT_STEREO);
t->mMixerChannelCount = audio_channel_count_from_out_mask(t->mMixerChannelMask);
- t->mSpeed = AUDIO_TIMESTRETCH_SPEED_NORMAL;
- t->mPitch = AUDIO_TIMESTRETCH_PITCH_NORMAL;
+ t->mPlaybackRate = AUDIO_PLAYBACK_RATE_DEFAULT;
// Check the downmixing (or upmixing) requirements.
status_t status = t->prepareForDownmix();
if (status != OK) {
@@ -668,19 +666,25 @@ void AudioMixer::setParameter(int name, int target, int param, void *value)
case TIMESTRETCH:
switch (param) {
case PLAYBACK_RATE: {
- const float speed = reinterpret_cast<float*>(value)[0];
- const float pitch = reinterpret_cast<float*>(value)[1];
- ALOG_ASSERT(AUDIO_TIMESTRETCH_SPEED_MIN <= speed
- && speed <= AUDIO_TIMESTRETCH_SPEED_MAX,
- "bad speed %f", speed);
- ALOG_ASSERT(AUDIO_TIMESTRETCH_PITCH_MIN <= pitch
- && pitch <= AUDIO_TIMESTRETCH_PITCH_MAX,
- "bad pitch %f", pitch);
- if (track.setPlaybackRate(speed, pitch)) {
- ALOGV("setParameter(TIMESTRETCH, PLAYBACK_RATE, %f %f", speed, pitch);
+ const AudioPlaybackRate *playbackRate =
+ reinterpret_cast<AudioPlaybackRate*>(value);
+ ALOG_ASSERT(AUDIO_TIMESTRETCH_SPEED_MIN <= playbackRate->mSpeed
+ && playbackRate->mSpeed <= AUDIO_TIMESTRETCH_SPEED_MAX,
+ "bad speed %f", playbackRate->mSpeed);
+ ALOG_ASSERT(AUDIO_TIMESTRETCH_PITCH_MIN <= playbackRate->mPitch
+ && playbackRate->mPitch <= AUDIO_TIMESTRETCH_PITCH_MAX,
+ "bad pitch %f", playbackRate->mPitch);
+ //TODO: use function from AudioResamplerPublic.h to test validity.
+ if (track.setPlaybackRate(*playbackRate)) {
+ ALOGV("setParameter(TIMESTRETCH, PLAYBACK_RATE, STRETCH_MODE, FALLBACK_MODE "
+ "%f %f %d %d",
+ playbackRate->mSpeed,
+ playbackRate->mPitch,
+ playbackRate->mStretchMode,
+ playbackRate->mFallbackMode);
// invalidateState(1 << name);
}
- } break;
+ } break;
default:
LOG_ALWAYS_FATAL("setParameter timestretch: bad param %d", param);
}
@@ -730,24 +734,26 @@ bool AudioMixer::track_t::setResampler(uint32_t trackSampleRate, uint32_t devSam
return false;
}
-bool AudioMixer::track_t::setPlaybackRate(float speed, float pitch)
+bool AudioMixer::track_t::setPlaybackRate(const AudioPlaybackRate &playbackRate)
{
- if (speed == mSpeed && pitch == mPitch) {
+ if ((mTimestretchBufferProvider == NULL &&
+ fabs(playbackRate.mSpeed - mPlaybackRate.mSpeed) < AUDIO_TIMESTRETCH_SPEED_MIN_DELTA &&
+ fabs(playbackRate.mPitch - mPlaybackRate.mPitch) < AUDIO_TIMESTRETCH_PITCH_MIN_DELTA) ||
+ isAudioPlaybackRateEqual(playbackRate, mPlaybackRate)) {
return false;
}
- mSpeed = speed;
- mPitch = pitch;
+ mPlaybackRate = playbackRate;
if (mTimestretchBufferProvider == NULL) {
// TODO: Remove MONO_HACK. Resampler sees #channels after the downmixer
// but if none exists, it is the channel count (1 for mono).
const int timestretchChannelCount = downmixerBufferProvider != NULL
? mMixerChannelCount : channelCount;
mTimestretchBufferProvider = new TimestretchBufferProvider(timestretchChannelCount,
- mMixerInFormat, sampleRate, speed, pitch);
+ mMixerInFormat, sampleRate, playbackRate);
reconfigureBufferProviders();
} else {
reinterpret_cast<TimestretchBufferProvider*>(mTimestretchBufferProvider)
- ->setPlaybackRate(speed, pitch);
+ ->setPlaybackRate(playbackRate);
}
return true;
}
diff --git a/services/audioflinger/AudioMixer.h b/services/audioflinger/AudioMixer.h
index e27a0d1..7165c6c 100644
--- a/services/audioflinger/AudioMixer.h
+++ b/services/audioflinger/AudioMixer.h
@@ -23,6 +23,7 @@
#include <hardware/audio_effect.h>
#include <media/AudioBufferProvider.h>
+#include <media/AudioResamplerPublic.h>
#include <media/nbaio/NBLog.h>
#include <system/audio.h>
#include <utils/Compat.h>
@@ -259,8 +260,7 @@ private:
audio_channel_mask_t mMixerChannelMask;
uint32_t mMixerChannelCount;
- float mSpeed;
- float mPitch;
+ AudioPlaybackRate mPlaybackRate;
bool needsRamp() { return (volumeInc[0] | volumeInc[1] | auxInc) != 0; }
bool setResampler(uint32_t trackSampleRate, uint32_t devSampleRate);
@@ -274,7 +274,7 @@ private:
void unprepareForDownmix();
status_t prepareForReformat();
void unprepareForReformat();
- bool setPlaybackRate(float speed, float pitch);
+ bool setPlaybackRate(const AudioPlaybackRate &playbackRate);
void reconfigureBufferProviders();
};
diff --git a/services/audioflinger/BufferProviders.cpp b/services/audioflinger/BufferProviders.cpp
index dcae5e7..77bf4ac 100644
--- a/services/audioflinger/BufferProviders.cpp
+++ b/services/audioflinger/BufferProviders.cpp
@@ -361,25 +361,25 @@ void ReformatBufferProvider::copyFrames(void *dst, const void *src, size_t frame
}
TimestretchBufferProvider::TimestretchBufferProvider(int32_t channelCount,
- audio_format_t format, uint32_t sampleRate, float speed, float pitch) :
+ audio_format_t format, uint32_t sampleRate, const AudioPlaybackRate &playbackRate) :
mChannelCount(channelCount),
mFormat(format),
mSampleRate(sampleRate),
mFrameSize(channelCount * audio_bytes_per_sample(format)),
- mSpeed(speed),
- mPitch(pitch),
mLocalBufferFrameCount(0),
mLocalBufferData(NULL),
mRemaining(0),
- mSonicStream(sonicCreateStream(sampleRate, mChannelCount))
+ mSonicStream(sonicCreateStream(sampleRate, mChannelCount)),
+ mFallbackFailErrorShown(false)
{
- ALOGV("TimestretchBufferProvider(%p)(%u, %#x, %u %f %f)",
- this, channelCount, format, sampleRate, speed, pitch);
- mBuffer.frameCount = 0;
-
LOG_ALWAYS_FATAL_IF(mSonicStream == NULL,
"TimestretchBufferProvider can't allocate Sonic stream");
- sonicSetSpeed(mSonicStream, speed);
+
+ setPlaybackRate(playbackRate);
+ ALOGV("TimestretchBufferProvider(%p)(%u, %#x, %u %f %f %d %d)",
+ this, channelCount, format, sampleRate, playbackRate.mSpeed,
+ playbackRate.mPitch, playbackRate.mStretchMode, playbackRate.mFallbackMode);
+ mBuffer.frameCount = 0;
}
TimestretchBufferProvider::~TimestretchBufferProvider()
@@ -423,8 +423,8 @@ status_t TimestretchBufferProvider::getNextBuffer(
// need to fetch more data
const size_t outputDesired = pBuffer->frameCount - mRemaining;
- mBuffer.frameCount = mSpeed == AUDIO_TIMESTRETCH_SPEED_NORMAL
- ? outputDesired : outputDesired * mSpeed + 1;
+ mBuffer.frameCount = mPlaybackRate.mSpeed == AUDIO_TIMESTRETCH_SPEED_NORMAL
+ ? outputDesired : outputDesired * mPlaybackRate.mSpeed + 1;
status_t res = mTrackBufferProvider->getNextBuffer(&mBuffer, pts);
@@ -491,13 +491,13 @@ void TimestretchBufferProvider::reset()
mRemaining = 0;
}
-status_t TimestretchBufferProvider::setPlaybackRate(float speed, float pitch)
+status_t TimestretchBufferProvider::setPlaybackRate(const AudioPlaybackRate &playbackRate)
{
- mSpeed = speed;
- mPitch = pitch;
-
- sonicSetSpeed(mSonicStream, speed);
+ mPlaybackRate = playbackRate;
+ mFallbackFailErrorShown = false;
+ sonicSetSpeed(mSonicStream, mPlaybackRate.mSpeed);
//TODO: pitch is ignored for now
+ //TODO: optimize: if parameters are the same, don't do any extra computation.
return OK;
}
@@ -508,33 +508,68 @@ void TimestretchBufferProvider::processFrames(void *dstBuffer, size_t *dstFrames
// Note dstFrames is the required number of frames.
// Ensure consumption from src is as expected.
- const size_t targetSrc = *dstFrames * mSpeed;
+ //TODO: add logic to track "very accurate" consumption related to speed, original sampling
+ //rate, actual frames processed.
+ const size_t targetSrc = *dstFrames * mPlaybackRate.mSpeed;
if (*srcFrames < targetSrc) { // limit dst frames to that possible
- *dstFrames = *srcFrames / mSpeed;
+ *dstFrames = *srcFrames / mPlaybackRate.mSpeed;
} else if (*srcFrames > targetSrc + 1) {
*srcFrames = targetSrc + 1;
}
- switch (mFormat) {
- case AUDIO_FORMAT_PCM_FLOAT:
- if (sonicWriteFloatToStream(mSonicStream, (float*)srcBuffer, *srcFrames) != 1) {
- ALOGE("sonicWriteFloatToStream cannot realloc");
- *srcFrames = 0; // cannot consume all of srcBuffer
+ if (mPlaybackRate.mSpeed< TIMESTRETCH_SONIC_SPEED_MIN ||
+ mPlaybackRate.mSpeed > TIMESTRETCH_SONIC_SPEED_MAX ) {
+ //fallback mode
+ if (*dstFrames > 0) {
+ switch(mPlaybackRate.mFallbackMode) {
+ case AUDIO_TIMESTRETCH_FALLBACK_CUT_REPEAT:
+ if (*dstFrames <= *srcFrames) {
+ size_t copySize = mFrameSize * *dstFrames;
+ memcpy(dstBuffer, srcBuffer, copySize);
+ } else {
+ // cyclically repeat the source.
+ for (size_t count = 0; count < *dstFrames; count += *srcFrames) {
+ size_t remaining = min(*srcFrames, *dstFrames - count);
+ memcpy((uint8_t*)dstBuffer + mFrameSize * count,
+ srcBuffer, mFrameSize * remaining);
+ }
+ }
+ break;
+ case AUDIO_TIMESTRETCH_FALLBACK_DEFAULT:
+ case AUDIO_TIMESTRETCH_FALLBACK_MUTE:
+ memset(dstBuffer,0, mFrameSize * *dstFrames);
+ break;
+ case AUDIO_TIMESTRETCH_FALLBACK_FAIL:
+ default:
+ if(!mFallbackFailErrorShown) {
+ ALOGE("invalid parameters in TimestretchBufferProvider fallbackMode:%d",
+ mPlaybackRate.mFallbackMode);
+ mFallbackFailErrorShown = true;
+ }
+ break;
+ }
}
- *dstFrames = sonicReadFloatFromStream(mSonicStream, (float*)dstBuffer, *dstFrames);
- break;
- case AUDIO_FORMAT_PCM_16_BIT:
- if (sonicWriteShortToStream(mSonicStream, (short*)srcBuffer, *srcFrames) != 1) {
- ALOGE("sonicWriteShortToStream cannot realloc");
- *srcFrames = 0; // cannot consume all of srcBuffer
+ } else {
+ switch (mFormat) {
+ case AUDIO_FORMAT_PCM_FLOAT:
+ if (sonicWriteFloatToStream(mSonicStream, (float*)srcBuffer, *srcFrames) != 1) {
+ ALOGE("sonicWriteFloatToStream cannot realloc");
+ *srcFrames = 0; // cannot consume all of srcBuffer
+ }
+ *dstFrames = sonicReadFloatFromStream(mSonicStream, (float*)dstBuffer, *dstFrames);
+ break;
+ case AUDIO_FORMAT_PCM_16_BIT:
+ if (sonicWriteShortToStream(mSonicStream, (short*)srcBuffer, *srcFrames) != 1) {
+ ALOGE("sonicWriteShortToStream cannot realloc");
+ *srcFrames = 0; // cannot consume all of srcBuffer
+ }
+ *dstFrames = sonicReadShortFromStream(mSonicStream, (short*)dstBuffer, *dstFrames);
+ break;
+ default:
+ // could also be caught on construction
+ LOG_ALWAYS_FATAL("invalid format %#x for TimestretchBufferProvider", mFormat);
}
- *dstFrames = sonicReadShortFromStream(mSonicStream, (short*)dstBuffer, *dstFrames);
- break;
- default:
- // could also be caught on construction
- LOG_ALWAYS_FATAL("invalid format %#x for TimestretchBufferProvider", mFormat);
}
}
-
// ----------------------------------------------------------------------------
} // namespace android
diff --git a/services/audioflinger/BufferProviders.h b/services/audioflinger/BufferProviders.h
index 42030c0..4970b6c 100644
--- a/services/audioflinger/BufferProviders.h
+++ b/services/audioflinger/BufferProviders.h
@@ -151,7 +151,8 @@ protected:
class TimestretchBufferProvider : public PassthruBufferProvider {
public:
TimestretchBufferProvider(int32_t channelCount,
- audio_format_t format, uint32_t sampleRate, float speed, float pitch);
+ audio_format_t format, uint32_t sampleRate,
+ const AudioPlaybackRate &playbackRate);
virtual ~TimestretchBufferProvider();
// Overrides AudioBufferProvider methods
@@ -161,7 +162,7 @@ public:
// Overrides PassthruBufferProvider
virtual void reset();
- virtual status_t setPlaybackRate(float speed, float pitch);
+ virtual status_t setPlaybackRate(const AudioPlaybackRate &playbackRate);
// processes frames
// dstBuffer is where to place the data
@@ -176,15 +177,17 @@ protected:
const audio_format_t mFormat;
const uint32_t mSampleRate; // const for now (TODO change this)
const size_t mFrameSize;
- float mSpeed;
- float mPitch;
+ AudioPlaybackRate mPlaybackRate;
private:
- AudioBufferProvider::Buffer mBuffer;
- size_t mLocalBufferFrameCount;
- void *mLocalBufferData;
- size_t mRemaining;
- sonicStream mSonicStream;
+ AudioBufferProvider::Buffer mBuffer; // for upstream request
+ size_t mLocalBufferFrameCount; // size of local buffer
+ void *mLocalBufferData; // internally allocated buffer for data returned
+ // to caller
+ size_t mRemaining; // remaining data in local buffer
+ sonicStream mSonicStream; // handle to sonic timestretch object
+ //FIXME: this dependency should be abstracted out
+ bool mFallbackFailErrorShown; // log fallback error only once
};
// ----------------------------------------------------------------------------
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index b30fd20..4eaeda3 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -3599,11 +3599,10 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac
// during last round
size_t desiredFrames;
const uint32_t sampleRate = track->mAudioTrackServerProxy->getSampleRate();
- float speed, pitch;
- track->mAudioTrackServerProxy->getPlaybackRate(&speed, &pitch);
+ AudioPlaybackRate playbackRate = track->mAudioTrackServerProxy->getPlaybackRate();
desiredFrames = sourceFramesNeededWithTimestretch(
- sampleRate, mNormalFrameCount, mSampleRate, speed);
+ sampleRate, mNormalFrameCount, mSampleRate, playbackRate.mSpeed);
// TODO: ONLY USED FOR LEGACY RESAMPLERS, remove when they are removed.
// add frames already consumed but not yet released by the resampler
// because mAudioTrackServerProxy->framesReady() will include these frames
@@ -3772,15 +3771,12 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac
AudioMixer::SAMPLE_RATE,
(void *)(uintptr_t)reqSampleRate);
- // set the playback rate as an float array {speed, pitch}
- float playbackRate[2];
- track->mAudioTrackServerProxy->getPlaybackRate(
- &playbackRate[0] /*speed*/, &playbackRate[1] /*pitch*/);
+ AudioPlaybackRate playbackRate = track->mAudioTrackServerProxy->getPlaybackRate();
mAudioMixer->setParameter(
name,
AudioMixer::TIMESTRETCH,
AudioMixer::PLAYBACK_RATE,
- playbackRate);
+ &playbackRate);
/*
* Select the appropriate output buffer for the track.
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index da2d634..c6e9745 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -906,11 +906,9 @@ status_t AudioFlinger::PlaybackThread::Track::getTimestamp(AudioTimestamp& times
// FIXME Not accurate under dynamic changes of sample rate and speed.
// Do not use track's mSampleRate as it is not current for mixer tracks.
uint32_t sampleRate = mAudioTrackServerProxy->getSampleRate();
- float speed, pitch;
- mAudioTrackServerProxy->getPlaybackRate(&speed, &pitch);
- uint32_t unpresentedFrames =
- ((double) playbackThread->mLatchQ.mUnpresentedFrames * sampleRate * speed)
- / playbackThread->mSampleRate;
+ AudioPlaybackRate playbackRate = mAudioTrackServerProxy->getPlaybackRate();
+ uint32_t unpresentedFrames = ((double) playbackThread->mLatchQ.mUnpresentedFrames *
+ sampleRate * playbackRate.mSpeed)/ playbackThread->mSampleRate;
// FIXME Since we're using a raw pointer as the key, it is theoretically possible
// for a brand new track to share the same address as a recently destroyed
// track, and thus for us to get the frames released of the wrong track.