summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/media/AudioSystem.h9
-rwxr-xr-xinclude/media/IAudioFlinger.h7
-rw-r--r--include/media/stagefright/FMA2DPWriter.h84
-rw-r--r--media/libmedia/AudioSystem.cpp13
-rw-r--r--media/libmedia/IAudioFlinger.cpp25
-rw-r--r--media/libmediaplayerservice/StagefrightRecorder.cpp29
-rw-r--r--media/libmediaplayerservice/StagefrightRecorder.h8
-rwxr-xr-xmedia/libstagefright/Android.mk5
-rw-r--r--media/libstagefright/FMA2DPWriter.cpp323
-rw-r--r--services/audioflinger/AudioFlinger.cpp26
-rw-r--r--services/audioflinger/AudioFlinger.h10
-rw-r--r--services/audioflinger/AudioPolicyService.cpp69
-rw-r--r--services/audioflinger/AudioPolicyService.h22
13 files changed, 618 insertions, 12 deletions
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index d8c57d3..31b1b08 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -1,10 +1,10 @@
/*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (C) 2008 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.
*
- * Copyright (C) 2008 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
@@ -120,6 +120,9 @@ public:
audio_channel_mask_t channelMask, size_t* buffSize);
static status_t setVoiceVolume(float volume);
+#ifdef QCOM_FM_ENABLED
+ static status_t setFmVolume(float volume);
+#endif
// return the number of audio frames written by AudioFlinger to audio HAL and
// audio dsp to DAC since the output on which the specified stream is playing
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index 0700a68..396f87b 100755
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -1,10 +1,10 @@
/*
+ * Copyright (C) 2007 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.
*
- * Copyright (C) 2007 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
@@ -219,6 +219,9 @@ public:
// that looks on primary device for a stream with fast flag, primary flag, or first one.
virtual int32_t getPrimaryOutputSamplingRate() = 0;
virtual int32_t getPrimaryOutputFrameCount() = 0;
+#ifdef QCOM_FM_ENABLED
+ virtual status_t setFmVolume(float volume) = 0;
+#endif
};
diff --git a/include/media/stagefright/FMA2DPWriter.h b/include/media/stagefright/FMA2DPWriter.h
new file mode 100644
index 0000000..f1c1694
--- /dev/null
+++ b/include/media/stagefright/FMA2DPWriter.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2010 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 FM_A2DP_WRITER_H_
+
+#define FM_A2DP_WRITER_H_
+
+#include <stdio.h>
+
+#include <media/stagefright/MediaWriter.h>
+#include <utils/threads.h>
+#include <media/AudioRecord.h>
+#include <utils/List.h>
+#include <semaphore.h>
+#include <media/mediarecorder.h>
+
+namespace android {
+
+struct MediaSource;
+struct MetaData;
+
+struct audioBufferstruct {
+ public:
+ audioBufferstruct (void *buff, size_t bufflen)
+ :audioBuffer(buff), bufferlen(bufflen){}
+
+ void *audioBuffer;
+ size_t bufferlen;
+ };
+
+struct FMA2DPWriter : public MediaWriter {
+ FMA2DPWriter();
+
+ status_t initCheck() const;
+ virtual status_t addSource(const sp<MediaSource> &source);
+ virtual bool reachedEOS();
+ virtual status_t start(MetaData *params = NULL);
+ virtual status_t stop();
+ virtual status_t pause();
+ virtual status_t allocateBufferPool();
+
+protected:
+ virtual ~FMA2DPWriter();
+
+private:
+ List<audioBufferstruct > mFreeQ,mDataQ;
+ Mutex mFreeQLock,mDataQLock;
+ sem_t mReaderThreadWakeupsem,mWriterThreadWakeupsem;
+ pthread_t mReaderThread,mWriterThread;
+ bool mStarted;
+ volatile bool mDone;
+ int32_t mAudioChannels;
+ int32_t mSampleRate;
+ audio_format_t mAudioFormat;
+ audio_source_t mAudioSource;
+ size_t mBufferSize;
+ static void *ReaderThreadWrapper(void *);
+ static void *WriterThreadWrapper(void *);
+ status_t readerthread();
+ status_t writerthread();
+ FMA2DPWriter(const FMA2DPWriter &);
+ FMA2DPWriter &operator=(const FMA2DPWriter &);
+};
+
+} // namespace android
+
+#endif // FM_A2DP_WRITER_H_
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index fd8c320..aaf2ddd 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -1,5 +1,9 @@
/*
* Copyright (C) 2006-2007 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.
@@ -411,6 +415,15 @@ void AudioSystem::releaseAudioSessionId(int audioSession) {
}
}
+#ifdef QCOM_FM_ENABLED
+status_t AudioSystem::setFmVolume(float value)
+{
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ return af->setFmVolume(value);
+}
+#endif
+
// ---------------------------------------------------------------------------
void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who) {
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index cc6a75c..9d5691f 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -1,7 +1,8 @@
/*
**
** Copyright 2007, The Android Open Source Project
-** Copyright (c) 2012, The Linux Foundation. All rights reserved.
+** Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+**
** Not a Contribution, Apache license notifications and license are retained
** for attribution purposes only.
**
@@ -73,6 +74,9 @@ enum {
GET_EFFECT_DESCRIPTOR,
CREATE_EFFECT,
MOVE_EFFECTS,
+#ifdef QCOM_FM_ENABLED
+ SET_FM_VOLUME,
+#endif
LOAD_HW_MODULE,
GET_PRIMARY_OUTPUT_SAMPLING_RATE,
GET_PRIMARY_OUTPUT_FRAME_COUNT,
@@ -730,6 +734,17 @@ public:
return reply.readInt32();
}
+#ifdef QCOM_FM_ENABLED
+ virtual status_t setFmVolume(float volume)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeFloat(volume);
+ remote()->transact(SET_FM_VOLUME, data, &reply);
+ return reply.readInt32();
+ }
+#endif
+
virtual audio_module_handle_t loadHwModule(const char *name)
{
Parcel data, reply;
@@ -1128,6 +1143,14 @@ status_t BnAudioFlinger::onTransact(
reply->writeInt32(moveEffects(session, srcOutput, dstOutput));
return NO_ERROR;
} break;
+#ifdef QCOM_FM_ENABLED
+ case SET_FM_VOLUME: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ float volume = data.readFloat();
+ reply->writeInt32( setFmVolume(volume) );
+ return NO_ERROR;
+ } break;
+#endif
case LOAD_HW_MODULE: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
reply->writeInt32(loadHwModule(data.readCString()));
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 335dd43..94886e8 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -1,6 +1,9 @@
/*
* Copyright (C) 2009 The Android Open Source Project
- * Copyright (c) 2010 - 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-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.
@@ -34,6 +37,9 @@
#include <media/stagefright/ExtendedWriter.h>
#include <media/stagefright/WAVEWriter.h>
#endif
+#ifdef QCOM_FM_ENABLED
+#include <media/stagefright/FMA2DPWriter.h>
+#endif
#include <media/stagefright/CameraSource.h>
#include <media/stagefright/CameraSourceTimeLapse.h>
#include <media/stagefright/MPEG2TSWriter.h>
@@ -771,6 +777,10 @@ status_t StagefrightRecorder::start() {
}
status_t status = OK;
+#ifdef QCOM_FM_ENABLED
+ if(AUDIO_SOURCE_FM_RX_A2DP == mAudioSource)
+ return startFMA2DPWriter();
+#endif
switch (mOutputFormat) {
case OUTPUT_FORMAT_DEFAULT:
@@ -1036,6 +1046,23 @@ status_t StagefrightRecorder::startRawAudioRecording() {
return OK;
}
+#ifdef QCOM_FM_ENABLED
+status_t StagefrightRecorder::startFMA2DPWriter() {
+ /* FM soc outputs at 48k */
+ mSampleRate = 48000;
+ mAudioChannels = 2;
+
+ sp<MetaData> meta = new MetaData;
+ meta->setInt32(kKeyChannelCount, mAudioChannels);
+ meta->setInt32(kKeySampleRate, mSampleRate);
+
+ mWriter = new FMA2DPWriter();
+ mWriter->setListener(mListener);
+ mWriter->start(meta.get());
+ return OK;
+}
+#endif
+
status_t StagefrightRecorder::startRTPRecording() {
CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_RTP_AVP);
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index 3f0b821..fd58115 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -1,6 +1,9 @@
/*
* Copyright (C) 2009 The Android Open Source Project
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * 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.
@@ -132,6 +135,9 @@ private:
sp<MetaData> *meta);
status_t startMPEG4Recording();
status_t startAMRRecording();
+#ifdef QCOM_FM_ENABLED
+ status_t startFMA2DPWriter();
+#endif
status_t startAACRecording();
#ifdef QCOM_HARDWARE
status_t startWAVERecording();
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index e2209ff4..b394d90 100755
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -57,6 +57,11 @@ LOCAL_SRC_FILES:= \
mp4/FragmentedMP4Parser.cpp \
mp4/TrackFragment.cpp \
+ifeq ($(BOARD_HAVE_QCOM_FM),true)
+LOCAL_SRC_FILES+= \
+ FMA2DPWriter.cpp
+endif
+
LOCAL_C_INCLUDES:= \
$(TOP)/frameworks/av/include/media/stagefright/timedtext \
$(TOP)/frameworks/native/include/media/hardware \
diff --git a/media/libstagefright/FMA2DPWriter.cpp b/media/libstagefright/FMA2DPWriter.cpp
new file mode 100644
index 0000000..1bcec17
--- /dev/null
+++ b/media/libstagefright/FMA2DPWriter.cpp
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "FMA2DPWriter"
+#include <utils/Log.h>
+
+
+#include <media/stagefright/FMA2DPWriter.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/mediarecorder.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+
+#include <media/AudioRecord.h>
+#include <media/AudioTrack.h>
+namespace android {
+
+#define BUFFER_POOL_SIZE 5
+static int kMaxBufferSize = 2048;
+
+FMA2DPWriter::FMA2DPWriter()
+ :mStarted(false),
+ mAudioChannels(0),
+ mSampleRate(0),
+ mAudioFormat(AUDIO_FORMAT_PCM_16_BIT),
+ mAudioSource(AUDIO_SOURCE_FM_RX_A2DP),
+ mBufferSize(0){
+ sem_init(&mReaderThreadWakeupsem,0,0);
+ sem_init(&mWriterThreadWakeupsem,0,0);
+}
+
+
+
+FMA2DPWriter::~FMA2DPWriter() {
+ if (mStarted) {
+ stop();
+ }
+ sem_destroy(&mReaderThreadWakeupsem);
+ sem_destroy(&mWriterThreadWakeupsem);
+}
+
+status_t FMA2DPWriter::initCheck() const {
+// API not need for FMA2DPWriter
+ return OK;
+}
+
+
+status_t FMA2DPWriter::addSource(const sp<MediaSource> &source) {
+// API not need for FMA2DPWriter
+ return OK;
+}
+
+status_t FMA2DPWriter::allocateBufferPool()
+{
+ Mutex::Autolock lock(mFreeQLock);
+
+ for (int i = 0; i < BUFFER_POOL_SIZE; ++i) {
+ int *buffer = (int*)malloc(mBufferSize);
+ if(buffer){
+ audioBufferstruct audioBuffer(buffer,mBufferSize);
+ mFreeQ.push_back(audioBuffer);
+ }
+ else{
+ ALOGE("fatal:failed to alloate buffer pool");
+ return NO_INIT;
+ }
+ }
+ return OK;
+}
+
+status_t FMA2DPWriter::start(MetaData *params) {
+
+ if (mStarted) {
+ // Already started, does nothing
+ return OK;
+ }
+
+ if(!mStarted){
+ if(!params){
+ ALOGE("fatal:params cannot be null");
+ return NO_INIT;
+ }
+ CHECK( params->findInt32( kKeyChannelCount, &mAudioChannels ) );
+ CHECK(mAudioChannels == 1 || mAudioChannels == 2);
+ CHECK( params->findInt32( kKeySampleRate, &mSampleRate ) );
+
+ if ( NO_ERROR != AudioSystem::getInputBufferSize(
+ mSampleRate, mAudioFormat, mAudioChannels, &mBufferSize) ){
+ mBufferSize = kMaxBufferSize ;
+ }
+ ALOGV("mBufferSize = %d", mBufferSize);
+ }
+
+ status_t err = allocateBufferPool();
+
+ if(err != OK)
+ return err;
+
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+ mDone = false;
+
+ pthread_create(&mReaderThread, &attr, ReaderThreadWrapper, this);
+ pthread_create(&mWriterThread, &attr, WriterThreadWrapper, this);
+
+ pthread_attr_destroy(&attr);
+
+
+ mStarted = true;
+
+ return OK;
+}
+
+status_t FMA2DPWriter::pause() {
+// API not need for FMA2DPWriter
+ return OK;
+}
+
+status_t FMA2DPWriter::stop() {
+ if (!mStarted) {
+ return OK;
+ }
+
+ mDone = true;
+
+ void *dummy;
+ pthread_join(mReaderThread, &dummy);
+ pthread_join(mWriterThread, &dummy);
+
+ for ( List<audioBufferstruct>::iterator it = mDataQ.begin();
+ it != mDataQ.end(); ++it){
+ free(it->audioBuffer);
+ }
+ for ( List<audioBufferstruct>::iterator it = mFreeQ.begin();
+ it != mFreeQ.end(); ++it){
+ free(it->audioBuffer);
+ }
+ mStarted = false;
+
+ return OK;
+}
+
+void *FMA2DPWriter::ReaderThreadWrapper(void *me) {
+ return (void *) static_cast<FMA2DPWriter *>(me)->readerthread();
+}
+
+void *FMA2DPWriter::WriterThreadWrapper(void *me) {
+ return (void *) static_cast<FMA2DPWriter *>(me)->writerthread();
+}
+
+status_t FMA2DPWriter::readerthread() {
+ status_t err = OK;
+ int framecount =((4*mBufferSize)/mAudioChannels)/sizeof(int16_t);
+ //sizeof(int16_t) is frame size for PCM stream
+ int inChannel =
+ (mAudioChannels == 2) ? AUDIO_CHANNEL_IN_STEREO :
+ AUDIO_CHANNEL_IN_MONO;
+
+ prctl(PR_SET_NAME, (unsigned long)"FMA2DPReaderThread", 0, 0, 0);
+
+ AudioRecord* record = new AudioRecord(
+ mAudioSource,
+ mSampleRate,
+ mAudioFormat,
+ inChannel,
+ framecount);
+ if(!record){
+ ALOGE("fatal:Not able to open audiorecord");
+ return UNKNOWN_ERROR;
+ }
+
+ status_t res = record->initCheck();
+ if (res == NO_ERROR)
+ res = record->start();
+ else{
+ ALOGE("fatal:record init check failure");
+ return UNKNOWN_ERROR;
+ }
+
+
+ while (!mDone) {
+
+ mFreeQLock.lock();
+ if(mFreeQ.empty()){
+ mFreeQLock.unlock();
+ ALOGV("FreeQ empty");
+ sem_wait(&mReaderThreadWakeupsem);
+ ALOGV("FreeQ filled up");
+ continue;
+ }
+ List<audioBufferstruct>::iterator it = mFreeQ.begin();
+ audioBufferstruct buff ( it->audioBuffer,it->bufferlen);
+ mFreeQ.erase(it);
+ mFreeQLock.unlock();
+
+ buff.bufferlen = record->read(buff.audioBuffer, mBufferSize);
+ ALOGV("read %d bytes", buff.bufferlen);
+ if (buff.bufferlen <= 0){
+ ALOGE("error in reading from audiorecord..bailing out.");
+ this ->notify(MEDIA_RECORDER_EVENT_ERROR, MEDIA_RECORDER_ERROR_UNKNOWN,
+ ERROR_MALFORMED);
+ err = INVALID_OPERATION ;
+ break;
+ }
+
+ mDataQLock.lock();
+ if(mDataQ.empty()){
+ ALOGV("waking up reader");
+ sem_post(&mWriterThreadWakeupsem);
+ }
+ mDataQ.push_back(buff);
+ mDataQLock.unlock();
+ }
+ record->stop();
+ delete record;
+
+ return err;
+}
+
+
+status_t FMA2DPWriter::writerthread(){
+ status_t err = OK;
+ int framecount =(16*mBufferSize)/sizeof(int16_t);
+ //sizeof(int16_t) is frame size for PCM stream
+ int outChannel = (mAudioChannels== 2) ? AUDIO_CHANNEL_OUT_STEREO :
+ AUDIO_CHANNEL_OUT_MONO;
+
+ prctl(PR_SET_NAME, (unsigned long)"FMA2DPWriterThread", 0, 0, 0);
+
+ AudioTrack *audioTrack= new AudioTrack(
+ AUDIO_STREAM_FM,
+ mSampleRate,
+ mAudioFormat,
+ outChannel,
+ framecount, 0);
+
+ if(!audioTrack){
+ ALOGE("fatal:Not able to open audiotrack");
+ return UNKNOWN_ERROR;
+ }
+ status_t res = audioTrack->initCheck();
+ if (res == NO_ERROR) {
+ audioTrack->setVolume(1, 1);
+ audioTrack->start();
+ }
+ else{
+ ALOGE("fatal:audiotrack init check failure");
+ return UNKNOWN_ERROR;
+ }
+
+
+ while (!mDone) {
+
+ mDataQLock.lock();
+ if(mDataQ.empty()){
+ mDataQLock.unlock();
+ ALOGV("dataQ empty");
+ sem_wait(&mWriterThreadWakeupsem);
+ ALOGV("dataQ filled up");
+ continue;
+ }
+ List<audioBufferstruct>::iterator it = mDataQ.begin();
+ audioBufferstruct buff ( it->audioBuffer,it->bufferlen);
+ mDataQ.erase(it);
+ mDataQLock.unlock();
+
+ size_t retval = audioTrack->write(buff.audioBuffer, buff.bufferlen);
+ if(!retval){
+ ALOGE("audio track write failure..bailing out");
+ this ->notify(MEDIA_RECORDER_EVENT_ERROR, MEDIA_RECORDER_ERROR_UNKNOWN,
+ ERROR_MALFORMED);
+ err = INVALID_OPERATION ;
+ break;
+ }
+ ALOGV("wrote %d bytes", buff.bufferlen);
+
+ mFreeQLock.lock();
+ if(mFreeQ.empty()){
+ ALOGV("WAKING UP READER");
+ sem_post(&mReaderThreadWakeupsem);
+ }
+ mFreeQ.push_back(buff);
+ mFreeQLock.unlock();
+ }
+ audioTrack->stop();
+ delete audioTrack;
+
+ return err;
+}
+
+bool FMA2DPWriter::reachedEOS() {
+// API not need for FMA2DPWriter
+ return OK;
+}
+
+
+} // namespace android
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 5975b62..88da88c 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1,9 +1,8 @@
/*
**
** Copyright 2007, The Android Open Source Project
-** Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+** Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
**
-** Copyright (c) 2012, The Linux Foundation. All rights reserved.
** Not a Contribution, Apache license notifications and license are retained
** for attribution purposes only.
**
@@ -1377,6 +1376,29 @@ status_t AudioFlinger::getRenderPosition(uint32_t *halFrames, uint32_t *dspFrame
return BAD_VALUE;
}
+#ifdef QCOM_FM_ENABLED
+status_t AudioFlinger::setFmVolume(float value)
+{
+ status_t ret = initCheck();
+ if (ret != NO_ERROR) {
+ return ret;
+ }
+
+ // check calling permissions
+ if (!settingsAllowed()) {
+ return PERMISSION_DENIED;
+ }
+
+ AutoMutex lock(mHardwareLock);
+ audio_hw_device_t *dev = mPrimaryHardwareDev->hwDevice();
+ mHardwareStatus = AUDIO_SET_FM_VOLUME;
+ ret = dev->set_fm_volume(dev, value);
+ mHardwareStatus = AUDIO_HW_IDLE;
+
+ return ret;
+}
+#endif
+
void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client)
{
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index cbda3fe..d6a3815 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -1,7 +1,8 @@
/*
**
** Copyright 2007, The Android Open Source Project
-** Copyright (c) 2012, The Linux Foundation. All rights reserved.
+** Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+**
** Not a Contribution, Apache license notifications and license are retained
** for attribution purposes only.
**
@@ -228,6 +229,10 @@ public:
virtual status_t moveEffects(int sessionId, audio_io_handle_t srcOutput,
audio_io_handle_t dstOutput);
+#ifdef QCOM_FM_ENABLED
+ virtual status_t setFmVolume(float volume);
+#endif
+
virtual audio_module_handle_t loadHwModule(const char *name);
virtual int32_t getPrimaryOutputSamplingRate();
@@ -2209,6 +2214,9 @@ mutable Mutex mLock; // mutex for process, commands and handl
AUDIO_HW_SET_MIC_MUTE, // set_mic_mute
AUDIO_HW_SET_VOICE_VOLUME, // set_voice_volume
AUDIO_HW_SET_PARAMETER, // set_parameters
+#ifdef QCOM_FM_ENABLED
+ AUDIO_SET_FM_VOLUME,
+#endif
AUDIO_HW_GET_INPUT_BUFFER_SIZE, // get_input_buffer_size
AUDIO_HW_GET_MASTER_VOLUME, // get_master_volume
AUDIO_HW_GET_PARAMETER, // get_parameters
diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp
index 7dd46f2..388ad6c 100644
--- a/services/audioflinger/AudioPolicyService.cpp
+++ b/services/audioflinger/AudioPolicyService.cpp
@@ -1,5 +1,9 @@
/*
* 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.
@@ -730,6 +734,18 @@ bool AudioPolicyService::AudioCommandThread::threadLoop()
}
delete data;
}break;
+#ifdef QCOM_FM_ENABLED
+ case SET_FM_VOLUME: {
+ FmVolumeData *data = (FmVolumeData *)command->mParam;
+ ALOGV("AudioCommandThread() processing set fm volume volume %f", data->mVolume);
+ command->mStatus = AudioSystem::setFmVolume(data->mVolume);
+ if (command->mWaitStatus) {
+ command->mCond.signal();
+ mWaitWorkCV.wait(mLock);
+ }
+ delete data;
+ }break;
+#endif
default:
ALOGW("AudioCommandThread() unknown command %d", command->mCommand);
}
@@ -885,6 +901,34 @@ status_t AudioPolicyService::AudioCommandThread::voiceVolumeCommand(float volume
return status;
}
+#ifdef QCOM_FM_ENABLED
+status_t AudioPolicyService::AudioCommandThread::fmVolumeCommand(float volume, int delayMs)
+{
+ status_t status = NO_ERROR;
+
+ AudioCommand *command = new AudioCommand();
+ command->mCommand = SET_FM_VOLUME;
+ FmVolumeData *data = new FmVolumeData();
+ data->mVolume = volume;
+ command->mParam = data;
+ if (delayMs == 0) {
+ command->mWaitStatus = true;
+ } else {
+ command->mWaitStatus = false;
+ }
+ Mutex::Autolock _l(mLock);
+ insertCommand_l(command, delayMs);
+ ALOGV("AudioCommandThread() adding set fm volume volume %f", volume);
+ mWaitWorkCV.signal();
+ if (command->mWaitStatus) {
+ command->mCond.wait(mLock);
+ status = command->mStatus;
+ mWaitWorkCV.signal();
+ }
+ return status;
+}
+#endif
+
// insertCommand_l() must be called with mLock held
void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *command, int delayMs)
{
@@ -950,6 +994,12 @@ void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *comma
removedCommands.add(command2);
time = command2->mTime;
} break;
+#ifdef QCOM_FM_ENABLED
+ case SET_FM_VOLUME: {
+ removedCommands.add(command2);
+ time = command2->mTime;
+ } break;
+#endif
case START_TONE:
case STOP_TONE:
default:
@@ -1026,6 +1076,13 @@ int AudioPolicyService::setStreamVolume(audio_stream_type_t stream,
output, delayMs);
}
+#ifdef QCOM_FM_ENABLED
+status_t AudioPolicyService::setFmVolume(float volume, int delayMs)
+{
+ return mAudioCommandThread->fmVolumeCommand(volume, delayMs);
+}
+#endif
+
int AudioPolicyService::startTone(audio_policy_tone_t tone,
audio_stream_type_t stream)
{
@@ -1546,6 +1603,15 @@ static int aps_set_voice_volume(void *service, float volume, int delay_ms)
return audioPolicyService->setVoiceVolume(volume, delay_ms);
}
+#ifdef QCOM_FM_ENABLED
+static int aps_set_fm_volume(void *service, float volume, int delay_ms)
+{
+ AudioPolicyService *audioPolicyService = (AudioPolicyService *)service;
+
+ return audioPolicyService->setFmVolume(volume, delay_ms);
+}
+#endif
+
}; // extern "C"
namespace {
@@ -1565,6 +1631,9 @@ namespace {
stop_tone : aps_stop_tone,
set_voice_volume : aps_set_voice_volume,
move_effects : aps_move_effects,
+#ifdef QCOM_FM_ENABLED
+ set_fm_volume : aps_set_fm_volume,
+#endif
load_hw_module : aps_load_hw_module,
open_output_on_module : aps_open_output_on_module,
open_input_on_module : aps_open_input_on_module,
diff --git a/services/audioflinger/AudioPolicyService.h b/services/audioflinger/AudioPolicyService.h
index 63f9549..1176411 100644
--- a/services/audioflinger/AudioPolicyService.h
+++ b/services/audioflinger/AudioPolicyService.h
@@ -1,5 +1,9 @@
/*
* 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.
@@ -134,6 +138,9 @@ public:
virtual status_t startTone(audio_policy_tone_t tone, audio_stream_type_t stream);
virtual status_t stopTone();
virtual status_t setVoiceVolume(float volume, int delayMs = 0);
+#ifdef QCOM_FM_ENABLED
+ virtual status_t setFmVolume(float volume, int delayMs = 0);
+#endif
private:
AudioPolicyService();
@@ -157,7 +164,10 @@ private:
STOP_TONE,
SET_VOLUME,
SET_PARAMETERS,
- SET_VOICE_VOLUME
+ SET_VOICE_VOLUME,
+#ifdef QCOM_FM_ENABLED
+ SET_FM_VOLUME
+#endif
};
AudioCommandThread (String8 name);
@@ -178,6 +188,9 @@ private:
status_t parametersCommand(audio_io_handle_t ioHandle,
const char *keyValuePairs, int delayMs = 0);
status_t voiceVolumeCommand(float volume, int delayMs = 0);
+#ifdef QCOM_FM_ENABLED
+ status_t fmVolumeCommand(float volume, int delayMs = 0);
+#endif
void insertCommand_l(AudioCommand *command, int delayMs = 0);
private:
@@ -222,6 +235,13 @@ private:
float mVolume;
};
+#ifdef QCOM_FM_ENABLED
+ class FmVolumeData {
+ public:
+ float mVolume;
+ };
+#endif
+
Mutex mLock;
Condition mWaitWorkCV;
Vector <AudioCommand *> mAudioCommands; // list of pending commands