summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMingming Yin <mingming@codeaurora.org>2013-01-10 18:42:38 -0800
committerSteve Kondik <shade@chemlab.org>2013-02-06 00:31:01 -0800
commit12170a107e7c96170a38dbe43e98447c87624bd7 (patch)
tree1f93126eab9e0cace115ad89dbba41594defca7b
parent4b47852b1b4de2f87ec1c1d7b44b41821a19eb35 (diff)
downloadframeworks_av-12170a107e7c96170a38dbe43e98447c87624bd7.zip
frameworks_av-12170a107e7c96170a38dbe43e98447c87624bd7.tar.gz
frameworks_av-12170a107e7c96170a38dbe43e98447c87624bd7.tar.bz2
Squashed commit of updates from CodeAurora
auido: Add amr-wb+ codec to ACodec. -Add an entry for amr-wb+ decoder in ACodec. -amr-wb+ non tunnel will be enabled by default. Change-Id: Ied8902eb83da29a3164eb99e88630570a43f681e libstagefright: Create MP3 decoder libraries without OMX layer - With the current MP3 OMX SW decoders, the decoding time is increased w.r.t the libraries without OMX layer that are present in GB. This increase in decoding time results reduction in power savings in LPA mode. - This commit is to remove OMX layer for MP3 to reduce the power consumption in LPA mode Change-Id: I835ab6d013a326f111e513586f884bacd5f7106a audioflinger: EffectModules are updated with device change Issue: Effects modules are not updated with the device change information Fix: 1) Add setDevice information to mLPAEffectChain 2) Remove the return after sending the device route information to Direct track so that mixer thread is also aware of the device change for EffectsChain Change-Id: I82936cd47290946a5e4772e448669d81e0e4d6f5 libmedia : Add a NULL pointer check - Print frame count in AudioTrack::dump() only if the control block is valid Change-Id: Icf594eb721b48795c43d7bd165f6086031ce6efd CRs-Fixed: 435050 libstagefright: Query AudioSystem for suggested record mute duration - AudioSource mutes a pre-defined duration (defined by kAutoRampStartUs) at the beginning of a recording. - Instead, query the audio system for any ongoing playback streams and use its output latency to calculate the duration to mute the incoming PCM stream. - This assumes all current playback threads will be paused once recording is started. Change-Id: Ie9b1d62e7be803ef1d8a59127b95c73e03fa5ce6 CRs-Fixed: 438149 libstagefright: Convert mono to stereo for LPA clips - Sound effects are not supported for mono clips - Repetative calling of effects_configure and effect_process for mono clips is resulting in crash in the sound effects library. - So, Mono clips are now converted to stereo by copying the left sample to right. - This is same as what Resampler does in Non-LPA Playback. This commit is a port of fcc0647fab20ceaf1c07bc10bb243f14c48b114c CRs-Fixed: 421639 Change-Id: Ie579c8d11afe3db8d42a35956e8bf23eeb88cfe6 audioflinger: Fix to set volume from MediaPlayer in Tunnel mode Issue: MediaPlayer.setVolume does not have effect on Playback volume in TunnelPlayer mode Fix: the left and right volume parameters of setVolume are hardcoded and defaulted in DirectAudioTrack. Updating the parameters from the input arguments fixes the issue Change-Id: I8a107ce57284b225b17d95fed0f69e3adc5fb131 CRs-Fixed: 441849 libstagefright: Enable Tunnel Decode for select formats - Enable tunnel mode decode only if the audio mime type matches a supported list. Change-Id: I32afd83e5fda1e90cb671dd747f17cb83bb84fc1 CRs-Fixed:437651 framework/av:: Add support to decode mp3 data in mp4 container - Added support to decode mp3 data in mp4 container packed as mp4a atom and .mp3 atom as well. Port of 8fa3774adf9259b33ee721cfaeff26da42c29928 Change-Id: I1a04022f30a9f6516575440aba7652986ab7dc58 CRs-Fixed: 439897 audiomixer: Use High Quality resampler Use very high quality resampler to upsample to 48KHz sample rate. Change-Id: I1ba5b839f1e74ae71b405538d970e6a966bd1d47 CRs-fixed: 416730 audioflinger: Fix a deadlock - A deadlock will happen if the obit recipient registered by the DirectAudioTrack is called. - Fix this by moving the lock acquisition in DirectAudioTrack::clearPowerManager() to after DirectAudioTrack::releaseWakeLock() is called. - Also synchronize use of mPowerManager in the DirectAudioTrack destructor with DirectAudioTrack::clearPowerManager() Change-Id: Ib127db1406c4a61a4054ca0cf30f4c7347a5c92a CRs-Fixed: 444093 libstagefright: TunnelPlayer: update condition to send SEEK_COMPLETE - If the client tries to seek to 0 (e.g as a result of LOOPING) without ever calling getPosition(), we will always sent an immediate seek notification without seeking. Change-Id: Id2b9d00c611278d0521cb6fd402710f0ec37bbdd CRs-Fixed: 441411 libstagefright: Remove unnecessary code from TunnelPlayer - TunnelPlayer tries to mimick AudioPlayer when trying to delete the extractor source. - It is needed for AudioPlayer as the OMXCodec object is referenced by the CallbackDispatcher as well as AudioPlayer. - This condition is not true for TunnelPlayer, so why do it. Change-Id: I79c4e17d01910e73ad01c5640ef374626313a18e CRs-Fixed: 442365 Add MediaDebug header from CAF Change-Id: I68dbe72f86a49685b82b64927d1aa80231647a7a
-rw-r--r--include/media/stagefright/AudioSource.h1
-rwxr-xr-xinclude/media/stagefright/LPAPlayer.h5
-rw-r--r--include/media/stagefright/MediaDebug.h40
-rw-r--r--media/libmedia/AudioRecord.cpp7
-rw-r--r--media/libmedia/AudioTrack.cpp15
-rw-r--r--media/libstagefright/ACodec.cpp4
-rwxr-xr-xmedia/libstagefright/Android.mk2
-rw-r--r--media/libstagefright/AudioSource.cpp17
-rw-r--r--media/libstagefright/AwesomePlayer.cpp60
-rw-r--r--media/libstagefright/LPAPlayerALSA.cpp68
-rw-r--r--media/libstagefright/MPEG4Extractor.cpp15
-rw-r--r--media/libstagefright/MediaExtractor.cpp9
-rw-r--r--media/libstagefright/OMXCodec.cpp56
-rw-r--r--media/libstagefright/TunnelPlayer.cpp17
-rw-r--r--media/libstagefright/codecs/mp3dec/Android.mk61
-rw-r--r--media/libstagefright/codecs/mp3dec/MP3Decoder.cpp586
-rw-r--r--media/libstagefright/include/AwesomePlayer.h2
-rw-r--r--media/libstagefright/include/MP3Decoder.h70
-rw-r--r--services/audioflinger/Android.mk4
-rw-r--r--services/audioflinger/AudioFlinger.cpp25
-rw-r--r--services/audioflinger/AudioMixer.cpp4
21 files changed, 988 insertions, 80 deletions
diff --git a/include/media/stagefright/AudioSource.h b/include/media/stagefright/AudioSource.h
index 99f3c3b..4489254 100644
--- a/include/media/stagefright/AudioSource.h
+++ b/include/media/stagefright/AudioSource.h
@@ -85,6 +85,7 @@ private:
int64_t mInitialReadTimeUs;
int64_t mNumFramesReceived;
int64_t mNumClientOwnedBuffers;
+ int64_t mAutoRampStartUs;
List<MediaBuffer * > mBuffersReceived;
diff --git a/include/media/stagefright/LPAPlayer.h b/include/media/stagefright/LPAPlayer.h
index b0e1d31..c3c5cac 100755
--- a/include/media/stagefright/LPAPlayer.h
+++ b/include/media/stagefright/LPAPlayer.h
@@ -92,7 +92,8 @@ private:
bool mPaused;
bool mA2DPEnabled;
int32_t mChannelMask;
- int32_t numChannels;
+ int32_t mNumOutputChannels;
+ int32_t mNumInputChannels;
int32_t mSampleRate;
int64_t mLatencyUs;
size_t mFrameSize;
@@ -259,6 +260,8 @@ private:
void *buffer, size_t size, void *cookie);
size_t AudioCallback(void *cookie, void *data, size_t size);
+ void convertMonoToStereo(int16_t *data, size_t size);
+
LPAPlayer(const LPAPlayer &);
LPAPlayer &operator=(const LPAPlayer &);
};
diff --git a/include/media/stagefright/MediaDebug.h b/include/media/stagefright/MediaDebug.h
new file mode 100644
index 0000000..bcaeeba
--- /dev/null
+++ b/include/media/stagefright/MediaDebug.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MEDIA_DEBUG_H_
+
+#define MEDIA_DEBUG_H_
+
+#include <cutils/log.h>
+
+#define LITERAL_TO_STRING_INTERNAL(x) #x
+#define LITERAL_TO_STRING(x) LITERAL_TO_STRING_INTERNAL(x)
+
+#define CHECK_EQ(x,y) \
+ LOG_ALWAYS_FATAL_IF( \
+ (x) != (y), \
+ __FILE__ ":" LITERAL_TO_STRING(__LINE__) " " #x " != " #y)
+
+#define CHECK(x) \
+ LOG_ALWAYS_FATAL_IF( \
+ !(x), \
+ __FILE__ ":" LITERAL_TO_STRING(__LINE__) " " #x)
+
+#endif // MEDIA_DEBUG_H_
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index ce03754..2725b5b 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -63,7 +63,12 @@ status_t AudioRecord::getMinFrameCount(
// We double the size of input buffer for ping pong use of record buffer.
size <<= 1;
- if (audio_is_linear_pcm(format)) {
+#ifdef QCOM_ENHANCED_AUDIO
+ if (audio_is_linear_pcm(format) || format == AUDIO_FORMAT_AMR_WB)
+#else
+ if (audio_is_linear_pcm(format))
+#endif
+ {
int channelCount = popcount(channelMask);
size /= channelCount * audio_bytes_per_sample(format);
}
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index a2172c9..36b1469 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -96,7 +96,8 @@ status_t AudioTrack::getMinFrameCount(
// ---------------------------------------------------------------------------
AudioTrack::AudioTrack()
- : mStatus(NO_INIT),
+ : mCblk(NULL),
+ mStatus(NO_INIT),
mIsTimed(false),
mPreviousPriority(ANDROID_PRIORITY_NORMAL),
mPreviousSchedulingGroup(SP_DEFAULT)
@@ -118,7 +119,8 @@ AudioTrack::AudioTrack(
void* user,
int notificationFrames,
int sessionId)
- : mStatus(NO_INIT),
+ : mCblk(NULL),
+ mStatus(NO_INIT),
mIsTimed(false),
mPreviousPriority(ANDROID_PRIORITY_NORMAL),
mPreviousSchedulingGroup(SP_DEFAULT)
@@ -144,7 +146,8 @@ AudioTrack::AudioTrack(
void* user,
int notificationFrames,
int sessionId)
- : mStatus(NO_INIT),
+ : mCblk(NULL),
+ mStatus(NO_INIT),
mIsTimed(false),
mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT)
#ifdef QCOM_HARDWARE
@@ -169,7 +172,8 @@ AudioTrack::AudioTrack(
void* user,
int notificationFrames,
int sessionId)
- : mStatus(NO_INIT),
+ : mCblk(NULL),
+ mStatus(NO_INIT),
mIsTimed(false),
mPreviousPriority(ANDROID_PRIORITY_NORMAL),
mPreviousSchedulingGroup(SP_DEFAULT)
@@ -1599,7 +1603,8 @@ status_t AudioTrack::dump(int fd, const Vector<String16>& args) const
result.append(" AudioTrack::dump\n");
snprintf(buffer, 255, " stream type(%d), left - right volume(%f, %f)\n", mStreamType, mVolume[0], mVolume[1]);
result.append(buffer);
- snprintf(buffer, 255, " format(%d), channel count(%d), frame count(%d)\n", mFormat, mChannelCount, mCblk->frameCount);
+ snprintf(buffer, 255, " format(%d), channel count(%d), frame count(%d)\n", mFormat, mChannelCount,
+ (mCblk == 0) ? 0 : mCblk->frameCount);
result.append(buffer);
snprintf(buffer, 255, " sample rate(%d), status(%d), muted(%d)\n", (mCblk == 0) ? 0 : mCblk->sampleRate, mStatus, mMuted);
result.append(buffer);
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 1f4038c..e86bf63 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -820,6 +820,10 @@ status_t ACodec::setComponentRole(
"audio_decoder.amrnb", "audio_encoder.amrnb" },
{ MEDIA_MIMETYPE_AUDIO_AMR_WB,
"audio_decoder.amrwb", "audio_encoder.amrwb" },
+#ifdef QCOM_ENHANCED_AUDIO
+ { MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS,
+ "audio_decoder.amrwbplus", "audio_encoder.amrwbplus" },
+#endif
{ MEDIA_MIMETYPE_AUDIO_AAC,
"audio_decoder.aac", "audio_encoder.aac" },
{ MEDIA_MIMETYPE_AUDIO_VORBIS,
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index eb89cfe..ea64cc8 100755
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -4,6 +4,7 @@ include $(CLEAR_VARS)
ifeq ($(BOARD_USES_ALSA_AUDIO),true)
ifeq ($(call is-chipset-in-board-platform,msm8960),true)
LOCAL_CFLAGS += -DUSE_TUNNEL_MODE
+ LOCAL_CFLAGS += -DTUNNEL_MODE_SUPPORTS_AMRWB
endif
endif
@@ -132,6 +133,7 @@ LOCAL_SHARED_LIBRARIES := \
LOCAL_STATIC_LIBRARIES := \
libstagefright_color_conversion \
+ libstagefright_mp3dec \
libstagefright_aacenc \
libstagefright_matroska \
libstagefright_timedtext \
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index 8e3811b..bb2d415 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -83,6 +83,17 @@ AudioSource::AudioSource(
this,
frameCount);
mInitCheck = mRecord->initCheck();
+
+ //configure the auto ramp start duration
+ mAutoRampStartUs = kAutoRampStartUs;
+ uint32_t playbackLatencyMs = 0;
+ if (AudioSystem::getOutputLatency(&playbackLatencyMs,
+ AUDIO_STREAM_DEFAULT) == OK) {
+ if (2*playbackLatencyMs*1000LL > kAutoRampStartUs) {
+ mAutoRampStartUs = 2*playbackLatencyMs*1000LL;
+ }
+ }
+ ALOGD("Start autoramp from %lld", mAutoRampStartUs);
} else {
mInitCheck = status;
}
@@ -238,14 +249,14 @@ status_t AudioSource::read(
int64_t timeUs;
CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
int64_t elapsedTimeUs = timeUs - mStartTimeUs;
- if (elapsedTimeUs < kAutoRampStartUs) {
+ if (elapsedTimeUs < mAutoRampStartUs) {
memset((uint8_t *) buffer->data(), 0, buffer->range_length());
- } else if (elapsedTimeUs < kAutoRampStartUs + kAutoRampDurationUs) {
+ } else if (elapsedTimeUs < mAutoRampStartUs + kAutoRampDurationUs) {
int32_t autoRampDurationFrames =
(kAutoRampDurationUs * mSampleRate + 500000LL) / 1000000LL;
int32_t autoRampStartFrames =
- (kAutoRampStartUs * mSampleRate + 500000LL) / 1000000LL;
+ (mAutoRampStartUs * mSampleRate + 500000LL) / 1000000LL;
int32_t nFrames = mNumFramesReceived - autoRampStartFrames;
rampVolume(nFrames, autoRampDurationFrames,
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 97ee08a..4b14baa 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -1544,26 +1544,26 @@ status_t AwesomePlayer::initAudioDecoder() {
nchannels);
#ifdef USE_TUNNEL_MODE
- char value[PROPERTY_VALUE_MAX];
- char tunnelDecode[128];
+ char tunnelDecode[PROPERTY_VALUE_MAX];
property_get("tunnel.decode",tunnelDecode,"0");
// Enable tunnel mode for mp3 and aac and if the clip is not aac adif
// and if no other tunnel mode instances aare running.
ALOGD("Tunnel Mime Type: %s, object alive = %d, mTunnelAliveAP = %d",\
mime, (TunnelPlayer::mTunnelObjectsAlive), mTunnelAliveAP);
- if(((strcmp("true",tunnelDecode) == 0)||(atoi(tunnelDecode))) &&
- (TunnelPlayer::mTunnelObjectsAlive == 0) &&
- //widevine will fallback to software decoder
- mTunnelAliveAP == 0 && (isADTS == 0) && mAudioSink->realtime() &&
- ((!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) ||
- (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) ||
- (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS)) ||
- (!strcasecmp(mime,MEDIA_MIMETYPE_AUDIO_AAC)))) {
-
- if(mVideoSource != NULL) {
- char tunnelAVDecode[128];
+
+ bool sys_prop_enabled = !strcmp("true",tunnelDecode) || atoi(tunnelDecode);
+
+ //widevine will fallback to software decoder
+ if (sys_prop_enabled && (TunnelPlayer::mTunnelObjectsAlive == 0) &&
+ mTunnelAliveAP == 0 && (isADTS == 0) &&
+ mAudioSink->realtime() &&
+ inSupportedTunnelFormats(mime)) {
+
+ if (mVideoSource != NULL) {
+ char tunnelAVDecode[PROPERTY_VALUE_MAX];
property_get("tunnel.audiovideo.decode",tunnelAVDecode,"0");
- if(((strncmp("true", tunnelAVDecode, 4) == 0)||(atoi(tunnelAVDecode)))) {
+ sys_prop_enabled = !strncmp("true", tunnelAVDecode, 4) || atoi(tunnelAVDecode);
+ if (sys_prop_enabled) {
ALOGD("Enable Tunnel Mode for A-V playback");
mIsTunnelAudio = true;
}
@@ -3027,4 +3027,36 @@ inline int64_t AwesomePlayer::getTimeOfDayUs() {
return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec;
}
+
+#ifdef USE_TUNNEL_MODE
+bool AwesomePlayer::inSupportedTunnelFormats(const char * mime) {
+ const char * tunnelFormats [ ] = {
+ MEDIA_MIMETYPE_AUDIO_MPEG,
+ MEDIA_MIMETYPE_AUDIO_AAC,
+#ifdef TUNNEL_MODE_SUPPORTS_AMRWB
+ MEDIA_MIMETYPE_AUDIO_AMR_WB,
+ MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS
+#endif
+ };
+
+ if (!mime) {
+ return false;
+ }
+
+ size_t len = sizeof(tunnelFormats)/sizeof(const char *);
+ for (size_t i = 0; i < len; i++) {
+ const char * tf = tunnelFormats[i];
+ if (!strncasecmp(mime, tf, strlen(tf))) {
+ if (strlen(mime) == strlen(tf)) { //to prevent a substring match
+ ALOGD("Tunnel playback supported for %s", tf);
+ return true;
+ }
+ }
+ }
+
+ ALOGW("Tunnel playback unsupported for %s", mime);
+ return false;
+}
+#endif
+
} // namespace android
diff --git a/media/libstagefright/LPAPlayerALSA.cpp b/media/libstagefright/LPAPlayerALSA.cpp
index 38d6bac..18aae8f 100644
--- a/media/libstagefright/LPAPlayerALSA.cpp
+++ b/media/libstagefright/LPAPlayerALSA.cpp
@@ -87,7 +87,8 @@ mAudioSink(audioSink),
mObserver(observer) {
ALOGV("LPAPlayer::LPAPlayer() ctor");
objectsAlive++;
- numChannels =0;
+ mNumOutputChannels =0;
+ mNumInputChannels = 0;
mPaused = false;
mIsA2DPEnabled = false;
mAudioFlinger = NULL;
@@ -256,20 +257,24 @@ status_t LPAPlayer::start(bool sourceAlreadyStarted) {
success = format->findInt32(kKeySampleRate, &mSampleRate);
CHECK(success);
- success = format->findInt32(kKeyChannelCount, &numChannels);
+ success = format->findInt32(kKeyChannelCount, &mNumInputChannels);
CHECK(success);
+ // Always produce stereo output
+ mNumOutputChannels = 2;
+
if(!format->findInt32(kKeyChannelMask, &mChannelMask)) {
// log only when there's a risk of ambiguity of channel mask selection
- ALOGI_IF(numChannels > 2,
- "source format didn't specify channel mask, using (%d) channel order", numChannels);
+ ALOGI_IF(mNumInputChannels > 2,
+ "source format didn't specify channel mask, using (%d) channel order", mNumInputChannels);
mChannelMask = CHANNEL_MASK_USE_CHANNEL_ORDER;
}
audio_output_flags_t flags = (audio_output_flags_t) (AUDIO_OUTPUT_FLAG_LPA |
AUDIO_OUTPUT_FLAG_DIRECT);
- ALOGV("mAudiosink->open() mSampleRate %d, numChannels %d, mChannelMask %d, flags %d",mSampleRate, numChannels, mChannelMask, flags);
+ ALOGV("mAudiosink->open() mSampleRate %d, numOutputChannels %d, mChannelMask %d, flags %d",mSampleRate,
+ mNumOutputChannels, mChannelMask, flags);
err = mAudioSink->open(
- mSampleRate, numChannels, mChannelMask, AUDIO_FORMAT_PCM_16_BIT,
+ mSampleRate, mNumOutputChannels, mChannelMask, AUDIO_FORMAT_PCM_16_BIT,
DEFAULT_AUDIOSINK_BUFFERCOUNT,
&LPAPlayer::AudioSinkCallback,
this,
@@ -372,7 +377,7 @@ void LPAPlayer::resume() {
audio_output_flags_t flags = (audio_output_flags_t) (AUDIO_OUTPUT_FLAG_LPA |
AUDIO_OUTPUT_FLAG_DIRECT);
status_t err = mAudioSink->open(
- mSampleRate, numChannels, mChannelMask, AUDIO_FORMAT_PCM_16_BIT,
+ mSampleRate, mNumOutputChannels, mChannelMask, AUDIO_FORMAT_PCM_16_BIT,
DEFAULT_AUDIOSINK_BUFFERCOUNT,
&LPAPlayer::AudioSinkCallback,
this,
@@ -491,6 +496,12 @@ void LPAPlayer::decoderThreadEntry() {
}
void* local_buf = malloc(MEM_BUFFER_SIZE);
int bytesWritten = 0;
+
+ if (!local_buf) {
+ ALOGE("Failed to allocate temporary buffer for decoderThread");
+ return;
+ }
+
while (!killDecoderThread) {
if (mReachedEOS || mPaused || !mIsAudioRouted) {
@@ -500,16 +511,27 @@ void LPAPlayer::decoderThreadEntry() {
continue;
}
- if (!mIsA2DPEnabled) {
- ALOGV("FillBuffer: MemBuffer size %d", MEM_BUFFER_SIZE);
- ALOGV("Fillbuffer started");
- //TODO: Add memset
+ if (mIsA2DPEnabled) {
+ //nothing to do
+ continue;
+ }
+
+ ALOGV("FillBuffer: MemBuffer size %d", MEM_BUFFER_SIZE);
+ ALOGV("Fillbuffer started");
+ if (mNumInputChannels == 1) {
+ bytesWritten = fillBuffer(local_buf, MEM_BUFFER_SIZE/2);
+ CHECK(bytesWritten <= MEM_BUFFER_SIZE/2);
+
+ convertMonoToStereo((int16_t*)local_buf, bytesWritten);
+ bytesWritten *= 2;
+ } else {
bytesWritten = fillBuffer(local_buf, MEM_BUFFER_SIZE);
- ALOGV("FillBuffer completed bytesToWrite %d", bytesWritten);
+ CHECK(bytesWritten <= MEM_BUFFER_SIZE);
+ }
- if(!killDecoderThread) {
- mAudioSink->write(local_buf, bytesWritten);
- }
+ ALOGV("FillBuffer completed bytesToWrite %d", bytesWritten);
+ if(!killDecoderThread) {
+ mAudioSink->write(local_buf, bytesWritten);
}
}
@@ -662,7 +684,7 @@ size_t LPAPlayer::fillBuffer(void *data, size_t size) {
size_t copy = size_remaining;
if (copy > mInputBuffer->range_length()) {
copy = mInputBuffer->range_length();
- }
+ } //is size_remaining < range_length impossible?
memcpy((char *)data + size_done,
(const char *)mInputBuffer->data() + mInputBuffer->range_offset(),
@@ -790,4 +812,18 @@ void LPAPlayer::onPauseTimeOut() {
}
+//dup each mono frame
+void LPAPlayer::convertMonoToStereo(int16_t *data, size_t size)
+{
+ int i =0;
+ int16_t *start_pointer = data;
+ int monoFrameCount = (size) / (sizeof(int16_t));
+
+ for (i = monoFrameCount; i > 0 ; i--) {
+ int16_t temp_sample = *(start_pointer + i - 1);
+ *(start_pointer + (i*2) - 1) = temp_sample;
+ *(start_pointer + (i*2) - 2) = temp_sample;
+ }
+}
+
} //namespace android
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 62ba826..488c2a3 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -243,6 +243,9 @@ static const char *FourCC2MIME(uint32_t fourcc) {
case FOURCC('m', 'p', '4', 'a'):
return MEDIA_MIMETYPE_AUDIO_AAC;
+ case FOURCC('.', 'm', 'p', '3'):
+ return MEDIA_MIMETYPE_AUDIO_MPEG;
+
case FOURCC('s', 'a', 'm', 'r'):
return MEDIA_MIMETYPE_AUDIO_AMR_NB;
@@ -1870,12 +1873,12 @@ status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio(
return OK;
}
- if (objectTypeIndication == 0x6b) {
- // The media subtype is MP3 audio
- // Our software MP3 audio decoder may not be able to handle
- // packetized MP3 audio; for now, lets just return ERROR_UNSUPPORTED
- ALOGE("MP3 track in MP4/3GPP file is not supported");
- return ERROR_UNSUPPORTED;
+ if (objectTypeIndication == 0x6b
+ || objectTypeIndication == 0x69) {
+ // This is mpeg1/2 audio content, set mimetype to mpeg
+ mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
+ ALOGD("objectTypeIndication:0x%x, set mimetype to mpeg ",objectTypeIndication);
+ return OK;
}
const uint8_t *csd;
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index 218448b..1eb5c19 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2009 The Android Open Source Project
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -107,13 +108,7 @@ sp<MediaExtractor> MediaExtractor::Create(
ret = new MPEG4Extractor(source);
}
#ifdef QCOM_ENHANCED_AUDIO
- char tunnelDecode[PROPERTY_VALUE_MAX];
- ALOGV("MediaExtractor::Create checking tunnel.decode");
- property_get("tunnel.decode",tunnelDecode,"0");
- if( (strncmp("true",tunnelDecode,4) == 0) || (atoi(tunnelDecode)) ) {
- bCheckExtendedExtractor = true;
- ALOGV("MediaExtractor::Create detected tunnel.decode as true...");
- }
+ bCheckExtendedExtractor = true;
#endif
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
ret = new MP3Extractor(source, meta);
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index e7ba1cc..5988061 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -23,6 +23,7 @@
#include <utils/Log.h>
#include "include/AACEncoder.h"
+#include "include/MP3Decoder.h"
#include "include/ESDS.h"
@@ -97,6 +98,11 @@ const static int64_t kBufferFilledEventTimeOutNs = 3000000000LL;
// component in question is buggy or not.
const static uint32_t kMaxColorFormatSupported = 1000;
+
+#define FACTORY_CREATE(name) \
+static sp<MediaSource> Make##name(const sp<MediaSource> &source) { \
+ return new name(source); \
+}
#define FACTORY_CREATE_ENCODER(name) \
static sp<MediaSource> Make##name(const sp<MediaSource> &source, const sp<MetaData> &meta) { \
return new name(source, meta); \
@@ -104,6 +110,7 @@ static sp<MediaSource> Make##name(const sp<MediaSource> &source, const sp<MetaDa
#define FACTORY_REF(name) { #name, Make##name },
+FACTORY_CREATE(MP3Decoder)
FACTORY_CREATE_ENCODER(AACEncoder)
static sp<MediaSource> InstantiateSoftwareEncoder(
@@ -127,8 +134,29 @@ static sp<MediaSource> InstantiateSoftwareEncoder(
return NULL;
}
+static sp<MediaSource> InstantiateSoftwareDecoder(
+ const char *name, const sp<MediaSource> &source) {
+ struct FactoryInfo {
+ const char *name;
+ sp<MediaSource> (*CreateFunc)(const sp<MediaSource> &);
+ };
+
+ static const FactoryInfo kFactoryInfo[] = {
+ FACTORY_REF(MP3Decoder)
+ };
+ for (size_t i = 0;
+ i < sizeof(kFactoryInfo) / sizeof(kFactoryInfo[0]); ++i) {
+ if (!strcmp(name, kFactoryInfo[i].name)) {
+ return (*kFactoryInfo[i].CreateFunc)(source);
+ }
+ }
+
+ return NULL;
+}
+
#undef FACTORY_CREATE_ENCODER
#undef FACTORY_REF
+#undef FACTORY_CREATE
#define CODEC_LOGI(x, ...) ALOGI("[%s] "x, mComponentName, ##__VA_ARGS__)
#define CODEC_LOGV(x, ...) ALOGV("[%s] "x, mComponentName, ##__VA_ARGS__)
@@ -173,7 +201,8 @@ static void InitOMXParams(T *params) {
}
static bool IsSoftwareCodec(const char *componentName) {
- if (!strncmp("OMX.google.", componentName, 11)) {
+ if (!strncmp("OMX.google.", componentName, 11)
+ || !strncmp("OMX.PV.", componentName, 7)) {
return true;
}
@@ -245,6 +274,7 @@ void OMXCodec::findMatchingCodecs(
const char *componentName = list->getCodecName(matchIndex);
// If a specific codec is requested, skip the non-matching ones.
+ ALOGV("matchComponentName %s ",matchComponentName);
if (matchComponentName && strcmp(componentName, matchComponentName)) {
continue;
}
@@ -389,15 +419,15 @@ sp<MediaSource> OMXCodec::Create(
componentName = tmp.c_str();
}
+ sp<MediaSource> softwareCodec;
if (createEncoder) {
- sp<MediaSource> softwareCodec =
- InstantiateSoftwareEncoder(componentName, source, meta);
-
- if (softwareCodec != NULL) {
- ALOGV("Successfully allocated software codec '%s'", componentName);
-
- return softwareCodec;
- }
+ softwareCodec = InstantiateSoftwareEncoder(componentName, source, meta);
+ } else {
+ softwareCodec = InstantiateSoftwareDecoder(componentName, source);
+ }
+ if (softwareCodec != NULL) {
+ ALOGE("Successfully allocated software codec '%s'", componentName);
+ return softwareCodec;
}
#ifdef QCOM_HARDWARE
//quirks = getComponentQuirks(componentNameBase, createEncoder);
@@ -562,8 +592,14 @@ status_t OMXCodec::configureCodec(const sp<MetaData> &meta) {
esds.getCodecSpecificInfo(
&codec_specific_data, &codec_specific_data_size);
- addCodecSpecificData(
+ const char * mime_type;
+ meta->findCString(kKeyMIMEType, &mime_type);
+ if (strncmp(mime_type,
+ MEDIA_MIMETYPE_AUDIO_MPEG,
+ strlen(MEDIA_MIMETYPE_AUDIO_MPEG))) {
+ addCodecSpecificData(
codec_specific_data, codec_specific_data_size);
+ }
} else if (meta->findData(kKeyAVCC, &type, &data, &size)) {
// Parse the AVCDecoderConfigurationRecord
diff --git a/media/libstagefright/TunnelPlayer.cpp b/media/libstagefright/TunnelPlayer.cpp
index 475cf56..564f916 100644
--- a/media/libstagefright/TunnelPlayer.cpp
+++ b/media/libstagefright/TunnelPlayer.cpp
@@ -376,7 +376,13 @@ status_t TunnelPlayer::seekTo(int64_t time_us) {
ALOGV("seekTo: time_us %lld", time_us);
- if (mPositionTimeRealUs != 0) {
+ //This can happen if the client calls seek
+ //without ever calling getPosition
+ if (mPositionTimeRealUs == -1) {
+ getOffsetRealTime_l(&mPositionTimeRealUs);
+ }
+
+ if (mPositionTimeRealUs > 0) {
//check for return conditions only if seektime
// is set
if (time_us > mPositionTimeRealUs){
@@ -522,17 +528,10 @@ void TunnelPlayer::reset() {
mInputBuffer = NULL;
}
- if(mStarted)
+ if (mStarted)
mSource->stop();
- // The following hack is necessary to ensure that the OMX
- // component is completely released by the time we may try
- // to instantiate it again.
- wp<MediaSource> tmp = mSource;
mSource.clear();
- while (tmp.promote() != NULL) {
- usleep(1000);
- }
mPositionTimeMediaUs = -1;
mPositionTimeRealUs = -1;
diff --git a/media/libstagefright/codecs/mp3dec/Android.mk b/media/libstagefright/codecs/mp3dec/Android.mk
index ec8d7ec..4837664 100644
--- a/media/libstagefright/codecs/mp3dec/Android.mk
+++ b/media/libstagefright/codecs/mp3dec/Android.mk
@@ -2,6 +2,7 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
+ MP3Decoder.cpp \
src/pvmp3_normalize.cpp \
src/pvmp3_alias_reduction.cpp \
src/pvmp3_crc.cpp \
@@ -52,6 +53,64 @@ LOCAL_CFLAGS := \
LOCAL_MODULE := libstagefright_mp3dec
+include $(BUILD_STATIC_LIBRARY)
+
+
+
+#LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ src/pvmp3_normalize.cpp \
+ src/pvmp3_alias_reduction.cpp \
+ src/pvmp3_crc.cpp \
+ src/pvmp3_decode_header.cpp \
+ src/pvmp3_decode_huff_cw.cpp \
+ src/pvmp3_getbits.cpp \
+ src/pvmp3_dequantize_sample.cpp \
+ src/pvmp3_framedecoder.cpp \
+ src/pvmp3_get_main_data_size.cpp \
+ src/pvmp3_get_side_info.cpp \
+ src/pvmp3_get_scale_factors.cpp \
+ src/pvmp3_mpeg2_get_scale_data.cpp \
+ src/pvmp3_mpeg2_get_scale_factors.cpp \
+ src/pvmp3_mpeg2_stereo_proc.cpp \
+ src/pvmp3_huffman_decoding.cpp \
+ src/pvmp3_huffman_parsing.cpp \
+ src/pvmp3_tables.cpp \
+ src/pvmp3_imdct_synth.cpp \
+ src/pvmp3_mdct_6.cpp \
+ src/pvmp3_dct_6.cpp \
+ src/pvmp3_poly_phase_synthesis.cpp \
+ src/pvmp3_equalizer.cpp \
+ src/pvmp3_seek_synch.cpp \
+ src/pvmp3_stereo_proc.cpp \
+ src/pvmp3_reorder.cpp \
+
+ifeq ($(TARGET_ARCH),arm)
+LOCAL_SRC_FILES += \
+ src/asm/pvmp3_polyphase_filter_window_gcc.s \
+ src/asm/pvmp3_mdct_18_gcc.s \
+ src/asm/pvmp3_dct_9_gcc.s \
+ src/asm/pvmp3_dct_16_gcc.s
+else
+LOCAL_SRC_FILES += \
+ src/pvmp3_polyphase_filter_window.cpp \
+ src/pvmp3_mdct_18.cpp \
+ src/pvmp3_dct_9.cpp \
+ src/pvmp3_dct_16.cpp
+endif
+
+LOCAL_C_INCLUDES := \
+ frameworks/av/media/libstagefright/include \
+ $(LOCAL_PATH)/src \
+ $(LOCAL_PATH)/include
+
+LOCAL_CFLAGS := \
+ -DOSCL_UNUSED_ARG=
+
+LOCAL_MODULE := libstagefright_mp3dec_omx
+
LOCAL_ARM_MODE := arm
include $(BUILD_STATIC_LIBRARY)
@@ -73,7 +132,7 @@ LOCAL_SHARED_LIBRARIES := \
libstagefright libstagefright_omx libstagefright_foundation libutils
LOCAL_STATIC_LIBRARIES := \
- libstagefright_mp3dec
+ libstagefright_mp3dec_omx
LOCAL_MODULE := libstagefright_soft_mp3dec
LOCAL_MODULE_TAGS := optional
diff --git a/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp b/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp
new file mode 100644
index 0000000..c24aca0
--- /dev/null
+++ b/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp
@@ -0,0 +1,586 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MP3Decoder.h"
+
+#include "include/pvmp3decoder_api.h"
+
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
+
+namespace android {
+
+// Everything must match except for
+// protection, bitrate, padding, private bits, mode extension,
+// copyright bit, original bit and emphasis.
+// Yes ... there are things that must indeed match...
+static const uint32_t kMask = 0xfffe0cc0;
+
+static bool get_mp3_frame_size(
+ uint32_t header, size_t *frame_size,
+ int *out_sampling_rate = NULL, int *out_channels = NULL,
+ int *out_bitrate = NULL) {
+ *frame_size = 0;
+
+ if (out_sampling_rate) {
+ *out_sampling_rate = 0;
+ }
+
+ if (out_channels) {
+ *out_channels = 0;
+ }
+
+ if (out_bitrate) {
+ *out_bitrate = 0;
+ }
+
+ if ((header & 0xffe00000) != 0xffe00000) {
+ return false;
+ }
+
+ unsigned version = (header >> 19) & 3;
+
+ if (version == 0x01) {
+ return false;
+ }
+
+ unsigned layer = (header >> 17) & 3;
+
+ if (layer == 0x00) {
+ return false;
+ }
+
+ unsigned protection = (header >> 16) & 1;
+
+ unsigned bitrate_index = (header >> 12) & 0x0f;
+
+ if (bitrate_index == 0 || bitrate_index == 0x0f) {
+ // Disallow "free" bitrate.
+ return false;
+ }
+
+ unsigned sampling_rate_index = (header >> 10) & 3;
+
+ if (sampling_rate_index == 3) {
+ return false;
+ }
+
+ static const int kSamplingRateV1[] = { 44100, 48000, 32000 };
+ int sampling_rate = kSamplingRateV1[sampling_rate_index];
+ if (version == 2 /* V2 */) {
+ sampling_rate /= 2;
+ } else if (version == 0 /* V2.5 */) {
+ sampling_rate /= 4;
+ }
+
+ unsigned padding = (header >> 9) & 1;
+
+ if (layer == 3) {
+ // layer I
+
+ static const int kBitrateV1[] = {
+ 32, 64, 96, 128, 160, 192, 224, 256,
+ 288, 320, 352, 384, 416, 448
+ };
+
+ static const int kBitrateV2[] = {
+ 32, 48, 56, 64, 80, 96, 112, 128,
+ 144, 160, 176, 192, 224, 256
+ };
+
+ int bitrate =
+ (version == 3 /* V1 */)
+ ? kBitrateV1[bitrate_index - 1]
+ : kBitrateV2[bitrate_index - 1];
+
+ if (out_bitrate) {
+ *out_bitrate = bitrate;
+ }
+
+ *frame_size = (12000 * bitrate / sampling_rate + padding) * 4;
+ } else {
+ // layer II or III
+
+ static const int kBitrateV1L2[] = {
+ 32, 48, 56, 64, 80, 96, 112, 128,
+ 160, 192, 224, 256, 320, 384
+ };
+
+ static const int kBitrateV1L3[] = {
+ 32, 40, 48, 56, 64, 80, 96, 112,
+ 128, 160, 192, 224, 256, 320
+ };
+
+ static const int kBitrateV2[] = {
+ 8, 16, 24, 32, 40, 48, 56, 64,
+ 80, 96, 112, 128, 144, 160
+ };
+
+ int bitrate;
+ if (version == 3 /* V1 */) {
+ bitrate = (layer == 2 /* L2 */)
+ ? kBitrateV1L2[bitrate_index - 1]
+ : kBitrateV1L3[bitrate_index - 1];
+ } else {
+ // V2 (or 2.5)
+
+ bitrate = kBitrateV2[bitrate_index - 1];
+ }
+
+ if (out_bitrate) {
+ *out_bitrate = bitrate;
+ }
+
+ if (version == 3 /* V1 */) {
+ *frame_size = 144000 * bitrate / sampling_rate + padding;
+ } else {
+ // V2 or V2.5
+ *frame_size = 72000 * bitrate / sampling_rate + padding;
+ }
+ }
+
+ if (out_sampling_rate) {
+ *out_sampling_rate = sampling_rate;
+ }
+
+ if (out_channels) {
+ int channel_mode = (header >> 6) & 3;
+
+ *out_channels = (channel_mode == 3) ? 1 : 2;
+ }
+
+ return true;
+}
+
+static bool resync(
+ uint8_t *data, uint32_t size, uint32_t match_header, off_t *out_pos) {
+
+ bool valid = false;
+ off_t pos = 0;
+ *out_pos = 0;
+ do {
+ if (pos + 4 > size) {
+ // Don't scan forever.
+ ALOGV("no dice, no valid sequence of frames found.");
+ break;
+ }
+
+ uint32_t header = U32_AT(data + pos);
+
+ if (match_header != 0 && (header & kMask) != (match_header & kMask)) {
+ ++pos;
+ continue;
+ }
+
+ ALOGV("found possible frame at %ld (header = 0x%08x)", pos, header);
+
+ // We found what looks like a valid frame,
+ valid = true;
+ *out_pos = pos;
+ } while (!valid);
+
+ return valid;
+}
+
+
+MP3Decoder::MP3Decoder(const sp<MediaSource> &source)
+ : mSource(source),
+ mNumChannels(0),
+ mStarted(false),
+ mBufferGroup(NULL),
+ mConfig(new tPVMP3DecoderExternal),
+ mDecoderBuf(NULL),
+ mAnchorTimeUs(0),
+ mNumFramesOutput(0),
+ mInputBuffer(NULL),
+ mPartialBuffer(NULL),
+ mFixedHeader(0) {
+ init();
+}
+
+void MP3Decoder::init() {
+ sp<MetaData> srcFormat = mSource->getFormat();
+
+ int32_t sampleRate;
+ CHECK(srcFormat->findInt32(kKeyChannelCount, &mNumChannels));
+ CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate));
+
+ mMeta = new MetaData;
+ mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
+ mMeta->setInt32(kKeyChannelCount, mNumChannels);
+ mMeta->setInt32(kKeySampleRate, sampleRate);
+
+ int64_t durationUs;
+ if (srcFormat->findInt64(kKeyDuration, &durationUs)) {
+ mMeta->setInt64(kKeyDuration, durationUs);
+ }
+
+ mMeta->setCString(kKeyDecoderComponent, "MP3Decoder");
+}
+
+MP3Decoder::~MP3Decoder() {
+ if (mStarted) {
+ stop();
+ }
+
+ delete mConfig;
+ mConfig = NULL;
+}
+
+status_t MP3Decoder::start(MetaData *params) {
+ CHECK(!mStarted);
+
+ mBufferGroup = new MediaBufferGroup;
+ mBufferGroup->add_buffer(new MediaBuffer(4608 * 2));
+
+ mConfig->equalizerType = flat;
+ mConfig->crcEnabled = false;
+
+ uint32_t memRequirements = pvmp3_decoderMemRequirements();
+ mDecoderBuf = malloc(memRequirements);
+
+ pvmp3_InitDecoder(mConfig, mDecoderBuf);
+
+ mSource->start();
+
+ mAnchorTimeUs = 0;
+ mNumFramesOutput = 0;
+ mStarted = true;
+
+ return OK;
+}
+
+status_t MP3Decoder::stop() {
+ CHECK(mStarted);
+
+ if (mInputBuffer) {
+ mInputBuffer->release();
+ mInputBuffer = NULL;
+ }
+
+ free(mDecoderBuf);
+ mDecoderBuf = NULL;
+
+ delete mBufferGroup;
+ mBufferGroup = NULL;
+
+ mSource->stop();
+
+ mStarted = false;
+
+ return OK;
+}
+
+sp<MetaData> MP3Decoder::getFormat() {
+ return mMeta;
+}
+
+status_t MP3Decoder::updatePartialFrame() {
+ status_t err = OK;
+ if (mPartialBuffer == NULL) {
+ return err;
+ }
+
+ size_t frameSize = 0;
+ uint32_t partialBufLen = mPartialBuffer->range_length();
+ uint32_t inputBufLen = mInputBuffer->range_length();
+ uint8_t frameHeader[4];
+ uint8_t *frmHdr;
+ uint32_t header;
+
+
+ // Look at the frame size and complete the partial frame
+ // Also check if a vaild header is found after the partial frame
+ if (partialBufLen < 4) { // check if partial frame has the 4 bytes header
+ if (inputBufLen < (4 - partialBufLen)) {
+ // input buffer does not have the frame header bytes
+ // bail out TODO
+ ALOGE("MP3Decoder::updatePartialFrame buffer to small header not found"
+ " partial buffer len %d, input buffer len %d",
+ partialBufLen, inputBufLen);
+ //mPartialBuffer->release();
+ //mPartialBuffer = NULL;
+ return UNKNOWN_ERROR;
+ }
+
+ // copy the header bytes to frameHeader
+ memcpy (frameHeader, mPartialBuffer->data(), partialBufLen);
+ memcpy (frameHeader + partialBufLen, mInputBuffer->data(), (4 - partialBufLen));
+ // get the first 4 bytes of the buffer
+ header = U32_AT((uint8_t *)frameHeader);
+ frmHdr = frameHeader;
+ } else {
+ frmHdr = (uint8_t *)mPartialBuffer->data();
+ }
+
+ // check if its a good frame, and the frame size
+ // get the first 4 bytes of the buffer
+ header = U32_AT(frmHdr);
+ bool curFrame = get_mp3_frame_size(header,&frameSize);
+ if (!curFrame) {
+ ALOGE("MP3Decoder::read - partial frame does not have a vaild header 0x%x",
+ header);
+ return UNKNOWN_ERROR;
+ }
+
+ // check if the following frame is good
+ uint32_t nextFrameOffset = frameSize - partialBufLen;
+ if ((nextFrameOffset + 4) <= inputBufLen) {
+ header = U32_AT((uint8_t *)mInputBuffer->data() + nextFrameOffset);
+ if ((header & 0xffe00000) != 0xffe00000) {
+ // next frame does not have a valid header,
+ // this may not be the next buffer, bail out.
+ ALOGE("MP3Decoder::read - next frame does not have a vaild header 0x%x",
+ header);
+ return UNKNOWN_ERROR;
+ }
+ } else {
+ // next frame header is out of range
+ // assume good header for now
+ ALOGE("MP3Decoder::read - assuming next frame is good");
+ }
+
+ // check if the input buffer has the remaining partial frame
+ if (frameSize > (partialBufLen + inputBufLen)) {
+ // input buffer does not have the remaining partial frame,
+ // discard data here as frame split in 3 buffers not supported
+ ALOGE("MP3Decoder::updatePartialFrame - input buffer does not have the complete frame."
+ " frame size %d, saved partial buffer len %d,"
+ " input buffer len %d", frameSize, partialBufLen, inputBufLen);
+ return UNKNOWN_ERROR;
+ }
+
+ // check if the mPartialBuffer can fit the remaining frame
+ if ((mPartialBuffer->size() - partialBufLen) < (frameSize - partialBufLen)) {
+ // mPartialBuffer is small to hold the reaming frame
+ //TODO
+ ALOGE("MP3Decoder::updatePartialFrame - mPartialBuffer is small, size %d, required &d",
+ (mPartialBuffer->size() - partialBufLen), (frameSize - partialBufLen));
+ return UNKNOWN_ERROR;
+ }
+
+ // done with error checks
+ // copy the partial frames to from a complete frame
+ // Copy the remaining frame from input buffer
+ uint32_t bytesRemaining = frameSize - mPartialBuffer->range_length();
+ memcpy ((uint8_t *)mPartialBuffer->data() + mPartialBuffer->range_length(),
+ (uint8_t *)mInputBuffer->data() + mInputBuffer->range_offset(),
+ bytesRemaining);
+
+ // mark the bytes as consumed from input buffer
+ mInputBuffer->set_range(
+ mInputBuffer->range_offset() + bytesRemaining,
+ mInputBuffer->range_length() - bytesRemaining);
+
+ // set the range and length of mPartialBuffer
+ mPartialBuffer->set_range(0,
+ mPartialBuffer->range_length() + bytesRemaining);
+
+ ALOGE("MP3Decoder::updatePartialFrame - copied the partial frame %d, input buffer length %d",
+ bytesRemaining, mInputBuffer->range_length());
+
+ return err;
+}
+
+status_t MP3Decoder::read(
+ MediaBuffer **out, const ReadOptions *options) {
+ status_t err;
+
+ *out = NULL;
+ bool usedPartialFrame = false;
+ bool seekSource = false;
+
+ int64_t seekTimeUs;
+ ReadOptions::SeekMode mode;
+ if (options && options->getSeekTo(&seekTimeUs, &mode)) {
+ CHECK(seekTimeUs >= 0);
+
+ mNumFramesOutput = 0;
+ seekSource = true;
+
+ if (mInputBuffer) {
+ mInputBuffer->release();
+ mInputBuffer = NULL;
+ }
+
+ if (mPartialBuffer) {
+ mPartialBuffer->release();
+ mPartialBuffer = NULL;
+ }
+
+ // Make sure that the next buffer output does not still
+ // depend on fragments from the last one decoded.
+ pvmp3_InitDecoder(mConfig, mDecoderBuf);
+ } else {
+ seekTimeUs = -1;
+ }
+
+ if (mInputBuffer == NULL) {
+ err = mSource->read(&mInputBuffer, options);
+
+ if (err != OK) {
+ return err;
+ }
+
+ if ((mFixedHeader == 0) && (mInputBuffer->range_length() > 4)) {
+ //save the first 4 bytes as fixed header for the reset of the file
+ mFixedHeader = U32_AT((uint8_t *)mInputBuffer->data());
+ }
+
+ if (seekSource == true) {
+ off_t syncOffset = 0;
+ bool valid = resync((uint8_t *)mInputBuffer->data() + mInputBuffer->range_offset()
+ ,mInputBuffer->range_length(), mFixedHeader, &syncOffset);
+ if (valid) {
+ // consume these bytes, we might find a frame header in next buffer
+ mInputBuffer->set_range(
+ mInputBuffer->range_offset() + syncOffset,
+ mInputBuffer->range_length() - syncOffset);
+ ALOGV("mp3 decoder found a sync point after seek syncOffset %d", syncOffset);
+ } else {
+ ALOGV("NO SYNC POINT found, buffer length %d",mInputBuffer->range_length());
+ }
+ }
+
+ int64_t timeUs;
+ if (mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) {
+ mAnchorTimeUs = timeUs;
+ mNumFramesOutput = 0;
+ } else {
+ // We must have a new timestamp after seeking.
+ CHECK(seekTimeUs < 0);
+ }
+ // check for partial frame
+ if (mPartialBuffer != NULL) {
+ err = updatePartialFrame();
+ if (err != OK) {
+ // updating partial frame failed, discard the previously
+ // saved partial frame and continue
+ mPartialBuffer->release();
+ mPartialBuffer = NULL;
+ err = OK;
+ }
+ }
+ }
+
+ MediaBuffer *buffer;
+ CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), OK);
+
+ if (mPartialBuffer != NULL) {
+ mConfig->pInputBuffer =
+ (uint8_t *)mPartialBuffer->data() + mPartialBuffer->range_offset();
+ mConfig->inputBufferCurrentLength = mPartialBuffer->range_length();
+ usedPartialFrame = true;
+ } else {
+ mConfig->pInputBuffer =
+ (uint8_t *)mInputBuffer->data() + mInputBuffer->range_offset();
+ mConfig->inputBufferCurrentLength = mInputBuffer->range_length();
+ }
+
+ mConfig->inputBufferMaxLength = 0;
+ mConfig->inputBufferUsedLength = 0;
+
+ mConfig->outputFrameSize = buffer->size() / sizeof(int16_t);
+ mConfig->pOutputBuffer = static_cast<int16_t *>(buffer->data());
+
+ ERROR_CODE decoderErr;
+ if ((decoderErr = pvmp3_framedecoder(mConfig, mDecoderBuf))
+ != NO_DECODING_ERROR) {
+ ALOGV("mp3 decoder returned error %d", decoderErr);
+
+ if ((decoderErr != NO_ENOUGH_MAIN_DATA_ERROR) &&
+ (decoderErr != SYNCH_LOST_ERROR)) {
+ buffer->release();
+ buffer = NULL;
+
+ mInputBuffer->release();
+ mInputBuffer = NULL;
+ if (mPartialBuffer) {
+ mPartialBuffer->release();
+ mPartialBuffer = NULL;
+ }
+ ALOGE("mp3 decoder returned UNKNOWN_ERROR");
+
+ return UNKNOWN_ERROR;
+ }
+
+ if ((mPartialBuffer == NULL) && (decoderErr == NO_ENOUGH_MAIN_DATA_ERROR)) {
+ // Might be a partial frame, save it
+ mPartialBuffer = new MediaBuffer(mInputBuffer->size());
+ memcpy ((uint8_t *)mPartialBuffer->data(),
+ mConfig->pInputBuffer, mConfig->inputBufferCurrentLength);
+ mPartialBuffer->set_range(0, mConfig->inputBufferCurrentLength);
+ // set output buffer to 0
+ mConfig->outputFrameSize = 0;
+ // consume the copied bytes from input
+ mConfig->inputBufferUsedLength = mConfig->inputBufferCurrentLength;
+ } else if(decoderErr == SYNCH_LOST_ERROR) {
+ // Try to find the mp3 frame header in the current buffer
+ off_t syncOffset = 0;
+ bool valid = resync(mConfig->pInputBuffer, mConfig->inputBufferCurrentLength,
+ mFixedHeader, &syncOffset);
+ if (!valid || !syncOffset) {
+ // consume these bytes, we might find a frame header in next buffer
+ syncOffset = mConfig->inputBufferCurrentLength;
+ }
+ // set output buffer to 0
+ mConfig->outputFrameSize = 0;
+ // consume the junk bytes from input buffer
+ mConfig->inputBufferUsedLength = syncOffset;
+ } else {
+ // This is recoverable, just ignore the current frame and
+ // play silence instead.
+ memset(buffer->data(), 0, mConfig->outputFrameSize * sizeof(int16_t));
+ mConfig->inputBufferUsedLength = mInputBuffer->range_length();
+ }
+ }
+
+ buffer->set_range(
+ 0, mConfig->outputFrameSize * sizeof(int16_t));
+
+ if ((mPartialBuffer != NULL) && usedPartialFrame) {
+ mPartialBuffer->set_range(
+ mPartialBuffer->range_offset() + mConfig->inputBufferUsedLength,
+ mPartialBuffer->range_length() - mConfig->inputBufferUsedLength);
+ mPartialBuffer->release();
+ mPartialBuffer = NULL;
+ } else {
+ mInputBuffer->set_range(
+ mInputBuffer->range_offset() + mConfig->inputBufferUsedLength,
+ mInputBuffer->range_length() - mConfig->inputBufferUsedLength);
+ }
+
+ if (mInputBuffer->range_length() == 0) {
+ mInputBuffer->release();
+ mInputBuffer = NULL;
+ }
+
+ buffer->meta_data()->setInt64(
+ kKeyTime,
+ mAnchorTimeUs
+ + (mNumFramesOutput * 1000000) / mConfig->samplingRate);
+
+ mNumFramesOutput += mConfig->outputFrameSize / mNumChannels;
+
+ *out = buffer;
+
+ return OK;
+}
+
+} // namespace android
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index a5586dd..348f485 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -365,6 +365,8 @@ private:
size_t countTracks() const;
#ifdef QCOM_ENHANCED_AUDIO
+ bool inSupportedTunnelFormats(const char * mime);
+
//Flag to check if tunnel mode audio is enabled
bool mIsTunnelAudio;
#endif
diff --git a/media/libstagefright/include/MP3Decoder.h b/media/libstagefright/include/MP3Decoder.h
new file mode 100644
index 0000000..8ff570a
--- /dev/null
+++ b/media/libstagefright/include/MP3Decoder.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MP3_DECODER_H_
+
+#define MP3_DECODER_H_
+
+#include <media/stagefright/MediaSource.h>
+
+struct tPVMP3DecoderExternal;
+
+namespace android {
+
+struct MediaBufferGroup;
+
+struct MP3Decoder : public MediaSource {
+ MP3Decoder(const sp<MediaSource> &source);
+
+ virtual status_t start(MetaData *params);
+ virtual status_t stop();
+
+ virtual sp<MetaData> getFormat();
+
+ virtual status_t read(
+ MediaBuffer **buffer, const ReadOptions *options);
+
+protected:
+ virtual ~MP3Decoder();
+
+private:
+ sp<MediaSource> mSource;
+ sp<MetaData> mMeta;
+ int32_t mNumChannels;
+
+ bool mStarted;
+
+ MediaBufferGroup *mBufferGroup;
+
+ tPVMP3DecoderExternal *mConfig;
+ void *mDecoderBuf;
+ int64_t mAnchorTimeUs;
+ int64_t mNumFramesOutput;
+ uint32_t mFixedHeader;
+
+ MediaBuffer *mInputBuffer;
+ MediaBuffer *mPartialBuffer;
+
+ void init();
+
+ MP3Decoder(const MP3Decoder &);
+ MP3Decoder &operator=(const MP3Decoder &);
+ status_t updatePartialFrame();
+};
+
+} // namespace android
+
+#endif // MP3_DECODER_H_
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index bd9421c..c2b97d8 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -13,6 +13,10 @@ include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
+ifeq ($(TARGET_QCOM_AUDIO_VARIANT),caf)
+LOCAL_CFLAGS += -DQCOM_ENHANCED_AUDIO
+endif
+
LOCAL_SRC_FILES:= \
AudioFlinger.cpp \
AudioMixer.cpp.arm \
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 12cfe9d..d260074 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1204,7 +1204,15 @@ status_t AudioFlinger::setParameters(audio_io_handle_t ioHandle, const String8&
if (desc != NULL) {
ALOGV("setParameters for mAudioTracks size %d desc %p",mDirectAudioTracks.size(),desc);
desc->stream->common.set_parameters(&desc->stream->common, keyValuePairs.string());
- return NO_ERROR;
+ AudioParameter param = AudioParameter(keyValuePairs);
+ String8 key = String8(AudioParameter::keyRouting);
+ int device;
+ if (param.getInt(key, device) == NO_ERROR) {
+ if(mLPAEffectChain != NULL){
+ mLPAEffectChain->setDevice_l(device);
+ audioConfigChanged_l(AudioSystem::EFFECT_CONFIG_CHANGED, 0, NULL);
+ }
+ }
}
}
#endif
@@ -6169,9 +6177,12 @@ AudioFlinger::DirectAudioTrack::~DirectAudioTrack() {
AudioSystem::releaseOutput(mOutput);
releaseWakeLock();
- if (mPowerManager != 0) {
- sp<IBinder> binder = mPowerManager->asBinder();
- binder->unlinkToDeath(mDeathRecipient);
+ {
+ Mutex::Autolock _l(pmLock);
+ if (mPowerManager != 0) {
+ sp<IBinder> binder = mPowerManager->asBinder();
+ binder->unlinkToDeath(mDeathRecipient);
+ }
}
}
@@ -6234,8 +6245,8 @@ void AudioFlinger::DirectAudioTrack::mute(bool muted) {
}
void AudioFlinger::DirectAudioTrack::setVolume(float left, float right) {
- mOutputDesc->mVolumeLeft = 1.0;
- mOutputDesc->mVolumeRight = 1.0;
+ mOutputDesc->mVolumeLeft = left;
+ mOutputDesc->mVolumeRight = right;
}
int64_t AudioFlinger::DirectAudioTrack::getTimeStamp() {
@@ -6428,8 +6439,8 @@ void AudioFlinger::DirectAudioTrack::releaseWakeLock()
void AudioFlinger::DirectAudioTrack::clearPowerManager()
{
- Mutex::Autolock _l(pmLock);
releaseWakeLock();
+ Mutex::Autolock _l(pmLock);
mPowerManager.clear();
}
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index af169d5..ced0453 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -549,7 +549,11 @@ bool AudioMixer::track_t::setResampler(uint32_t value, uint32_t devSampleRate)
(value == 48000 && devSampleRate == 44100))) {
quality = AudioResampler::LOW_QUALITY;
} else {
+#ifdef QCOM_ENHANCED_AUDIO
+ quality = AudioResampler::VERY_HIGH_QUALITY;
+#else
quality = AudioResampler::DEFAULT_QUALITY;
+#endif
}
resampler = AudioResampler::create(
format,