summaryrefslogtreecommitdiffstats
path: root/media/libmedia/AudioTrack.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'media/libmedia/AudioTrack.cpp')
-rw-r--r--media/libmedia/AudioTrack.cpp266
1 files changed, 218 insertions, 48 deletions
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index fa52fa9..a2172c9 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -2,6 +2,10 @@
**
** Copyright 2007, The Android Open Source Project
**
+** Copyright (c) 2012, 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
@@ -96,6 +100,10 @@ AudioTrack::AudioTrack()
mIsTimed(false),
mPreviousPriority(ANDROID_PRIORITY_NORMAL),
mPreviousSchedulingGroup(SP_DEFAULT)
+#ifdef QCOM_HARDWARE
+ ,mAudioFlinger(NULL),
+ mObserver(NULL)
+#endif
{
}
@@ -114,6 +122,10 @@ AudioTrack::AudioTrack(
mIsTimed(false),
mPreviousPriority(ANDROID_PRIORITY_NORMAL),
mPreviousSchedulingGroup(SP_DEFAULT)
+#ifdef QCOM_HARDWARE
+ ,mAudioFlinger(NULL),
+ mObserver(NULL)
+#endif
{
mStatus = set(streamType, sampleRate, format, channelMask,
frameCount, flags, cbf, user, notificationFrames,
@@ -135,6 +147,10 @@ AudioTrack::AudioTrack(
: mStatus(NO_INIT),
mIsTimed(false),
mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT)
+#ifdef QCOM_HARDWARE
+ ,mAudioFlinger(NULL),
+ mObserver(NULL)
+#endif
{
mStatus = set((audio_stream_type_t)streamType, sampleRate, (audio_format_t)format,
(audio_channel_mask_t) channelMask,
@@ -157,6 +173,10 @@ AudioTrack::AudioTrack(
mIsTimed(false),
mPreviousPriority(ANDROID_PRIORITY_NORMAL),
mPreviousSchedulingGroup(SP_DEFAULT)
+#ifdef QCOM_HARDWARE
+ ,mAudioFlinger(NULL),
+ mObserver(NULL)
+#endif
{
mStatus = set(streamType, sampleRate, format, channelMask,
0 /*frameCount*/, flags, cbf, user, notificationFrames,
@@ -177,9 +197,22 @@ AudioTrack::~AudioTrack()
mAudioTrackThread->requestExitAndWait();
mAudioTrackThread.clear();
}
+#ifdef QCOM_HARDWARE
+ if (mAudioTrack != 0) {
+ mAudioTrack.clear();
+ AudioSystem::releaseAudioSessionId(mSessionId);
+ }
+
+ if (mDirectTrack != 0) {
+ mDirectTrack.clear();
+ }
+#else
mAudioTrack.clear();
+#endif
IPCThreadState::self()->flushCommands();
+#ifndef QCOM_HARDWARE
AudioSystem::releaseAudioSessionId(mSessionId);
+#endif
}
}
@@ -252,12 +285,24 @@ status_t AudioTrack::set(
flags = (audio_output_flags_t)(flags &~AUDIO_OUTPUT_FLAG_DEEP_BUFFER);
}
+#ifdef QCOM_ENHANCED_AUDIO
+ if ((streamType == AUDIO_STREAM_VOICE_CALL)
+ && (channelMask == AUDIO_CHANNEL_OUT_MONO)
+ && ((sampleRate == 8000 || sampleRate == 16000)))
+ {
+ ALOGD("Turn on Direct Output for VOIP RX");
+ flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_VOIP_RX|AUDIO_OUTPUT_FLAG_DIRECT);
+ }
+#endif
+
if (!audio_is_output_channel(channelMask)) {
ALOGE("Invalid channel mask %#x", channelMask);
return BAD_VALUE;
}
uint32_t channelCount = popcount(channelMask);
+ ALOGV("AudioTrack getOutput streamType %d, sampleRate %d, format %d, channelMask %d, flags %x",
+ streamType, sampleRate, format, channelMask, flags);
audio_io_handle_t output = AudioSystem::getOutput(
streamType,
sampleRate, format, channelMask,
@@ -278,46 +323,86 @@ status_t AudioTrack::set(
mFlags = flags;
mCbf = cbf;
- if (cbf != NULL) {
- mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);
- mAudioTrackThread->run("AudioTrack", ANDROID_PRIORITY_AUDIO, 0 /*stack*/);
- }
-
- // create the IAudioTrack
- status_t status = createTrack_l(streamType,
- sampleRate,
- format,
- channelMask,
- frameCount,
- flags,
- sharedBuffer,
- output);
+#ifdef QCOM_HARDWARE
+ if (flags & AUDIO_OUTPUT_FLAG_LPA || flags & AUDIO_OUTPUT_FLAG_TUNNEL) {
+ ALOGV("Creating Direct Track");
+ const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
+ if (audioFlinger == 0) {
+ ALOGE("Could not get audioflinger");
+ return NO_INIT;
+ }
+ mAudioFlinger = audioFlinger;
+ status_t status = NO_ERROR;
+ mAudioDirectOutput = output;
+ mDirectTrack = audioFlinger->createDirectTrack( getpid(),
+ sampleRate,
+ channelMask,
+ mAudioDirectOutput,
+ &mSessionId,
+ this,
+ streamType,
+ &status);
+ if(status != NO_ERROR) {
+ ALOGE("createDirectTrack returned with status %d", status);
+ return status;
+ }
+ mAudioTrack = NULL;
+ mSharedBuffer = NULL;
+ }
+ else {
+#endif
+ if (cbf != NULL) {
+ mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);
+ mAudioTrackThread->run("AudioTrack", ANDROID_PRIORITY_AUDIO, 0 /*stack*/);
+ }
+ // create the IAudioTrack
+ status_t status = createTrack_l(streamType,
+ sampleRate,
+ format,
+ channelMask,
+ frameCount,
+ flags,
+ sharedBuffer,
+ output);
- if (status != NO_ERROR) {
- if (mAudioTrackThread != 0) {
- mAudioTrackThread->requestExit();
- mAudioTrackThread.clear();
+ if (status != NO_ERROR) {
+ if (mAudioTrackThread != 0) {
+ mAudioTrackThread->requestExit();
+ mAudioTrackThread.clear();
+ }
+ return status;
}
- return status;
+#ifdef QCOM_HARDWARE
+ AudioSystem::acquireAudioSessionId(mSessionId);
+ mAudioDirectOutput = -1;
+ mDirectTrack = NULL;
+ mSharedBuffer = sharedBuffer;
}
-
+ mUserData = user;
+#endif
mStatus = NO_ERROR;
mStreamType = streamType;
mFormat = format;
mChannelMask = channelMask;
mChannelCount = channelCount;
- mSharedBuffer = sharedBuffer;
+
mMuted = false;
mActive = false;
- mUserData = user;
+
mLoopCount = 0;
mMarkerPosition = 0;
mMarkerReached = false;
mNewPosition = 0;
mUpdatePeriod = 0;
mFlushed = false;
+
+#ifndef QCOM_HARDWARE
+ mSharedBuffer = sharedBuffer;
+ mUserData = user;
AudioSystem::acquireAudioSessionId(mSessionId);
+#endif
+
mRestoreStatus = NO_ERROR;
return NO_ERROR;
}
@@ -331,6 +416,11 @@ status_t AudioTrack::initCheck() const
uint32_t AudioTrack::latency() const
{
+#ifdef QCOM_HARDWARE
+ if(mAudioDirectOutput != -1) {
+ return mAudioFlinger->latency(mAudioDirectOutput);
+ }
+#endif
return mLatency;
}
@@ -351,6 +441,11 @@ int AudioTrack::channelCount() const
uint32_t AudioTrack::frameCount() const
{
+#ifdef QCOM_HARDWARE
+ if(mAudioDirectOutput != -1) {
+ return mAudioFlinger->frameCount(mAudioDirectOutput);
+ }
+#endif
return mCblk->frameCount;
}
@@ -372,6 +467,16 @@ sp<IMemory>& AudioTrack::sharedBuffer()
void AudioTrack::start()
{
+#ifdef QCOM_HARDWARE
+ if (mDirectTrack != NULL) {
+ if(mActive == 0) {
+ mActive = 1;
+ mDirectTrack->start();
+ }
+ return;
+ }
+#endif
+
sp<AudioTrackThread> t = mAudioTrackThread;
ALOGV("start %p", this);
@@ -436,26 +541,35 @@ void AudioTrack::stop()
AutoMutex lock(mLock);
if (mActive) {
- mActive = false;
- mCblk->cv.signal();
- mAudioTrack->stop();
- // Cancel loops (If we are in the middle of a loop, playback
- // would not stop until loopCount reaches 0).
- setLoop_l(0, 0, 0);
- // the playback head position will reset to 0, so if a marker is set, we need
- // to activate it again
- mMarkerReached = false;
- // Force flush if a shared buffer is used otherwise audioflinger
- // will not stop before end of buffer is reached.
- if (mSharedBuffer != 0) {
- flush_l();
- }
- if (t != 0) {
- t->pause();
- } else {
- setpriority(PRIO_PROCESS, 0, mPreviousPriority);
- set_sched_policy(0, mPreviousSchedulingGroup);
+#ifdef QCOM_HARDWARE
+ if(mDirectTrack != NULL) {
+ mActive = false;
+ mDirectTrack->stop();
+ } else if (mAudioTrack != NULL) {
+#endif
+ mActive = false;
+ mCblk->cv.signal();
+ mAudioTrack->stop();
+ // Cancel loops (If we are in the middle of a loop, playback
+ // would not stop until loopCount reaches 0).
+ setLoop_l(0, 0, 0);
+ // the playback head position will reset to 0, so if a marker is set, we need
+ // to activate it again
+ mMarkerReached = false;
+ // Force flush if a shared buffer is used otherwise audioflinger
+ // will not stop before end of buffer is reached.
+ if (mSharedBuffer != 0) {
+ flush_l();
+ }
+ if (t != 0) {
+ t->pause();
+ } else {
+ setpriority(PRIO_PROCESS, 0, mPreviousPriority);
+ set_sched_policy(0, mPreviousSchedulingGroup);
+ }
+#ifdef QCOM_HARDWARE
}
+#endif
}
}
@@ -469,7 +583,12 @@ bool AudioTrack::stopped() const
void AudioTrack::flush()
{
AutoMutex lock(mLock);
- flush_l();
+#ifdef QCOM_HARDWARE
+ if(mDirectTrack != NULL) {
+ mDirectTrack->flush();
+ } else
+#endif
+ flush_l();
}
// must be called with mLock held
@@ -497,14 +616,28 @@ void AudioTrack::pause()
AutoMutex lock(mLock);
if (mActive) {
mActive = false;
- mCblk->cv.signal();
- mAudioTrack->pause();
+#ifdef QCOM_HARDWARE
+ if(mDirectTrack != NULL) {
+ ALOGV("mDirectTrack pause");
+ mDirectTrack->pause();
+ } else {
+#endif
+ mCblk->cv.signal();
+ mAudioTrack->pause();
+#ifdef QCOM_HARDWARE
+ }
+#endif
}
}
void AudioTrack::mute(bool e)
{
- mAudioTrack->mute(e);
+#ifdef QCOM_HARDWARE
+ if(mDirectTrack != NULL) {
+ mDirectTrack->mute(e);
+ } else
+#endif
+ mAudioTrack->mute(e);
mMuted = e;
}
@@ -522,8 +655,13 @@ status_t AudioTrack::setVolume(float left, float right)
AutoMutex lock(mLock);
mVolume[LEFT] = left;
mVolume[RIGHT] = right;
-
- mCblk->setVolumeLR((uint32_t(uint16_t(right * 0x1000)) << 16) | uint16_t(left * 0x1000));
+#ifdef QCOM_HARDWARE
+ if(mDirectTrack != NULL) {
+ ALOGV("mDirectTrack->setVolume(left = %f , right = %f)", left,right);
+ mDirectTrack->setVolume(left, right);
+ } else
+#endif
+ mCblk->setVolumeLR((uint32_t(uint16_t(right * 0x1000)) << 16) | uint16_t(left * 0x1000));
return NO_ERROR;
}
@@ -540,6 +678,11 @@ void AudioTrack::getVolume(float* left, float* right) const
status_t AudioTrack::setAuxEffectSendLevel(float level)
{
+#ifdef QCOM_HARDWARE
+ if (mDirectTrack != NULL) {
+ return NO_ERROR;
+ }
+#endif
ALOGV("setAuxEffectSendLevel(%f)", level);
if (level < 0.0f || level > 1.0f) {
return BAD_VALUE;
@@ -586,6 +729,11 @@ uint32_t AudioTrack::getSampleRate() const
}
AutoMutex lock(mLock);
+#ifdef QCOM_HARDWARE
+ if(mAudioDirectOutput != -1) {
+ return mAudioFlinger->sampleRate(mAudioDirectOutput);
+ }
+#endif
return mCblk->sampleRate;
}
@@ -1076,7 +1224,12 @@ void AudioTrack::releaseBuffer(Buffer* audioBuffer)
ssize_t AudioTrack::write(const void* buffer, size_t userSize)
{
-
+#ifdef QCOM_HARDWARE
+ if (mDirectTrack != NULL) {
+ mDirectTrack->write(buffer,userSize);
+ return userSize;
+ }
+#endif
if (mSharedBuffer != 0) return INVALID_OPERATION;
if (mIsTimed) return INVALID_OPERATION;
@@ -1456,6 +1609,23 @@ status_t AudioTrack::dump(int fd, const Vector<String16>& args) const
return NO_ERROR;
}
+#ifdef QCOM_HARDWARE
+void AudioTrack::notify(int msg) {
+ if (msg == EVENT_UNDERRUN) {
+ ALOGV("Posting event underrun to Audio Sink.");
+ mCbf(EVENT_UNDERRUN, mUserData, 0);
+ }
+}
+
+status_t AudioTrack::getTimeStamp(uint64_t *tstamp) {
+ if (mDirectTrack != NULL) {
+ *tstamp = mDirectTrack->getTimeStamp();
+ ALOGV("Timestamp %lld ", *tstamp);
+ }
+ return NO_ERROR;
+}
+#endif
+
// =========================================================================
AudioTrack::AudioTrackThread::AudioTrackThread(AudioTrack& receiver, bool bCanCallJava)