summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--camera/VendorTagDescriptor.cpp8
-rw-r--r--include/ndk/NdkMediaCodec.h11
-rw-r--r--media/libmedia/AudioRecord.cpp42
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayer.cpp13
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp4
-rw-r--r--media/libnbaio/NBLog.cpp2
-rw-r--r--media/libstagefright/MediaBuffer.cpp5
-rw-r--r--media/ndk/NdkMediaCodec.cpp4
-rw-r--r--services/audioflinger/AudioFlinger.cpp8
-rw-r--r--services/audioflinger/AudioMixer.cpp202
-rw-r--r--services/audioflinger/AudioMixer.h58
-rw-r--r--services/audioflinger/AudioResamplerDyn.cpp22
-rw-r--r--services/audioflinger/AudioWatchdog.cpp2
-rw-r--r--services/audioflinger/FastMixer.cpp108
-rw-r--r--services/audioflinger/FastMixer.h4
-rw-r--r--services/audioflinger/FastMixerState.cpp2
-rw-r--r--services/audioflinger/FastMixerState.h1
-rw-r--r--services/audioflinger/StateQueue.cpp4
-rw-r--r--services/audioflinger/Threads.cpp119
-rw-r--r--services/audioflinger/Threads.h11
-rw-r--r--services/audioflinger/TrackBase.h9
-rw-r--r--services/audioflinger/Tracks.cpp24
-rw-r--r--services/audiopolicy/AudioPolicyManager.cpp7
-rw-r--r--services/camera/libcameraservice/utils/CameraTraces.cpp4
-rw-r--r--services/medialog/MediaLogService.cpp4
25 files changed, 476 insertions, 202 deletions
diff --git a/camera/VendorTagDescriptor.cpp b/camera/VendorTagDescriptor.cpp
index 59dce91..3f72f34 100644
--- a/camera/VendorTagDescriptor.cpp
+++ b/camera/VendorTagDescriptor.cpp
@@ -349,18 +349,18 @@ void VendorTagDescriptor::dump(int fd, int verbosity, int indentation) const {
size_t size = mTagToNameMap.size();
if (size == 0) {
- fdprintf(fd, "%*sDumping configured vendor tag descriptors: None set\n",
+ dprintf(fd, "%*sDumping configured vendor tag descriptors: None set\n",
indentation, "");
return;
}
- fdprintf(fd, "%*sDumping configured vendor tag descriptors: %zu entries\n",
+ dprintf(fd, "%*sDumping configured vendor tag descriptors: %zu entries\n",
indentation, "", size);
for (size_t i = 0; i < size; ++i) {
uint32_t tag = mTagToNameMap.keyAt(i);
if (verbosity < 1) {
- fdprintf(fd, "%*s0x%x\n", indentation + 2, "", tag);
+ dprintf(fd, "%*s0x%x\n", indentation + 2, "", tag);
continue;
}
String8 name = mTagToNameMap.valueAt(i);
@@ -369,7 +369,7 @@ void VendorTagDescriptor::dump(int fd, int verbosity, int indentation) const {
int type = mTagToTypeMap.valueFor(tag);
const char* typeName = (type >= 0 && type < NUM_TYPES) ?
camera_metadata_type_names[type] : "UNKNOWN";
- fdprintf(fd, "%*s0x%x (%s) with type %d (%s) defined in section %s\n", indentation + 2,
+ dprintf(fd, "%*s0x%x (%s) with type %d (%s) defined in section %s\n", indentation + 2,
"", tag, name.string(), type, typeName, sectionName.string());
}
diff --git a/include/ndk/NdkMediaCodec.h b/include/ndk/NdkMediaCodec.h
index 2f000d7..c07f4c9 100644
--- a/include/ndk/NdkMediaCodec.h
+++ b/include/ndk/NdkMediaCodec.h
@@ -163,17 +163,6 @@ media_status_t AMediaCodec_releaseOutputBuffer(AMediaCodec*, size_t idx, bool re
media_status_t AMediaCodec_releaseOutputBufferAtTime(
AMediaCodec *mData, size_t idx, int64_t timestampNs);
-typedef void (*OnCodecEvent)(AMediaCodec *codec, void *userdata);
-
-/**
- * Set a callback to be called when a new buffer is available, or there was a format
- * or buffer change.
- * Note that you cannot perform any operations on the mediacodec from within the callback.
- * If you need to perform mediacodec operations, you must do so on a different thread.
- */
-media_status_t AMediaCodec_setNotificationCallback(
- AMediaCodec*, OnCodecEvent callback, void *userdata);
-
typedef enum {
AMEDIACODECRYPTOINFO_MODE_CLEAR = 0,
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 1c808d0..db61e85 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -203,23 +203,6 @@ status_t AudioRecord::set(
mFrameSize = sizeof(uint8_t);
}
- // validate framecount
- size_t minFrameCount;
- status_t status = AudioRecord::getMinFrameCount(&minFrameCount,
- sampleRate, format, channelMask);
- if (status != NO_ERROR) {
- ALOGE("getMinFrameCount() failed for sampleRate %u, format %#x, channelMask %#x; status %d",
- sampleRate, format, channelMask, status);
- return status;
- }
- ALOGV("AudioRecord::set() minFrameCount = %d", minFrameCount);
-
- if (frameCount == 0) {
- frameCount = minFrameCount;
- } else if (frameCount < minFrameCount) {
- ALOGE("frameCount %u < minFrameCount %u", frameCount, minFrameCount);
- return BAD_VALUE;
- }
// mFrameCount is initialized in openRecord_l
mReqFrameCount = frameCount;
@@ -242,7 +225,7 @@ status_t AudioRecord::set(
}
// create the IAudioRecord
- status = openRecord_l(0 /*epoch*/);
+ status_t status = openRecord_l(0 /*epoch*/);
if (status != NO_ERROR) {
if (mAudioRecordThread != 0) {
@@ -464,6 +447,29 @@ status_t AudioRecord::openRecord_l(size_t epoch)
size_t frameCount = mReqFrameCount;
if (!(mFlags & AUDIO_INPUT_FLAG_FAST)) {
+ // validate framecount
+ // If fast track was not requested, this preserves
+ // the old behavior of validating on client side.
+ // FIXME Eventually the validation should be done on server side
+ // regardless of whether it's a fast or normal track. It's debatable
+ // whether to account for the input latency to provision buffers appropriately.
+ size_t minFrameCount;
+ status = AudioRecord::getMinFrameCount(&minFrameCount,
+ mSampleRate, mFormat, mChannelMask);
+ if (status != NO_ERROR) {
+ ALOGE("getMinFrameCount() failed for sampleRate %u, format %#x, channelMask %#x; "
+ "status %d",
+ mSampleRate, mFormat, mChannelMask, status);
+ return status;
+ }
+
+ if (frameCount == 0) {
+ frameCount = minFrameCount;
+ } else if (frameCount < minFrameCount) {
+ ALOGE("frameCount %u < minFrameCount %u", frameCount, minFrameCount);
+ return BAD_VALUE;
+ }
+
// Make sure that application is notified with sufficient margin before overrun
if (mNotificationFramesAct == 0 || mNotificationFramesAct > frameCount/2) {
mNotificationFramesAct = frameCount/2;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index d8d939a..857e703 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -1376,16 +1376,15 @@ void NuPlayer::onSourceNotify(const sp<AMessage> &msg) {
sp<NuPlayerDriver> driver = mDriver.promote();
if (driver != NULL) {
- driver->notifyPrepareCompleted(err);
- }
-
- int64_t durationUs;
- if (mDriver != NULL && mSource->getDuration(&durationUs) == OK) {
- sp<NuPlayerDriver> driver = mDriver.promote();
- if (driver != NULL) {
+ // notify duration first, so that it's definitely set when
+ // the app received the "prepare complete" callback.
+ int64_t durationUs;
+ if (mSource->getDuration(&durationUs) == OK) {
driver->notifyDuration(durationUs);
}
+ driver->notifyPrepareCompleted(err);
}
+
break;
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index e4850f0..280b5af 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -284,6 +284,10 @@ status_t NuPlayerDriver::seekTo(int msec) {
case STATE_PREPARED:
{
mStartupSeekTimeUs = seekTimeUs;
+ // pretend that the seek completed. It will actually happen when starting playback.
+ // TODO: actually perform the seek here, so the player is ready to go at the new
+ // location
+ notifySeekComplete();
break;
}
diff --git a/media/libnbaio/NBLog.cpp b/media/libnbaio/NBLog.cpp
index 4d9a1fa..4d14904 100644
--- a/media/libnbaio/NBLog.cpp
+++ b/media/libnbaio/NBLog.cpp
@@ -438,7 +438,7 @@ void NBLog::Reader::dump(int fd, size_t indent)
void NBLog::Reader::dumpLine(const String8& timestamp, String8& body)
{
if (mFd >= 0) {
- fdprintf(mFd, "%.*s%s %s\n", mIndent, "", timestamp.string(), body.string());
+ dprintf(mFd, "%.*s%s %s\n", mIndent, "", timestamp.string(), body.string());
} else {
ALOGI("%.*s%s %s", mIndent, "", timestamp.string(), body.string());
}
diff --git a/media/libstagefright/MediaBuffer.cpp b/media/libstagefright/MediaBuffer.cpp
index 11b80bf..8af0880 100644
--- a/media/libstagefright/MediaBuffer.cpp
+++ b/media/libstagefright/MediaBuffer.cpp
@@ -27,7 +27,6 @@
#include <media/stagefright/MetaData.h>
#include <ui/GraphicBuffer.h>
-#include <sys/atomics.h>
namespace android {
@@ -92,7 +91,7 @@ void MediaBuffer::release() {
return;
}
- int prevCount = __atomic_dec(&mRefCount);
+ int prevCount = __sync_fetch_and_sub(&mRefCount, 1);
if (prevCount == 1) {
if (mObserver == NULL) {
delete this;
@@ -112,7 +111,7 @@ void MediaBuffer::claim() {
}
void MediaBuffer::add_ref() {
- (void) __atomic_inc(&mRefCount);
+ (void) __sync_fetch_and_add(&mRefCount, 1);
}
void *MediaBuffer::data() const {
diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
index bd2541f..2ac16c7 100644
--- a/media/ndk/NdkMediaCodec.cpp
+++ b/media/ndk/NdkMediaCodec.cpp
@@ -61,6 +61,8 @@ public:
virtual void onMessageReceived(const sp<AMessage> &msg);
};
+typedef void (*OnCodecEvent)(AMediaCodec *codec, void *userdata);
+
struct AMediaCodec {
sp<android::MediaCodec> mCodec;
sp<ALooper> mLooper;
@@ -347,7 +349,7 @@ media_status_t AMediaCodec_releaseOutputBufferAtTime(
return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx, timestampNs));
}
-EXPORT
+//EXPORT
media_status_t AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback, void *userdata) {
mData->mCallback = callback;
mData->mCallbackUserData = userdata;
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 457ac3d..5b09d54 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -430,7 +430,7 @@ status_t AudioFlinger::dump(int fd, const Vector<String16>& args)
if (mLogMemoryDealer != 0) {
sp<IBinder> binder = defaultServiceManager()->getService(String16("media.log"));
if (binder != 0) {
- fdprintf(fd, "\nmedia.log:\n");
+ dprintf(fd, "\nmedia.log:\n");
Vector<String16> args;
binder->dump(fd, args);
}
@@ -2606,7 +2606,7 @@ void AudioFlinger::dumpTee(int fd, const sp<NBAIO_Source>& source, audio_io_hand
}
} else {
if (fd >= 0) {
- fdprintf(fd, "unable to rotate tees in %s: %s\n", teePath, strerror(errno));
+ dprintf(fd, "unable to rotate tees in %s: %s\n", teePath, strerror(errno));
}
}
char teeTime[16];
@@ -2660,11 +2660,11 @@ void AudioFlinger::dumpTee(int fd, const sp<NBAIO_Source>& source, audio_io_hand
write(teeFd, &temp, sizeof(temp));
close(teeFd);
if (fd >= 0) {
- fdprintf(fd, "tee copied to %s\n", teePath);
+ dprintf(fd, "tee copied to %s\n", teePath);
}
} else {
if (fd >= 0) {
- fdprintf(fd, "unable to create tee %s: %s\n", teePath, strerror(errno));
+ dprintf(fd, "unable to create tee %s: %s\n", teePath, strerror(errno));
}
}
}
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index 805eaa4..8d57451 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -34,6 +34,7 @@
#include <system/audio.h>
#include <audio_utils/primitives.h>
+#include <audio_utils/format.h>
#include <common_time/local_clock.h>
#include <common_time/cc_helper.h>
@@ -88,6 +89,103 @@ void AudioMixer::DownmixerBufferProvider::releaseBuffer(AudioBufferProvider::Buf
}
}
+template <typename T>
+T min(const T& a, const T& b)
+{
+ return a < b ? a : b;
+}
+
+AudioMixer::ReformatBufferProvider::ReformatBufferProvider(int32_t channels,
+ audio_format_t inputFormat, audio_format_t outputFormat) :
+ mTrackBufferProvider(NULL),
+ mChannels(channels),
+ mInputFormat(inputFormat),
+ mOutputFormat(outputFormat),
+ mInputFrameSize(channels * audio_bytes_per_sample(inputFormat)),
+ mOutputFrameSize(channels * audio_bytes_per_sample(outputFormat)),
+ mOutputData(NULL),
+ mOutputCount(0),
+ mConsumed(0)
+{
+ ALOGV("ReformatBufferProvider(%p)(%d, %#x, %#x)", this, channels, inputFormat, outputFormat);
+ if (requiresInternalBuffers()) {
+ mOutputCount = 256;
+ (void)posix_memalign(&mOutputData, 32, mOutputCount * mOutputFrameSize);
+ }
+ mBuffer.frameCount = 0;
+}
+
+AudioMixer::ReformatBufferProvider::~ReformatBufferProvider()
+{
+ ALOGV("~ReformatBufferProvider(%p)", this);
+ if (mBuffer.frameCount != 0) {
+ mTrackBufferProvider->releaseBuffer(&mBuffer);
+ }
+ free(mOutputData);
+}
+
+status_t AudioMixer::ReformatBufferProvider::getNextBuffer(AudioBufferProvider::Buffer *pBuffer,
+ int64_t pts) {
+ //ALOGV("ReformatBufferProvider(%p)::getNextBuffer(%p (%zu), %lld)",
+ // this, pBuffer, pBuffer->frameCount, pts);
+ if (!requiresInternalBuffers()) {
+ status_t res = mTrackBufferProvider->getNextBuffer(pBuffer, pts);
+ if (res == OK) {
+ memcpy_by_audio_format(pBuffer->raw, mOutputFormat, pBuffer->raw, mInputFormat,
+ pBuffer->frameCount * mChannels);
+ }
+ return res;
+ }
+ if (mBuffer.frameCount == 0) {
+ mBuffer.frameCount = pBuffer->frameCount;
+ status_t res = mTrackBufferProvider->getNextBuffer(&mBuffer, pts);
+ // TODO: Track down a bug in the upstream provider
+ // LOG_ALWAYS_FATAL_IF(res == OK && mBuffer.frameCount == 0,
+ // "ReformatBufferProvider::getNextBuffer():"
+ // " Invalid zero framecount returned from getNextBuffer()");
+ if (res != OK || mBuffer.frameCount == 0) {
+ pBuffer->raw = NULL;
+ pBuffer->frameCount = 0;
+ return res;
+ }
+ }
+ ALOG_ASSERT(mConsumed < mBuffer.frameCount);
+ size_t count = min(mOutputCount, mBuffer.frameCount - mConsumed);
+ count = min(count, pBuffer->frameCount);
+ pBuffer->raw = mOutputData;
+ pBuffer->frameCount = count;
+ //ALOGV("reformatting %d frames from %#x to %#x, %d chan",
+ // pBuffer->frameCount, mInputFormat, mOutputFormat, mChannels);
+ memcpy_by_audio_format(pBuffer->raw, mOutputFormat,
+ (uint8_t*)mBuffer.raw + mConsumed * mInputFrameSize, mInputFormat,
+ pBuffer->frameCount * mChannels);
+ return OK;
+}
+
+void AudioMixer::ReformatBufferProvider::releaseBuffer(AudioBufferProvider::Buffer *pBuffer) {
+ //ALOGV("ReformatBufferProvider(%p)::releaseBuffer(%p(%zu))",
+ // this, pBuffer, pBuffer->frameCount);
+ if (!requiresInternalBuffers()) {
+ mTrackBufferProvider->releaseBuffer(pBuffer);
+ return;
+ }
+ // LOG_ALWAYS_FATAL_IF(pBuffer->frameCount == 0, "Invalid framecount");
+ mConsumed += pBuffer->frameCount; // TODO: update for efficiency to reuse existing content
+ if (mConsumed != 0 && mConsumed >= mBuffer.frameCount) {
+ mConsumed = 0;
+ mTrackBufferProvider->releaseBuffer(&mBuffer);
+ // ALOG_ASSERT(mBuffer.frameCount == 0);
+ }
+ pBuffer->raw = NULL;
+ pBuffer->frameCount = 0;
+}
+
+void AudioMixer::ReformatBufferProvider::reset() {
+ if (mBuffer.frameCount != 0) {
+ mTrackBufferProvider->releaseBuffer(&mBuffer);
+ }
+ mConsumed = 0;
+}
// ----------------------------------------------------------------------------
bool AudioMixer::sIsMultichannelCapable = false;
@@ -153,8 +251,13 @@ void AudioMixer::setLog(NBLog::Writer *log)
mState.mLog = log;
}
-int AudioMixer::getTrackName(audio_channel_mask_t channelMask, int sessionId)
+int AudioMixer::getTrackName(audio_channel_mask_t channelMask,
+ audio_format_t format, int sessionId)
{
+ if (!isValidPcmTrackFormat(format)) {
+ ALOGE("AudioMixer::getTrackName invalid format (%#x)", format);
+ return -1;
+ }
uint32_t names = (~mTrackNames) & mConfiguredNames;
if (names != 0) {
int n = __builtin_ctz(names);
@@ -176,7 +279,8 @@ int AudioMixer::getTrackName(audio_channel_mask_t channelMask, int sessionId)
// t->frameCount
t->channelCount = audio_channel_count_from_out_mask(channelMask);
t->enabled = false;
- t->format = 16;
+ ALOGV_IF(channelMask != AUDIO_CHANNEL_OUT_STEREO,
+ "Non-stereo channel mask: %d\n", channelMask);
t->channelMask = channelMask;
t->sessionId = sessionId;
// setBufferProvider(name, AudioBufferProvider *) is required before enable(name)
@@ -191,9 +295,15 @@ int AudioMixer::getTrackName(audio_channel_mask_t channelMask, int sessionId)
// setParameter(name, TRACK, MAIN_BUFFER, mixBuffer) is required before enable(name)
t->mainBuffer = NULL;
t->auxBuffer = NULL;
+ t->mInputBufferProvider = NULL;
+ t->mReformatBufferProvider = NULL;
t->downmixerBufferProvider = NULL;
t->mMixerFormat = AUDIO_FORMAT_PCM_16_BIT;
-
+ t->mFormat = format;
+ t->mMixerInFormat = AUDIO_FORMAT_PCM_16_BIT;
+ if (t->mFormat != t->mMixerInFormat) {
+ prepareTrackForReformat(t, n);
+ }
status_t status = initTrackDownmix(&mState.tracks[n], n, channelMask);
if (status != OK) {
ALOGE("AudioMixer::getTrackName invalid channelMask (%#x)", channelMask);
@@ -237,9 +347,9 @@ void AudioMixer::unprepareTrackForDownmix(track_t* pTrack, int trackName __unuse
if (pTrack->downmixerBufferProvider != NULL) {
// this track had previously been configured with a downmixer, delete it
ALOGV(" deleting old downmixer");
- pTrack->bufferProvider = pTrack->downmixerBufferProvider->mTrackBufferProvider;
delete pTrack->downmixerBufferProvider;
pTrack->downmixerBufferProvider = NULL;
+ reconfigureBufferProviders(pTrack);
} else {
ALOGV(" nothing to do, no downmixer to delete");
}
@@ -333,21 +443,51 @@ status_t AudioMixer::prepareTrackForDownmix(track_t* pTrack, int trackName)
}// end of scope for local variables that are not used in goto label "noDownmixForActiveTrack"
// initialization successful:
- // - keep track of the real buffer provider in case it was set before
- pDbp->mTrackBufferProvider = pTrack->bufferProvider;
- // - we'll use the downmix effect integrated inside this
- // track's buffer provider, and we'll use it as the track's buffer provider
pTrack->downmixerBufferProvider = pDbp;
- pTrack->bufferProvider = pDbp;
-
+ reconfigureBufferProviders(pTrack);
return NO_ERROR;
noDownmixForActiveTrack:
delete pDbp;
pTrack->downmixerBufferProvider = NULL;
+ reconfigureBufferProviders(pTrack);
return NO_INIT;
}
+void AudioMixer::unprepareTrackForReformat(track_t* pTrack, int trackName __unused) {
+ ALOGV("AudioMixer::unprepareTrackForReformat(%d)", trackName);
+ if (pTrack->mReformatBufferProvider != NULL) {
+ delete pTrack->mReformatBufferProvider;
+ pTrack->mReformatBufferProvider = NULL;
+ reconfigureBufferProviders(pTrack);
+ }
+}
+
+status_t AudioMixer::prepareTrackForReformat(track_t* pTrack, int trackName)
+{
+ ALOGV("AudioMixer::prepareTrackForReformat(%d) with format %#x", trackName, pTrack->mFormat);
+ // discard the previous reformatter if there was one
+ unprepareTrackForReformat(pTrack, trackName);
+ pTrack->mReformatBufferProvider = new ReformatBufferProvider(
+ audio_channel_count_from_out_mask(pTrack->channelMask),
+ pTrack->mFormat, pTrack->mMixerInFormat);
+ reconfigureBufferProviders(pTrack);
+ return NO_ERROR;
+}
+
+void AudioMixer::reconfigureBufferProviders(track_t* pTrack)
+{
+ pTrack->bufferProvider = pTrack->mInputBufferProvider;
+ if (pTrack->mReformatBufferProvider) {
+ pTrack->mReformatBufferProvider->mTrackBufferProvider = pTrack->bufferProvider;
+ pTrack->bufferProvider = pTrack->mReformatBufferProvider;
+ }
+ if (pTrack->downmixerBufferProvider) {
+ pTrack->downmixerBufferProvider->mTrackBufferProvider = pTrack->bufferProvider;
+ pTrack->bufferProvider = pTrack->downmixerBufferProvider;
+ }
+}
+
void AudioMixer::deleteTrackName(int name)
{
ALOGV("AudioMixer::deleteTrackName(%d)", name);
@@ -364,6 +504,8 @@ void AudioMixer::deleteTrackName(int name)
track.resampler = NULL;
// delete the downmixer
unprepareTrackForDownmix(&mState.tracks[name], name);
+ // delete the reformatter
+ unprepareTrackForReformat(&mState.tracks[name], name);
mTrackNames &= ~(1<<name);
}
@@ -435,9 +577,20 @@ void AudioMixer::setParameter(int name, int target, int param, void *value)
invalidateState(1 << name);
}
break;
- case FORMAT:
- ALOG_ASSERT(valueInt == AUDIO_FORMAT_PCM_16_BIT);
- break;
+ case FORMAT: {
+ audio_format_t format = static_cast<audio_format_t>(valueInt);
+ if (track.mFormat != format) {
+ ALOG_ASSERT(audio_is_linear_pcm(format), "Invalid format %#x", format);
+ track.mFormat = format;
+ ALOGV("setParameter(TRACK, FORMAT, %#x)", format);
+ //if (track.mFormat != track.mMixerInFormat)
+ {
+ ALOGD("Reformatting!");
+ prepareTrackForReformat(&track, name);
+ }
+ invalidateState(1 << name);
+ }
+ } break;
// FIXME do we want to support setting the downmix type from AudioFlinger?
// for a specific track? or per mixer?
/* case DOWNMIX_TYPE:
@@ -550,8 +703,9 @@ bool AudioMixer::track_t::setResampler(uint32_t value, uint32_t devSampleRate)
} else {
quality = AudioResampler::DEFAULT_QUALITY;
}
+ const int bits = mMixerInFormat == AUDIO_FORMAT_PCM_16_BIT ? 16 : /* FLOAT */ 32;
resampler = AudioResampler::create(
- format,
+ bits,
// the resampler sees the number of channels after the downmixer, if any
(int) (downmixerBufferProvider != NULL ? MAX_NUM_CHANNELS : channelCount),
devSampleRate, quality);
@@ -596,21 +750,13 @@ void AudioMixer::setBufferProvider(int name, AudioBufferProvider* bufferProvider
name -= TRACK0;
ALOG_ASSERT(uint32_t(name) < MAX_NUM_TRACKS, "bad track name %d", name);
- if (mState.tracks[name].downmixerBufferProvider != NULL) {
- // update required?
- if (mState.tracks[name].downmixerBufferProvider->mTrackBufferProvider != bufferProvider) {
- ALOGV("AudioMixer::setBufferProvider(%p) for downmix", bufferProvider);
- // setting the buffer provider for a track that gets downmixed consists in:
- // 1/ setting the buffer provider to the "downmix / buffer provider" wrapper
- // so it's the one that gets called when the buffer provider is needed,
- mState.tracks[name].bufferProvider = mState.tracks[name].downmixerBufferProvider;
- // 2/ saving the buffer provider for the track so the wrapper can use it
- // when it downmixes.
- mState.tracks[name].downmixerBufferProvider->mTrackBufferProvider = bufferProvider;
- }
- } else {
- mState.tracks[name].bufferProvider = bufferProvider;
+ if (mState.tracks[name].mReformatBufferProvider != NULL) {
+ mState.tracks[name].mReformatBufferProvider->reset();
+ } else if (mState.tracks[name].downmixerBufferProvider != NULL) {
}
+
+ mState.tracks[name].mInputBufferProvider = bufferProvider;
+ reconfigureBufferProviders(&mState.tracks[name]);
}
diff --git a/services/audioflinger/AudioMixer.h b/services/audioflinger/AudioMixer.h
index 09e63a6..573ba96 100644
--- a/services/audioflinger/AudioMixer.h
+++ b/services/audioflinger/AudioMixer.h
@@ -104,7 +104,10 @@ public:
// For all APIs with "name": TRACK0 <= name < TRACK0 + MAX_NUM_TRACKS
// Allocate a track name. Returns new track name if successful, -1 on failure.
- int getTrackName(audio_channel_mask_t channelMask, int sessionId);
+ // The failure could be because of an invalid channelMask or format, or that
+ // the track capacity of the mixer is exceeded.
+ int getTrackName(audio_channel_mask_t channelMask,
+ audio_format_t format, int sessionId);
// Free an allocated track by name
void deleteTrackName(int name);
@@ -122,6 +125,13 @@ public:
size_t getUnreleasedFrames(int name) const;
+ static inline bool isValidPcmTrackFormat(audio_format_t format) {
+ return format == AUDIO_FORMAT_PCM_16_BIT ||
+ format == AUDIO_FORMAT_PCM_24_BIT_PACKED ||
+ format == AUDIO_FORMAT_PCM_32_BIT ||
+ format == AUDIO_FORMAT_PCM_FLOAT;
+ }
+
private:
enum {
@@ -143,6 +153,7 @@ private:
struct state_t;
struct track_t;
class DownmixerBufferProvider;
+ class ReformatBufferProvider;
typedef void (*hook_t)(track_t* t, int32_t* output, size_t numOutFrames, int32_t* temp,
int32_t* aux);
@@ -170,7 +181,7 @@ private:
uint16_t frameCount;
uint8_t channelCount; // 1 or 2, redundant with (needs & NEEDS_CHANNEL_COUNT__MASK)
- uint8_t format; // always 16
+ uint8_t unused_padding; // formerly format, was always 16
uint16_t enabled; // actually bool
audio_channel_mask_t channelMask;
@@ -193,14 +204,19 @@ private:
int32_t* auxBuffer;
// 16-byte boundary
-
+ AudioBufferProvider* mInputBufferProvider; // 4 bytes
+ ReformatBufferProvider* mReformatBufferProvider; // 4 bytes
DownmixerBufferProvider* downmixerBufferProvider; // 4 bytes
int32_t sessionId;
- audio_format_t mMixerFormat; // at this time: AUDIO_FORMAT_PCM_(FLOAT|16_BIT)
+ // 16-byte boundary
+ audio_format_t mMixerFormat; // output mix format: AUDIO_FORMAT_PCM_(FLOAT|16_BIT)
+ audio_format_t mFormat; // input track format
+ audio_format_t mMixerInFormat; // mix internal format AUDIO_FORMAT_PCM_(FLOAT|16_BIT)
+ // each track must be converted to this format.
- int32_t padding[1];
+ int32_t mUnused[1]; // alignment padding
// 16-byte boundary
@@ -239,6 +255,35 @@ private:
effect_config_t mDownmixConfig;
};
+ // AudioBufferProvider wrapper that reformats track to acceptable mixer input type
+ class ReformatBufferProvider : public AudioBufferProvider {
+ public:
+ ReformatBufferProvider(int32_t channels,
+ audio_format_t inputFormat, audio_format_t outputFormat);
+ virtual ~ReformatBufferProvider();
+
+ // overrides AudioBufferProvider methods
+ virtual status_t getNextBuffer(Buffer* buffer, int64_t pts);
+ virtual void releaseBuffer(Buffer* buffer);
+
+ void reset();
+ inline bool requiresInternalBuffers() {
+ return true; //mInputFrameSize < mOutputFrameSize;
+ }
+
+ AudioBufferProvider* mTrackBufferProvider;
+ int32_t mChannels;
+ audio_format_t mInputFormat;
+ audio_format_t mOutputFormat;
+ size_t mInputFrameSize;
+ size_t mOutputFrameSize;
+ // (only) required for reformatting to a larger size.
+ AudioBufferProvider::Buffer mBuffer;
+ void* mOutputData;
+ size_t mOutputCount;
+ size_t mConsumed;
+ };
+
// bitmask of allocated track names, where bit 0 corresponds to TRACK0 etc.
uint32_t mTrackNames;
@@ -266,6 +311,9 @@ private:
static status_t initTrackDownmix(track_t* pTrack, int trackNum, audio_channel_mask_t mask);
static status_t prepareTrackForDownmix(track_t* pTrack, int trackNum);
static void unprepareTrackForDownmix(track_t* pTrack, int trackName);
+ static status_t prepareTrackForReformat(track_t* pTrack, int trackNum);
+ static void unprepareTrackForReformat(track_t* pTrack, int trackName);
+ static void reconfigureBufferProviders(track_t* pTrack);
static void track__genericResample(track_t* t, int32_t* out, size_t numFrames, int32_t* temp,
int32_t* aux);
diff --git a/services/audioflinger/AudioResamplerDyn.cpp b/services/audioflinger/AudioResamplerDyn.cpp
index 3abe8fd..a4446a4 100644
--- a/services/audioflinger/AudioResamplerDyn.cpp
+++ b/services/audioflinger/AudioResamplerDyn.cpp
@@ -455,12 +455,13 @@ void AudioResamplerDyn<TC, TI, TO>::resample(TO* out, size_t outFrameCount,
const Constants& c(mConstants);
const TC* const coefs = mConstants.mFirCoefs;
TI* impulse = mInBuffer.getImpulse();
- size_t inputIndex = mInputIndex;
+ size_t inputIndex = 0;
uint32_t phaseFraction = mPhaseFraction;
const uint32_t phaseIncrement = mPhaseIncrement;
size_t outputIndex = 0;
size_t outputSampleCount = outFrameCount * 2; // stereo output
- size_t inFrameCount = getInFrameCountRequired(outFrameCount);
+ size_t inFrameCount = getInFrameCountRequired(outFrameCount) + (phaseFraction != 0);
+ ALOG_ASSERT(0 < inFrameCount && inFrameCount < (1U << 31));
const uint32_t phaseWrapLimit = c.mL << c.mShift;
// NOTE: be very careful when modifying the code here. register
@@ -474,11 +475,13 @@ void AudioResamplerDyn<TC, TI, TO>::resample(TO* out, size_t outFrameCount,
// buffer is empty, fetch a new one
while (mBuffer.frameCount == 0) {
mBuffer.frameCount = inFrameCount;
+ ALOG_ASSERT(inFrameCount > 0);
provider->getNextBuffer(&mBuffer,
calculateOutputPTS(outputIndex / 2));
if (mBuffer.raw == NULL) {
goto resample_exit;
}
+ inFrameCount -= mBuffer.frameCount;
if (phaseFraction >= phaseWrapLimit) { // read in data
mInBuffer.template readAdvance<CHANNELS>(
impulse, c.mHalfNumCoefs,
@@ -487,7 +490,7 @@ void AudioResamplerDyn<TC, TI, TO>::resample(TO* out, size_t outFrameCount,
while (phaseFraction >= phaseWrapLimit) {
inputIndex++;
if (inputIndex >= mBuffer.frameCount) {
- inputIndex -= mBuffer.frameCount;
+ inputIndex = 0;
provider->releaseBuffer(&mBuffer);
break;
}
@@ -535,15 +538,22 @@ void AudioResamplerDyn<TC, TI, TO>::resample(TO* out, size_t outFrameCount,
done:
// often arrives here when input buffer runs out
if (inputIndex >= frameCount) {
- inputIndex -= frameCount;
+ inputIndex = 0;
provider->releaseBuffer(&mBuffer);
- // mBuffer.frameCount MUST be zero here.
+ ALOG_ASSERT(mBuffer.frameCount == 0);
}
}
resample_exit:
+ // Release frames to avoid the count being inaccurate for pts timing.
+ // TODO: Avoid this extra check by making fetch count exact. This is tricky
+ // due to the overfetching mechanism which loads unnecessarily when
+ // mBuffer.frameCount == 0.
+ if (inputIndex) {
+ mBuffer.frameCount = inputIndex;
+ provider->releaseBuffer(&mBuffer);
+ }
mInBuffer.setImpulse(impulse);
- mInputIndex = inputIndex;
mPhaseFraction = phaseFraction;
}
diff --git a/services/audioflinger/AudioWatchdog.cpp b/services/audioflinger/AudioWatchdog.cpp
index 93d185e..877e776 100644
--- a/services/audioflinger/AudioWatchdog.cpp
+++ b/services/audioflinger/AudioWatchdog.cpp
@@ -34,7 +34,7 @@ void AudioWatchdogDump::dump(int fd)
} else {
strcpy(buf, "N/A\n");
}
- fdprintf(fd, "Watchdog: underruns=%u, logs=%u, most recent underrun log at %s",
+ dprintf(fd, "Watchdog: underruns=%u, logs=%u, most recent underrun log at %s",
mUnderruns, mLogs, buf);
}
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index 1caed11..c840418 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -26,7 +26,6 @@
#define ATRACE_TAG ATRACE_TAG_AUDIO
#include "Configuration.h"
-#include <sys/atomics.h>
#include <time.h>
#include <utils/Log.h>
#include <utils/Trace.h>
@@ -53,8 +52,8 @@ FastMixer::FastMixer() : FastThread(),
outputSink(NULL),
outputSinkGen(0),
mixer(NULL),
- mixBuffer(NULL),
- mixBufferState(UNDEFINED),
+ mMixerBuffer(NULL),
+ mMixerBufferState(UNDEFINED),
format(Format_Invalid),
sampleRate(0),
fastTracksGen(0),
@@ -109,7 +108,7 @@ void FastMixer::onIdle()
void FastMixer::onExit()
{
delete mixer;
- delete[] mixBuffer;
+ delete[] mMixerBuffer;
}
bool FastMixer::isSubClassCommand(FastThreadState::Command command)
@@ -155,14 +154,14 @@ void FastMixer::onStateChange()
// FIXME to avoid priority inversion, don't delete here
delete mixer;
mixer = NULL;
- delete[] mixBuffer;
- mixBuffer = NULL;
+ delete[] mMixerBuffer;
+ mMixerBuffer = NULL;
if (frameCount > 0 && sampleRate > 0) {
// FIXME new may block for unbounded time at internal mutex of the heap
// implementation; it would be better to have normal mixer allocate for us
// to avoid blocking here and to prevent possible priority inversion
mixer = new AudioMixer(frameCount, sampleRate, FastMixerState::kMaxFastTracks);
- mixBuffer = new short[frameCount * FCC_2];
+ mMixerBuffer = new short[frameCount * FCC_2];
periodNs = (frameCount * 1000000000LL) / sampleRate; // 1.00
underrunNs = (frameCount * 1750000000LL) / sampleRate; // 1.75
overrunNs = (frameCount * 500000000LL) / sampleRate; // 0.50
@@ -175,7 +174,7 @@ void FastMixer::onStateChange()
forceNs = 0;
warmupNs = 0;
}
- mixBufferState = UNDEFINED;
+ mMixerBufferState = UNDEFINED;
#if !LOG_NDEBUG
for (unsigned i = 0; i < FastMixerState::kMaxFastTracks; ++i) {
fastTrackNames[i] = -1;
@@ -193,7 +192,7 @@ void FastMixer::onStateChange()
const unsigned currentTrackMask = current->mTrackMask;
dumpState->mTrackMask = currentTrackMask;
if (current->mFastTracksGen != fastTracksGen) {
- ALOG_ASSERT(mixBuffer != NULL);
+ ALOG_ASSERT(mMixerBuffer != NULL);
int name;
// process removed tracks first to avoid running out of track names
@@ -224,13 +223,16 @@ void FastMixer::onStateChange()
AudioBufferProvider *bufferProvider = fastTrack->mBufferProvider;
ALOG_ASSERT(bufferProvider != NULL && fastTrackNames[i] == -1);
if (mixer != NULL) {
- name = mixer->getTrackName(fastTrack->mChannelMask, AUDIO_SESSION_OUTPUT_MIX);
+ name = mixer->getTrackName(fastTrack->mChannelMask,
+ fastTrack->mFormat, AUDIO_SESSION_OUTPUT_MIX);
ALOG_ASSERT(name >= 0);
fastTrackNames[i] = name;
mixer->setBufferProvider(name, bufferProvider);
mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER,
- (void *) mixBuffer);
+ (void *) mMixerBuffer);
// newly allocated track names default to full scale volume
+ mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::FORMAT,
+ (void *)(uintptr_t)fastTrack->mFormat);
mixer->enable(name);
}
generations[i] = fastTrack->mGeneration;
@@ -259,6 +261,8 @@ void FastMixer::onStateChange()
}
mixer->setParameter(name, AudioMixer::RESAMPLE,
AudioMixer::REMOVE, NULL);
+ mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::FORMAT,
+ (void *)(uintptr_t)fastTrack->mFormat);
mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK,
(void *)(uintptr_t) fastTrack->mChannelMask);
// already enabled
@@ -281,7 +285,7 @@ void FastMixer::onWork()
const size_t frameCount = current->mFrameCount;
if ((command & FastMixerState::MIX) && (mixer != NULL) && isWarm) {
- ALOG_ASSERT(mixBuffer != NULL);
+ ALOG_ASSERT(mMixerBuffer != NULL);
// for each track, update volume and check for underrun
unsigned currentTrackMask = current->mTrackMask;
while (currentTrackMask != 0) {
@@ -358,26 +362,26 @@ void FastMixer::onWork()
// process() is CPU-bound
mixer->process(pts);
- mixBufferState = MIXED;
- } else if (mixBufferState == MIXED) {
- mixBufferState = UNDEFINED;
+ mMixerBufferState = MIXED;
+ } else if (mMixerBufferState == MIXED) {
+ mMixerBufferState = UNDEFINED;
}
//bool didFullWrite = false; // dumpsys could display a count of partial writes
- if ((command & FastMixerState::WRITE) && (outputSink != NULL) && (mixBuffer != NULL)) {
- if (mixBufferState == UNDEFINED) {
- memset(mixBuffer, 0, frameCount * FCC_2 * sizeof(short));
- mixBufferState = ZEROED;
+ if ((command & FastMixerState::WRITE) && (outputSink != NULL) && (mMixerBuffer != NULL)) {
+ if (mMixerBufferState == UNDEFINED) {
+ memset(mMixerBuffer, 0, frameCount * FCC_2 * sizeof(short));
+ mMixerBufferState = ZEROED;
}
// if non-NULL, then duplicate write() to this non-blocking sink
NBAIO_Sink* teeSink;
if ((teeSink = current->mTeeSink) != NULL) {
- (void) teeSink->write(mixBuffer, frameCount);
+ (void) teeSink->write(mMixerBuffer, frameCount);
}
// FIXME write() is non-blocking and lock-free for a properly implemented NBAIO sink,
// but this code should be modified to handle both non-blocking and blocking sinks
dumpState->mWriteSequence++;
ATRACE_BEGIN("write");
- ssize_t framesWritten = outputSink->write(mixBuffer, frameCount);
+ ssize_t framesWritten = outputSink->write(mMixerBuffer, frameCount);
ATRACE_END();
dumpState->mWriteSequence++;
if (framesWritten >= 0) {
@@ -461,7 +465,7 @@ static int compare_uint32_t(const void *pa, const void *pb)
void FastMixerDumpState::dump(int fd) const
{
if (mCommand == FastMixerState::INITIAL) {
- fdprintf(fd, " FastMixer not initialized\n");
+ dprintf(fd, " FastMixer not initialized\n");
return;
}
#define COMMAND_MAX 32
@@ -495,10 +499,10 @@ void FastMixerDumpState::dump(int fd) const
double measuredWarmupMs = (mMeasuredWarmupTs.tv_sec * 1000.0) +
(mMeasuredWarmupTs.tv_nsec / 1000000.0);
double mixPeriodSec = (double) mFrameCount / (double) mSampleRate;
- fdprintf(fd, " FastMixer command=%s writeSequence=%u framesWritten=%u\n"
- " numTracks=%u writeErrors=%u underruns=%u overruns=%u\n"
- " sampleRate=%u frameCount=%zu measuredWarmup=%.3g ms, warmupCycles=%u\n"
- " mixPeriod=%.2f ms\n",
+ dprintf(fd, " FastMixer command=%s writeSequence=%u framesWritten=%u\n"
+ " numTracks=%u writeErrors=%u underruns=%u overruns=%u\n"
+ " sampleRate=%u frameCount=%zu measuredWarmup=%.3g ms, warmupCycles=%u\n"
+ " mixPeriod=%.2f ms\n",
string, mWriteSequence, mFramesWritten,
mNumTracks, mWriteErrors, mUnderruns, mOverruns,
mSampleRate, mFrameCount, measuredWarmupMs, mWarmupCycles,
@@ -550,26 +554,26 @@ void FastMixerDumpState::dump(int fd) const
#endif
}
if (n) {
- fdprintf(fd, " Simple moving statistics over last %.1f seconds:\n",
- wall.n() * mixPeriodSec);
- fdprintf(fd, " wall clock time in ms per mix cycle:\n"
- " mean=%.2f min=%.2f max=%.2f stddev=%.2f\n",
- wall.mean()*1e-6, wall.minimum()*1e-6, wall.maximum()*1e-6,
- wall.stddev()*1e-6);
- fdprintf(fd, " raw CPU load in us per mix cycle:\n"
- " mean=%.0f min=%.0f max=%.0f stddev=%.0f\n",
- loadNs.mean()*1e-3, loadNs.minimum()*1e-3, loadNs.maximum()*1e-3,
- loadNs.stddev()*1e-3);
+ dprintf(fd, " Simple moving statistics over last %.1f seconds:\n",
+ wall.n() * mixPeriodSec);
+ dprintf(fd, " wall clock time in ms per mix cycle:\n"
+ " mean=%.2f min=%.2f max=%.2f stddev=%.2f\n",
+ wall.mean()*1e-6, wall.minimum()*1e-6, wall.maximum()*1e-6,
+ wall.stddev()*1e-6);
+ dprintf(fd, " raw CPU load in us per mix cycle:\n"
+ " mean=%.0f min=%.0f max=%.0f stddev=%.0f\n",
+ loadNs.mean()*1e-3, loadNs.minimum()*1e-3, loadNs.maximum()*1e-3,
+ loadNs.stddev()*1e-3);
} else {
- fdprintf(fd, " No FastMixer statistics available currently\n");
+ dprintf(fd, " No FastMixer statistics available currently\n");
}
#ifdef CPU_FREQUENCY_STATISTICS
- fdprintf(fd, " CPU clock frequency in MHz:\n"
- " mean=%.0f min=%.0f max=%.0f stddev=%.0f\n",
- kHz.mean()*1e-3, kHz.minimum()*1e-3, kHz.maximum()*1e-3, kHz.stddev()*1e-3);
- fdprintf(fd, " adjusted CPU load in MHz (i.e. normalized for CPU clock frequency):\n"
- " mean=%.1f min=%.1f max=%.1f stddev=%.1f\n",
- loadMHz.mean(), loadMHz.minimum(), loadMHz.maximum(), loadMHz.stddev());
+ dprintf(fd, " CPU clock frequency in MHz:\n"
+ " mean=%.0f min=%.0f max=%.0f stddev=%.0f\n",
+ kHz.mean()*1e-3, kHz.minimum()*1e-3, kHz.maximum()*1e-3, kHz.stddev()*1e-3);
+ dprintf(fd, " adjusted CPU load in MHz (i.e. normalized for CPU clock frequency):\n"
+ " mean=%.1f min=%.1f max=%.1f stddev=%.1f\n",
+ loadMHz.mean(), loadMHz.minimum(), loadMHz.maximum(), loadMHz.stddev());
#endif
if (tail != NULL) {
qsort(tail, n, sizeof(uint32_t), compare_uint32_t);
@@ -580,12 +584,12 @@ void FastMixerDumpState::dump(int fd) const
left.sample(tail[i]);
right.sample(tail[n - (i + 1)]);
}
- fdprintf(fd, " Distribution of mix cycle times in ms for the tails (> ~3 stddev outliers):\n"
- " left tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n"
- " right tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n",
- left.mean()*1e-6, left.minimum()*1e-6, left.maximum()*1e-6, left.stddev()*1e-6,
- right.mean()*1e-6, right.minimum()*1e-6, right.maximum()*1e-6,
- right.stddev()*1e-6);
+ dprintf(fd, " Distribution of mix cycle times in ms for the tails (> ~3 stddev outliers):\n"
+ " left tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n"
+ " right tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n",
+ left.mean()*1e-6, left.minimum()*1e-6, left.maximum()*1e-6, left.stddev()*1e-6,
+ right.mean()*1e-6, right.minimum()*1e-6, right.maximum()*1e-6,
+ right.stddev()*1e-6);
delete[] tail;
}
#endif
@@ -595,9 +599,9 @@ void FastMixerDumpState::dump(int fd) const
// Instead we always display all tracks, with an indication
// of whether we think the track is active.
uint32_t trackMask = mTrackMask;
- fdprintf(fd, " Fast tracks: kMaxFastTracks=%u activeMask=%#x\n",
+ dprintf(fd, " Fast tracks: kMaxFastTracks=%u activeMask=%#x\n",
FastMixerState::kMaxFastTracks, trackMask);
- fdprintf(fd, " Index Active Full Partial Empty Recent Ready\n");
+ dprintf(fd, " Index Active Full Partial Empty Recent Ready\n");
for (uint32_t i = 0; i < FastMixerState::kMaxFastTracks; ++i, trackMask >>= 1) {
bool isActive = trackMask & 1;
const FastTrackDump *ftDump = &mTracks[i];
@@ -617,7 +621,7 @@ void FastMixerDumpState::dump(int fd) const
mostRecent = "?";
break;
}
- fdprintf(fd, " %5u %6s %4u %7u %5u %7s %5zu\n", i, isActive ? "yes" : "no",
+ dprintf(fd, " %5u %6s %4u %7u %5u %7s %5zu\n", i, isActive ? "yes" : "no",
(underruns.mBitFields.mFull) & UNDERRUN_MASK,
(underruns.mBitFields.mPartial) & UNDERRUN_MASK,
(underruns.mBitFields.mEmpty) & UNDERRUN_MASK,
diff --git a/services/audioflinger/FastMixer.h b/services/audioflinger/FastMixer.h
index db89ef4..db3e2c9 100644
--- a/services/audioflinger/FastMixer.h
+++ b/services/audioflinger/FastMixer.h
@@ -61,8 +61,8 @@ private:
NBAIO_Sink *outputSink;
int outputSinkGen;
AudioMixer* mixer;
- short *mixBuffer;
- enum {UNDEFINED, MIXED, ZEROED} mixBufferState;
+ short *mMixerBuffer;
+ enum {UNDEFINED, MIXED, ZEROED} mMixerBufferState;
NBAIO_Format format;
unsigned sampleRate;
int fastTracksGen;
diff --git a/services/audioflinger/FastMixerState.cpp b/services/audioflinger/FastMixerState.cpp
index 8e6d0d4..3aa8dad 100644
--- a/services/audioflinger/FastMixerState.cpp
+++ b/services/audioflinger/FastMixerState.cpp
@@ -20,7 +20,7 @@ namespace android {
FastTrack::FastTrack() :
mBufferProvider(NULL), mVolumeProvider(NULL),
- mChannelMask(AUDIO_CHANNEL_OUT_STEREO), mGeneration(0)
+ mChannelMask(AUDIO_CHANNEL_OUT_STEREO), mFormat(AUDIO_FORMAT_INVALID), mGeneration(0)
{
}
diff --git a/services/audioflinger/FastMixerState.h b/services/audioflinger/FastMixerState.h
index e388fb3..661c9ca 100644
--- a/services/audioflinger/FastMixerState.h
+++ b/services/audioflinger/FastMixerState.h
@@ -45,6 +45,7 @@ struct FastTrack {
ExtendedAudioBufferProvider* mBufferProvider; // must be NULL if inactive, or non-NULL if active
VolumeProvider* mVolumeProvider; // optional; if NULL then full-scale
audio_channel_mask_t mChannelMask; // AUDIO_CHANNEL_OUT_MONO or AUDIO_CHANNEL_OUT_STEREO
+ audio_format_t mFormat; // track format
int mGeneration; // increment when any field is assigned
};
diff --git a/services/audioflinger/StateQueue.cpp b/services/audioflinger/StateQueue.cpp
index 48399c0..7e01c9f 100644
--- a/services/audioflinger/StateQueue.cpp
+++ b/services/audioflinger/StateQueue.cpp
@@ -28,12 +28,12 @@ namespace android {
#ifdef STATE_QUEUE_DUMP
void StateQueueObserverDump::dump(int fd)
{
- fdprintf(fd, "State queue observer: stateChanges=%u\n", mStateChanges);
+ dprintf(fd, "State queue observer: stateChanges=%u\n", mStateChanges);
}
void StateQueueMutatorDump::dump(int fd)
{
- fdprintf(fd, "State queue mutator: pushDirty=%u pushAck=%u blockedSequence=%u\n",
+ dprintf(fd, "State queue mutator: pushDirty=%u pushAck=%u blockedSequence=%u\n",
mPushDirty, mPushAck, mBlockedSequence);
}
#endif
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 4972c7a..576350e 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -142,8 +142,17 @@ static const int kPriorityFastMixer = 3;
// FIXME It would be better for client to tell AudioFlinger the value of N,
// so AudioFlinger could allocate the right amount of memory.
// See the client's minBufCount and mNotificationFramesAct calculations for details.
+
+// This is the default value, if not specified by property.
static const int kFastTrackMultiplier = 2;
+// The minimum and maximum allowed values
+static const int kFastTrackMultiplierMin = 1;
+static const int kFastTrackMultiplierMax = 2;
+
+// The actual value to use, which can be specified per-device via property af.fast_track_multiplier.
+static int sFastTrackMultiplier = kFastTrackMultiplier;
+
// See Thread::readOnlyHeap().
// Initially this heap is used to allocate client buffers for "fast" AudioRecord.
// Eventually it will be the single buffer that FastCapture writes into via HAL read(),
@@ -152,6 +161,22 @@ static const size_t kRecordThreadReadOnlyHeapSize = 0x1000;
// ----------------------------------------------------------------------------
+static pthread_once_t sFastTrackMultiplierOnce = PTHREAD_ONCE_INIT;
+
+static void sFastTrackMultiplierInit()
+{
+ char value[PROPERTY_VALUE_MAX];
+ if (property_get("af.fast_track_multiplier", value, NULL) > 0) {
+ char *endptr;
+ unsigned long ul = strtoul(value, &endptr, 0);
+ if (*endptr == '\0' && kFastTrackMultiplierMin <= ul && ul <= kFastTrackMultiplierMax) {
+ sFastTrackMultiplier = (int) ul;
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------
+
#ifdef ADD_BATTERY_DATA
// To collect the amplifier usage
static void addBatteryData(uint32_t params) {
@@ -539,30 +564,30 @@ void AudioFlinger::ThreadBase::dumpBase(int fd, const Vector<String16>& args __u
bool locked = AudioFlinger::dumpTryLock(mLock);
if (!locked) {
- fdprintf(fd, "thread %p maybe dead locked\n", this);
+ dprintf(fd, "thread %p maybe dead locked\n", this);
}
- fdprintf(fd, " I/O handle: %d\n", mId);
- fdprintf(fd, " TID: %d\n", getTid());
- fdprintf(fd, " Standby: %s\n", mStandby ? "yes" : "no");
- fdprintf(fd, " Sample rate: %u\n", mSampleRate);
- fdprintf(fd, " HAL frame count: %zu\n", mFrameCount);
- fdprintf(fd, " HAL buffer size: %u bytes\n", mBufferSize);
- fdprintf(fd, " Channel Count: %u\n", mChannelCount);
- fdprintf(fd, " Channel Mask: 0x%08x (%s)\n", mChannelMask,
+ dprintf(fd, " I/O handle: %d\n", mId);
+ dprintf(fd, " TID: %d\n", getTid());
+ dprintf(fd, " Standby: %s\n", mStandby ? "yes" : "no");
+ dprintf(fd, " Sample rate: %u\n", mSampleRate);
+ dprintf(fd, " HAL frame count: %zu\n", mFrameCount);
+ dprintf(fd, " HAL buffer size: %u bytes\n", mBufferSize);
+ dprintf(fd, " Channel Count: %u\n", mChannelCount);
+ dprintf(fd, " Channel Mask: 0x%08x (%s)\n", mChannelMask,
channelMaskToString(mChannelMask, mType != RECORD).string());
- fdprintf(fd, " Format: 0x%x (%s)\n", mFormat, formatToString(mFormat));
- fdprintf(fd, " Frame size: %zu\n", mFrameSize);
- fdprintf(fd, " Pending config events:");
+ dprintf(fd, " Format: 0x%x (%s)\n", mFormat, formatToString(mFormat));
+ dprintf(fd, " Frame size: %zu\n", mFrameSize);
+ dprintf(fd, " Pending config events:");
size_t numConfig = mConfigEvents.size();
if (numConfig) {
for (size_t i = 0; i < numConfig; i++) {
mConfigEvents[i]->dump(buffer, SIZE);
- fdprintf(fd, "\n %s", buffer);
+ dprintf(fd, "\n %s", buffer);
}
- fdprintf(fd, "\n");
+ dprintf(fd, "\n");
} else {
- fdprintf(fd, " none\n");
+ dprintf(fd, " none\n");
}
if (locked) {
@@ -1225,15 +1250,15 @@ void AudioFlinger::PlaybackThread::dumpTracks(int fd, const Vector<String16>& ar
// These values are "raw"; they will wrap around. See prepareTracks_l() for a better way.
FastTrackUnderruns underruns = getFastTrackUnderruns(0);
- fdprintf(fd, " Normal mixer raw underrun counters: partial=%u empty=%u\n",
+ dprintf(fd, " Normal mixer raw underrun counters: partial=%u empty=%u\n",
underruns.mBitFields.mPartial, underruns.mBitFields.mEmpty);
size_t numtracks = mTracks.size();
size_t numactive = mActiveTracks.size();
- fdprintf(fd, " %d Tracks", numtracks);
+ dprintf(fd, " %d Tracks", numtracks);
size_t numactiveseen = 0;
if (numtracks) {
- fdprintf(fd, " of which %d are active\n", numactive);
+ dprintf(fd, " of which %d are active\n", numactive);
Track::appendDumpHeader(result);
for (size_t i = 0; i < numtracks; ++i) {
sp<Track> track = mTracks[i];
@@ -1265,22 +1290,21 @@ void AudioFlinger::PlaybackThread::dumpTracks(int fd, const Vector<String16>& ar
}
write(fd, result.string(), result.size());
-
}
void AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String16>& args)
{
- fdprintf(fd, "\nOutput thread %p:\n", this);
- fdprintf(fd, " Normal frame count: %zu\n", mNormalFrameCount);
- fdprintf(fd, " Last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime));
- fdprintf(fd, " Total writes: %d\n", mNumWrites);
- fdprintf(fd, " Delayed writes: %d\n", mNumDelayedWrites);
- fdprintf(fd, " Blocked in write: %s\n", mInWrite ? "yes" : "no");
- fdprintf(fd, " Suspend count: %d\n", mSuspended);
- fdprintf(fd, " Sink buffer : %p\n", mSinkBuffer);
- fdprintf(fd, " Mixer buffer: %p\n", mMixerBuffer);
- fdprintf(fd, " Effect buffer: %p\n", mEffectBuffer);
- fdprintf(fd, " Fast track availMask=%#x\n", mFastTrackAvailMask);
+ dprintf(fd, "\nOutput thread %p:\n", this);
+ dprintf(fd, " Normal frame count: %zu\n", mNormalFrameCount);
+ dprintf(fd, " Last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime));
+ dprintf(fd, " Total writes: %d\n", mNumWrites);
+ dprintf(fd, " Delayed writes: %d\n", mNumDelayedWrites);
+ dprintf(fd, " Blocked in write: %s\n", mInWrite ? "yes" : "no");
+ dprintf(fd, " Suspend count: %d\n", mSuspended);
+ dprintf(fd, " Sink buffer : %p\n", mSinkBuffer);
+ dprintf(fd, " Mixer buffer: %p\n", mMixerBuffer);
+ dprintf(fd, " Effect buffer: %p\n", mEffectBuffer);
+ dprintf(fd, " Fast track availMask=%#x\n", mFastTrackAvailMask);
dumpBase(fd, args);
}
@@ -1356,7 +1380,12 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrac
) {
// if frameCount not specified, then it defaults to fast mixer (HAL) frame count
if (frameCount == 0) {
- frameCount = mFrameCount * kFastTrackMultiplier;
+ // read the fast track multiplier property the first time it is needed
+ int ok = pthread_once(&sFastTrackMultiplierOnce, sFastTrackMultiplierInit);
+ if (ok != 0) {
+ ALOGE("%s pthread_once failed: %d", __func__, ok);
+ }
+ frameCount = mFrameCount * sFastTrackMultiplier;
}
ALOGV("AUDIO_OUTPUT_FLAG_FAST accepted: frameCount=%d mFrameCount=%d",
frameCount, mFrameCount);
@@ -2758,6 +2787,8 @@ AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, Aud
// wrap the source side of the MonoPipe to make it an AudioBufferProvider
fastTrack->mBufferProvider = new SourceAudioBufferProvider(new MonoPipeReader(monoPipe));
fastTrack->mVolumeProvider = NULL;
+ fastTrack->mChannelMask = mChannelMask; // mPipeSink channel mask for audio to FastMixer
+ fastTrack->mFormat = mFormat; // mPipeSink format for audio to FastMixer
fastTrack->mGeneration++;
state->mFastTracksGen++;
state->mTrackMask = 1;
@@ -3210,6 +3241,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac
fastTrack->mBufferProvider = eabp;
fastTrack->mVolumeProvider = vp;
fastTrack->mChannelMask = track->mChannelMask;
+ fastTrack->mFormat = track->mFormat;
fastTrack->mGeneration++;
state->mTrackMask |= 1 << j;
didModify = true;
@@ -3601,9 +3633,10 @@ track_is_ready: ;
}
// getTrackName_l() must be called with ThreadBase::mLock held
-int AudioFlinger::MixerThread::getTrackName_l(audio_channel_mask_t channelMask, int sessionId)
+int AudioFlinger::MixerThread::getTrackName_l(audio_channel_mask_t channelMask,
+ audio_format_t format, int sessionId)
{
- return mAudioMixer->getTrackName(channelMask, sessionId);
+ return mAudioMixer->getTrackName(channelMask, format, sessionId);
}
// deleteTrackName_l() must be called with ThreadBase::mLock held
@@ -3716,7 +3749,8 @@ bool AudioFlinger::MixerThread::checkForNewParameter_l(const String8& keyValuePa
delete mAudioMixer;
mAudioMixer = new AudioMixer(mNormalFrameCount, mSampleRate);
for (size_t i = 0; i < mTracks.size() ; i++) {
- int name = getTrackName_l(mTracks[i]->mChannelMask, mTracks[i]->mSessionId);
+ int name = getTrackName_l(mTracks[i]->mChannelMask,
+ mTracks[i]->mFormat, mTracks[i]->mSessionId);
if (name < 0) {
break;
}
@@ -3748,7 +3782,7 @@ void AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>& ar
PlaybackThread::dumpInternals(fd, args);
- fdprintf(fd, " AudioMixer tracks: 0x%08x\n", mAudioMixer->trackNames());
+ dprintf(fd, " AudioMixer tracks: 0x%08x\n", mAudioMixer->trackNames());
// Make a non-atomic copy of fast mixer dump state so it won't change underneath us
const FastMixerDumpState copy(mFastMixerDumpState);
@@ -4007,7 +4041,7 @@ void AudioFlinger::DirectOutputThread::threadLoop_sleepTime()
// getTrackName_l() must be called with ThreadBase::mLock held
int AudioFlinger::DirectOutputThread::getTrackName_l(audio_channel_mask_t channelMask __unused,
- int sessionId __unused)
+ audio_format_t format __unused, int sessionId __unused)
{
return 0;
}
@@ -5203,6 +5237,7 @@ sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createRe
// to be at least 2 x the record thread frame count and cover audio hardware latency.
// This is probably too conservative, but legacy application code may depend on it.
// If you change this calculation, also review the start threshold which is related.
+ // FIXME It's not clear how input latency actually matters. Perhaps this should be 0.
uint32_t latencyMs = 50; // FIXME mInput->stream->get_latency(mInput->stream);
size_t mNormalFrameCount = 2048; // FIXME
uint32_t minBufCount = latencyMs / ((1000 * mNormalFrameCount) / mSampleRate);
@@ -5435,12 +5470,12 @@ void AudioFlinger::RecordThread::dump(int fd, const Vector<String16>& args)
void AudioFlinger::RecordThread::dumpInternals(int fd, const Vector<String16>& args)
{
- fdprintf(fd, "\nInput thread %p:\n", this);
+ dprintf(fd, "\nInput thread %p:\n", this);
if (mActiveTracks.size() > 0) {
- fdprintf(fd, " Buffer size: %zu bytes\n", mBufferSize);
+ dprintf(fd, " Buffer size: %zu bytes\n", mBufferSize);
} else {
- fdprintf(fd, " No active record clients\n");
+ dprintf(fd, " No active record clients\n");
}
dumpBase(fd, args);
@@ -5455,9 +5490,9 @@ void AudioFlinger::RecordThread::dumpTracks(int fd, const Vector<String16>& args
size_t numtracks = mTracks.size();
size_t numactive = mActiveTracks.size();
size_t numactiveseen = 0;
- fdprintf(fd, " %d Tracks", numtracks);
+ dprintf(fd, " %d Tracks", numtracks);
if (numtracks) {
- fdprintf(fd, " of which %d are active\n", numactive);
+ dprintf(fd, " of which %d are active\n", numactive);
RecordTrack::appendDumpHeader(result);
for (size_t i = 0; i < numtracks ; ++i) {
sp<RecordTrack> track = mTracks[i];
@@ -5471,7 +5506,7 @@ void AudioFlinger::RecordThread::dumpTracks(int fd, const Vector<String16>& args
}
}
} else {
- fdprintf(fd, "\n");
+ dprintf(fd, "\n");
}
if (numactiveseen != numactive) {
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index f8037c6..8c9943c 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -356,6 +356,8 @@ public:
// If a thread does not have such a heap, this method returns 0.
virtual sp<MemoryDealer> readOnlyHeap() const { return 0; }
+ virtual sp<IMemory> pipeMemory() const { return 0; }
+
mutable Mutex mLock;
protected:
@@ -674,7 +676,8 @@ protected:
// Allocate a track name for a given channel mask.
// Returns name >= 0 if successful, -1 on failure.
- virtual int getTrackName_l(audio_channel_mask_t channelMask, int sessionId) = 0;
+ virtual int getTrackName_l(audio_channel_mask_t channelMask,
+ audio_format_t format, int sessionId) = 0;
virtual void deleteTrackName_l(int name) = 0;
// Time to sleep between cycles when:
@@ -831,7 +834,8 @@ public:
protected:
virtual mixer_state prepareTracks_l(Vector< sp<Track> > *tracksToRemove);
- virtual int getTrackName_l(audio_channel_mask_t channelMask, int sessionId);
+ virtual int getTrackName_l(audio_channel_mask_t channelMask,
+ audio_format_t format, int sessionId);
virtual void deleteTrackName_l(int name);
virtual uint32_t idleSleepTimeUs() const;
virtual uint32_t suspendSleepTimeUs() const;
@@ -884,7 +888,8 @@ public:
status_t& status);
protected:
- virtual int getTrackName_l(audio_channel_mask_t channelMask, int sessionId);
+ virtual int getTrackName_l(audio_channel_mask_t channelMask,
+ audio_format_t format, int sessionId);
virtual void deleteTrackName_l(int name);
virtual uint32_t activeSleepTimeUs() const;
virtual uint32_t idleSleepTimeUs() const;
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index 5f13be3..4cba3fd 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -39,6 +39,13 @@ public:
STARTING_2, // for RecordTrack only
};
+ // where to allocate the data buffer
+ enum alloc_type {
+ ALLOC_CBLK, // allocate immediately after control block
+ ALLOC_READONLY, // allocate from a separate read-only heap per thread
+ ALLOC_PIPE, // do not allocate; use the pipe buffer
+ };
+
TrackBase(ThreadBase *thread,
const sp<Client>& client,
uint32_t sampleRate,
@@ -50,7 +57,7 @@ public:
int uid,
IAudioFlinger::track_flags_t flags,
bool isOut,
- bool useReadOnlyHeap = false);
+ alloc_type alloc = ALLOC_CBLK);
virtual ~TrackBase();
virtual status_t initCheck() const { return getCblk() != 0 ? NO_ERROR : NO_MEMORY; }
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index f698fa2..7ddc71c 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -73,7 +73,7 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase(
int clientUid,
IAudioFlinger::track_flags_t flags,
bool isOut,
- bool useReadOnlyHeap)
+ alloc_type alloc)
: RefBase(),
mThread(thread),
mClient(client),
@@ -117,7 +117,7 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase(
// ALOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize);
size_t size = sizeof(audio_track_cblk_t);
size_t bufferSize = (sharedBuffer == 0 ? roundup(frameCount) : frameCount) * mFrameSize;
- if (sharedBuffer == 0 && !useReadOnlyHeap) {
+ if (sharedBuffer == 0 && alloc == ALLOC_CBLK) {
size += bufferSize;
}
@@ -139,7 +139,8 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase(
// construct the shared structure in-place.
if (mCblk != NULL) {
new(mCblk) audio_track_cblk_t();
- if (useReadOnlyHeap) {
+ switch (alloc) {
+ case ALLOC_READONLY: {
const sp<MemoryDealer> roHeap(thread->readOnlyHeap());
if (roHeap == 0 ||
(mBufferMemory = roHeap->allocate(bufferSize)) == 0 ||
@@ -153,7 +154,17 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase(
return;
}
memset(mBuffer, 0, bufferSize);
- } else {
+ } break;
+ case ALLOC_PIPE:
+ mBufferMemory = thread->pipeMemory();
+ // mBuffer is the virtual address as seen from current process (mediaserver),
+ // and should normally be coming from mBufferMemory->pointer().
+ // However in this case the TrackBase does not reference the buffer directly.
+ // It should references the buffer via the pipe.
+ // Therefore, to detect incorrect usage of the buffer, we set mBuffer to NULL.
+ mBuffer = NULL;
+ break;
+ case ALLOC_CBLK:
// clear all buffers
if (sharedBuffer == 0) {
mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
@@ -164,6 +175,7 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase(
mCblk->mFlags = CBLK_FORCEREADY; // FIXME hack, need to fix the track ready logic
#endif
}
+ break;
}
#ifdef TEE_SINK
@@ -385,7 +397,7 @@ AudioFlinger::PlaybackThread::Track::Track(
}
mServerProxy = mAudioTrackServerProxy;
- mName = thread->getTrackName_l(channelMask, sessionId);
+ mName = thread->getTrackName_l(channelMask, format, sessionId);
if (mName < 0) {
ALOGE("no more track names available");
return;
@@ -1842,7 +1854,7 @@ AudioFlinger::RecordThread::RecordTrack::RecordTrack(
: TrackBase(thread, client, sampleRate, format,
channelMask, frameCount, 0 /*sharedBuffer*/, sessionId, uid,
flags, false /*isOut*/,
- (flags & IAudioFlinger::TRACK_FAST) != 0 /*useReadOnlyHeap*/),
+ (flags & IAudioFlinger::TRACK_FAST) != 0 ? ALLOC_READONLY : ALLOC_CBLK),
mOverflow(false), mResampler(NULL), mRsmpOutBuffer(NULL), mRsmpOutFrameCount(0),
// See real initialization of mRsmpInFront at RecordThread::start()
mRsmpInUnrel(0), mRsmpInFront(0), mFramesToDrop(0), mResamplerBufferProvider(NULL)
diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp
index b047e1d..db0f57d 100644
--- a/services/audiopolicy/AudioPolicyManager.cpp
+++ b/services/audiopolicy/AudioPolicyManager.cpp
@@ -100,6 +100,7 @@ const StringToEnum sDeviceNameToEnumTable[] = {
STRING_TO_ENUM(AUDIO_DEVICE_IN_TV_TUNER),
STRING_TO_ENUM(AUDIO_DEVICE_IN_LINE),
STRING_TO_ENUM(AUDIO_DEVICE_IN_SPDIF),
+ STRING_TO_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_A2DP),
};
const StringToEnum sFlagNameToEnumTable[] = {
@@ -3164,6 +3165,12 @@ audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t input
case AUDIO_SOURCE_DEFAULT:
case AUDIO_SOURCE_MIC:
+ if (availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) {
+ device = AUDIO_DEVICE_IN_BLUETOOTH_A2DP;
+ break;
+ }
+ // FALL THROUGH
+
case AUDIO_SOURCE_VOICE_RECOGNITION:
case AUDIO_SOURCE_HOTWORD:
case AUDIO_SOURCE_VOICE_COMMUNICATION:
diff --git a/services/camera/libcameraservice/utils/CameraTraces.cpp b/services/camera/libcameraservice/utils/CameraTraces.cpp
index 346e15f..374dc5e 100644
--- a/services/camera/libcameraservice/utils/CameraTraces.cpp
+++ b/services/camera/libcameraservice/utils/CameraTraces.cpp
@@ -74,10 +74,10 @@ status_t CameraTraces::dump(int fd, const Vector<String16> &args __attribute__((
return BAD_VALUE;
}
- fdprintf(fd, "Camera traces (%zu):\n", pcsList.size());
+ dprintf(fd, "Camera traces (%zu):\n", pcsList.size());
if (pcsList.empty()) {
- fdprintf(fd, " No camera traces collected.\n");
+ dprintf(fd, " No camera traces collected.\n");
}
// Print newest items first
diff --git a/services/medialog/MediaLogService.cpp b/services/medialog/MediaLogService.cpp
index 0c7fbbd..41dab1f 100644
--- a/services/medialog/MediaLogService.cpp
+++ b/services/medialog/MediaLogService.cpp
@@ -60,7 +60,7 @@ status_t MediaLogService::dump(int fd, const Vector<String16>& args __unused)
static const String16 sDump("android.permission.DUMP");
if (!(IPCThreadState::self()->getCallingUid() == AID_MEDIA ||
PermissionCache::checkCallingPermission(sDump))) {
- fdprintf(fd, "Permission Denial: can't dump media.log from pid=%d, uid=%d\n",
+ dprintf(fd, "Permission Denial: can't dump media.log from pid=%d, uid=%d\n",
IPCThreadState::self()->getCallingPid(),
IPCThreadState::self()->getCallingUid());
return NO_ERROR;
@@ -74,7 +74,7 @@ status_t MediaLogService::dump(int fd, const Vector<String16>& args __unused)
for (size_t i = 0; i < namedReaders.size(); i++) {
const NamedReader& namedReader = namedReaders[i];
if (fd >= 0) {
- fdprintf(fd, "\n%s:\n", namedReader.name());
+ dprintf(fd, "\n%s:\n", namedReader.name());
} else {
ALOGI("%s:", namedReader.name());
}