diff options
Diffstat (limited to 'services')
-rw-r--r-- | services/audioflinger/Android.mk | 4 | ||||
-rw-r--r-- | services/audioflinger/AudioFlinger.cpp | 935 | ||||
-rw-r--r-- | services/audioflinger/AudioFlinger.h | 215 | ||||
-rw-r--r-- | services/audioflinger/AudioMixer.cpp | 4 | ||||
-rw-r--r-- | services/audioflinger/AudioPolicyService.cpp | 11 | ||||
-rw-r--r-- | services/camera/libcameraservice/Camera2Client.cpp | 2 | ||||
-rw-r--r-- | services/camera/libcameraservice/CameraClient.cpp | 75 | ||||
-rw-r--r-- | services/camera/libcameraservice/CameraClient.h | 3 | ||||
-rw-r--r-- | services/camera/libcameraservice/CameraHardwareInterface.h | 16 | ||||
-rw-r--r-- | services/camera/libcameraservice/CameraService.cpp | 15 | ||||
-rw-r--r-- | services/camera/libcameraservice/CameraService.h | 4 |
11 files changed, 1236 insertions, 48 deletions
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk index 2899953..a14c205 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 1913b6f..bcb9756 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -1,6 +1,11 @@ /* ** ** Copyright 2007, The Android Open Source Project +** Copyright (c) 2011-2012, 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. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -100,6 +105,11 @@ #define ALOGVV(a...) do { } while(0) #endif +#ifdef QCOM_HARDWARE +#define DIRECT_TRACK_EOS 1 +static const char lockName[] = "DirectTrack"; +#endif + namespace android { static const char kDeadlockedString[] = "AudioFlinger may be deadlocked\n"; @@ -206,11 +216,13 @@ static int load_audio_interface(const char *if_name, audio_hw_device_t **dev) if (rc) { goto out; } +#if !defined(ICS_AUDIO_BLOB) && !defined(MR0_AUDIO_BLOB) if ((*dev)->common.version != AUDIO_DEVICE_API_VERSION_CURRENT) { ALOGE("%s wrong audio hw device version %04x", __func__, (*dev)->common.version); rc = BAD_VALUE; goto out; } +#endif return 0; out: @@ -218,6 +230,14 @@ out: return rc; } +static uint32_t getInputChannelCount(uint32_t channels) { +#ifdef QCOM_HARDWARE + // only mono or stereo and 5.1 are supported for input sources + return popcount((channels) & (AUDIO_CHANNEL_IN_STEREO | AUDIO_CHANNEL_IN_MONO | AUDIO_CHANNEL_IN_5POINT1)); +#else + return popcount(channels); +#endif +} // ---------------------------------------------------------------------------- AudioFlinger::AudioFlinger() @@ -235,10 +255,18 @@ AudioFlinger::AudioFlinger() void AudioFlinger::onFirstRef() { int rc = 0; +#ifdef QCOM_HARDWARE + mA2DPHandle = -1; +#endif Mutex::Autolock _l(mLock); /* TODO: move all this work into an Init() function */ +#ifdef QCOM_HARDWARE + mLPASessionId = -2; // -2 is invalid session ID + mIsEffectConfigChanged = false; + mLPAEffectChain = NULL; +#endif char val_str[PROPERTY_VALUE_MAX] = { 0 }; if (property_get("ro.audio.flinger_standbytime_ms", val_str, NULL) >= 0) { uint32_t int_val; @@ -298,6 +326,13 @@ AudioFlinger::AudioHwDevice* AudioFlinger::findSuitableHwDev_l( if ((dev->get_supported_devices != NULL) && (dev->get_supported_devices(dev) & devices) == devices) return audioHwDevice; +#ifdef ICS_AUDIO_BLOB + else if (dev->get_supported_devices == NULL && i != 0 && + devices == 0x80) + // Reasonably safe assumption: A non-primary HAL without + // get_supported_devices is a locally-built A2DP binary + return audioHwDevice; +#endif } } else { // check a match for the requested module handle @@ -544,9 +579,218 @@ Exit: return trackHandle; } +#ifdef QCOM_HARDWARE +sp<IDirectTrack> AudioFlinger::createDirectTrack( + pid_t pid, + uint32_t sampleRate, + audio_channel_mask_t channelMask, + audio_io_handle_t output, + int *sessionId, + IDirectTrackClient *client, + audio_stream_type_t streamType, + status_t *status) +{ + *status = NO_ERROR; + status_t lStatus = NO_ERROR; + sp<IDirectTrack> track = NULL; + DirectAudioTrack* directTrack = NULL; + Mutex::Autolock _l(mLock); + + ALOGV("createDirectTrack() sessionId: %d sampleRate %d channelMask %d", + *sessionId, sampleRate, channelMask); + AudioSessionDescriptor *desc = mDirectAudioTracks.valueFor(output); + if(desc == NULL) { + ALOGE("Error: Invalid output (%d) to create direct audio track", output); + lStatus = BAD_VALUE; + goto Exit; + } + desc->mStreamType = streamType; + if (desc->flag & AUDIO_OUTPUT_FLAG_LPA) { + if (sessionId != NULL && *sessionId != AUDIO_SESSION_OUTPUT_MIX) { + for (size_t i = 0; i < mPlaybackThreads.size(); i++) { + sp<PlaybackThread> t = mPlaybackThreads.valueAt(i); + // Check if the session ID is already associated with a track + uint32_t sessions = t->hasAudioSession(*sessionId); + + // check if an effect with same session ID is waiting for a ssession to be created + ALOGV("check if an effect with same session ID is waiting for a ssession to be created"); + if ((mLPAEffectChain == NULL) && (sessions & PlaybackThread::EFFECT_SESSION)) { + // Clear reference to previous effect chain if any + t->mLock.lock(); + ALOGV("getting the LPA effect chain and setting LPA flag to true."); + mLPAEffectChain = t->getEffectChain_l(*sessionId); + t->mLock.unlock(); + } + } + mLPASessionId = *sessionId; + if (mLPAEffectChain != NULL) { + mLPAEffectChain->setLPAFlag(true); + // For LPA, the volume will be applied in DSP. No need for volume + // control in the Effect chain, so setting it to unity. + uint32_t volume = 0x1000000; // Equals to 1.0 in 8.24 format + mLPAEffectChain->setVolume_l(&volume,&volume); + } else { + ALOGW("There was no effectChain created for the sessionId(%d)", mLPASessionId); + } + mLPASampleRate = sampleRate; + mLPANumChannels = popcount(channelMask); + } else { + if(sessionId != NULL) { + ALOGE("Error: Invalid sessionID (%d) for direct audio track", *sessionId); + } + } + } + mLock.unlock(); + directTrack = new DirectAudioTrack(this, output, desc, client, desc->flag); + desc->trackRefPtr = dynamic_cast<void *>(directTrack); + mLock.lock(); + if (directTrack != 0) { + track = dynamic_cast<IDirectTrack *>(directTrack); + AudioEventObserver* obv = dynamic_cast<AudioEventObserver *>(directTrack); + ALOGE("setting observer mOutputDesc track %p, obv %p", track.get(), obv); + desc->stream->set_observer(desc->stream, reinterpret_cast<void *>(obv)); + } else { + lStatus = BAD_VALUE; + } +Exit: + if(lStatus) { + if (track != NULL) { + track.clear(); + } + *status = lStatus; + } + return track; +} + +void AudioFlinger::deleteEffectSession() +{ + Mutex::Autolock _l(mLock); + ALOGV("deleteSession"); + // -2 is invalid session ID + mLPASessionId = -2; + if (mLPAEffectChain != NULL) { + mLPAEffectChain->setLPAFlag(false); + size_t i, numEffects = mLPAEffectChain->getNumEffects(); + for(i = 0; i < numEffects; i++) { + sp<EffectModule> effect = mLPAEffectChain->getEffectFromIndex_l(i); + effect->setInBuffer(mLPAEffectChain->inBuffer()); + if (i == numEffects-1) { + effect->setOutBuffer(mLPAEffectChain->outBuffer()); + } else { + effect->setOutBuffer(mLPAEffectChain->inBuffer()); + } + effect->configure(); + } + mLPAEffectChain.clear(); + mLPAEffectChain = NULL; + } +} + +// ToDo: Should we go ahead with this frameCount? +#define DEAFULT_FRAME_COUNT 1200 +void AudioFlinger::applyEffectsOn(void *token, int16_t *inBuffer, int16_t *outBuffer, int size) +{ + ALOGV("applyEffectsOn: inBuf %p outBuf %p size %d token %p", inBuffer, outBuffer, size, token); + // This might be the first buffer to apply effects after effect config change + // should not skip effects processing + mIsEffectConfigChanged = false; + + volatile size_t numEffects = 0; + if(mLPAEffectChain != NULL) { + numEffects = mLPAEffectChain->getNumEffects(); + } + + if( numEffects > 0) { + size_t i = 0; + int16_t *pIn = inBuffer; + int16_t *pOut = outBuffer; + + int frameCount = size / (sizeof(int16_t) * mLPANumChannels); + + while(frameCount > 0) { + if(mLPAEffectChain == NULL) { + ALOGV("LPA Effect Chain is removed - No effects processing !!"); + numEffects = 0; + break; + } + mLPAEffectChain->lock(); + + numEffects = mLPAEffectChain->getNumEffects(); + if(!numEffects) { + ALOGV("applyEffectsOn: All the effects are removed - nothing to process"); + mLPAEffectChain->unlock(); + break; + } + + int outFrameCount = (frameCount > DEAFULT_FRAME_COUNT ? DEAFULT_FRAME_COUNT: frameCount); + bool isEffectEnabled = false; + for(i = 0; i < numEffects; i++) { + // If effect configuration is changed while applying effects do not process further + if(mIsEffectConfigChanged) { + mLPAEffectChain->unlock(); + ALOGV("applyEffectsOn: mIsEffectConfigChanged is set - no further processing"); + return; + } + sp<EffectModule> effect = mLPAEffectChain->getEffectFromIndex_l(i); + if(effect == NULL) { + ALOGE("getEffectFromIndex_l(%d) returned NULL ptr", i); + mLPAEffectChain->unlock(); + return; + } + if(i == 0) { + // For the first set input and output buffers different + isEffectEnabled = effect->isProcessEnabled(); + effect->setInBuffer(pIn); + effect->setOutBuffer(pOut); + } else { + // For the remaining use previous effect's output buffer as input buffer + effect->setInBuffer(pOut); + effect->setOutBuffer(pOut); + } + // true indicates that it is being applied on LPA output + effect->configure(true, mLPASampleRate, mLPANumChannels, outFrameCount); + } + + if(isEffectEnabled) { + // Clear the output buffer + memset(pOut, 0, (outFrameCount * mLPANumChannels * sizeof(int16_t))); + } else { + // Copy input buffer content to the output buffer + memcpy(pOut, pIn, (outFrameCount * mLPANumChannels * sizeof(int16_t))); + } + + mLPAEffectChain->process_l(); + + mLPAEffectChain->unlock(); + + // Update input and output buffer pointers + pIn += (outFrameCount * mLPANumChannels); + pOut += (outFrameCount * mLPANumChannels); + frameCount -= outFrameCount; + } + } + + if (!numEffects) { + ALOGV("applyEffectsOn: There are no effects to be applied"); + if(inBuffer != outBuffer) { + // No effect applied so just copy input buffer to output buffer + memcpy(outBuffer, inBuffer, size); + } + } +} +#endif + uint32_t AudioFlinger::sampleRate(audio_io_handle_t output) const { Mutex::Autolock _l(mLock); +#ifdef QCOM_HARDWARE + if (!mDirectAudioTracks.isEmpty()) { + AudioSessionDescriptor *desc = mDirectAudioTracks.valueFor(output); + if(desc != NULL) { + return desc->stream->common.get_sample_rate(&desc->stream->common); + } + } +#endif PlaybackThread *thread = checkPlaybackThread_l(output); if (thread == NULL) { ALOGW("sampleRate() unknown thread %d", output); @@ -558,6 +802,12 @@ uint32_t AudioFlinger::sampleRate(audio_io_handle_t output) const int AudioFlinger::channelCount(audio_io_handle_t output) const { Mutex::Autolock _l(mLock); +#ifdef QCOM_HARDWARE + AudioSessionDescriptor *desc = mDirectAudioTracks.valueFor(output); + if(desc != NULL) { + return desc->stream->common.get_channels(&desc->stream->common); + } +#endif PlaybackThread *thread = checkPlaybackThread_l(output); if (thread == NULL) { ALOGW("channelCount() unknown thread %d", output); @@ -580,6 +830,12 @@ audio_format_t AudioFlinger::format(audio_io_handle_t output) const size_t AudioFlinger::frameCount(audio_io_handle_t output) const { Mutex::Autolock _l(mLock); +#ifdef QCOM_HARDWARE + AudioSessionDescriptor *desc = mDirectAudioTracks.valueFor(output); + if(desc != NULL) { + return desc->stream->common.get_buffer_size(&desc->stream->common); + } +#endif PlaybackThread *thread = checkPlaybackThread_l(output); if (thread == NULL) { ALOGW("frameCount() unknown thread %d", output); @@ -613,6 +869,9 @@ status_t AudioFlinger::setMasterVolume(float value) return PERMISSION_DENIED; } +#ifdef QCOM_HARDWARE + mA2DPHandle = -1; +#endif Mutex::Autolock _l(mLock); mMasterVolume = value; @@ -724,6 +983,7 @@ status_t AudioFlinger::setMasterMute(bool muted) mMasterMute = muted; // Set master mute in the HALs which support it. +#ifndef ICS_AUDIO_BLOB for (size_t i = 0; i < mAudioHwDevs.size(); i++) { AutoMutex lock(mHardwareLock); AudioHwDevice *dev = mAudioHwDevs.valueAt(i); @@ -734,6 +994,7 @@ status_t AudioFlinger::setMasterMute(bool muted) } mHardwareStatus = AUDIO_HW_IDLE; } +#endif // Now set the master mute in each playback thread. Playback threads // assigned to HALs which do not have master mute support will apply master @@ -781,12 +1042,35 @@ status_t AudioFlinger::setStreamVolume(audio_stream_type_t stream, float value, } AutoMutex lock(mLock); +#ifdef QCOM_HARDWARE + ALOGV("setStreamVolume stream %d, output %d, value %f",stream, output, value); + AudioSessionDescriptor *desc = NULL; + if (!mDirectAudioTracks.isEmpty()) { + desc = mDirectAudioTracks.valueFor(output); + if (desc != NULL) { + ALOGV("setStreamVolume for mAudioTracks size %d desc %p",mDirectAudioTracks.size(),desc); + if (desc->mStreamType == stream) { + mStreamTypes[stream].volume = value; + desc->stream->set_volume(desc->stream, + desc->mVolumeLeft * mStreamTypes[stream].volume, + desc->mVolumeRight* mStreamTypes[stream].volume); + return NO_ERROR; + } + } + } +#endif PlaybackThread *thread = NULL; if (output) { thread = checkPlaybackThread_l(output); if (thread == NULL) { +#ifdef QCOM_HARDWARE + if (desc != NULL) { + return NO_ERROR; + } +#endif return BAD_VALUE; } + } mStreamTypes[stream].volume = value; @@ -913,6 +1197,26 @@ status_t AudioFlinger::setParameters(audio_io_handle_t ioHandle, const String8& return final_result; } +#ifdef QCOM_HARDWARE + AudioSessionDescriptor *desc = NULL; + if (!mDirectAudioTracks.isEmpty()) { + desc = mDirectAudioTracks.valueFor(ioHandle); + if (desc != NULL) { + ALOGV("setParameters for mAudioTracks size %d desc %p",mDirectAudioTracks.size(),desc); + desc->stream->common.set_parameters(&desc->stream->common, keyValuePairs.string()); + 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 + // hold a strong ref on thread in case closeOutput() or closeInput() is called // and the thread is exited once the lock is released sp<ThreadBase> thread; @@ -925,13 +1229,17 @@ status_t AudioFlinger::setParameters(audio_io_handle_t ioHandle, const String8& // indicate output device change to all input threads for pre processing AudioParameter param = AudioParameter(keyValuePairs); int value; + DefaultKeyedVector< int, sp<RecordThread> > recordThreads = mRecordThreads; + mLock.unlock(); if ((param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) && (value != 0)) { - for (size_t i = 0; i < mRecordThreads.size(); i++) { - mRecordThreads.valueAt(i)->setParameters(keyValuePairs); + for (size_t i = 0; i < recordThreads.size(); i++) { + recordThreads.valueAt(i)->setParameters(keyValuePairs); } } + mLock.lock(); } + mLock.unlock(); } if (thread != 0) { return thread->setParameters(keyValuePairs); @@ -991,7 +1299,11 @@ size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, audio_format_t form format: format, }; audio_hw_device_t *dev = mPrimaryHardwareDev->hwDevice(); +#ifndef ICS_AUDIO_BLOB size_t size = dev->get_input_buffer_size(dev, &config); +#else + size_t size = dev->get_input_buffer_size(dev, sampleRate, format, popcount(channelMask)); +#endif mHardwareStatus = AUDIO_HW_IDLE; return size; } @@ -1048,14 +1360,14 @@ void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client) Mutex::Autolock _l(mLock); - pid_t pid = IPCThreadState::self()->getCallingPid(); - if (mNotificationClients.indexOfKey(pid) < 0) { + sp<IBinder> binder = client->asBinder(); + if (mNotificationClients.indexOfKey(binder) < 0) { sp<NotificationClient> notificationClient = new NotificationClient(this, client, - pid); - ALOGV("registerClient() client %p, pid %d", notificationClient.get(), pid); + binder); + ALOGV("registerClient() client %p, binder %d", notificationClient.get(), binder.get()); - mNotificationClients.add(pid, notificationClient); + mNotificationClients.add(binder, notificationClient); sp<IBinder> binder = client->asBinder(); binder->linkToDeath(notificationClient); @@ -1070,14 +1382,39 @@ void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client) mRecordThreads.valueAt(i)->sendIoConfigEvent(AudioSystem::INPUT_OPENED); } } +#ifdef QCOM_HARDWARE + // Send the notification to the client only once. + if (mA2DPHandle != -1) { + ALOGV("A2DP active. Notifying the registered client"); + client->ioConfigChanged(AudioSystem::A2DP_OUTPUT_STATE, mA2DPHandle, &mA2DPHandle); + } +#endif } -void AudioFlinger::removeNotificationClient(pid_t pid) +#ifdef QCOM_HARDWARE +status_t AudioFlinger::deregisterClient(const sp<IAudioFlingerClient>& client) { + ALOGV("deregisterClient() %p, tid %d, calling tid %d", client.get(), gettid(), IPCThreadState::self()->getCallingPid()); Mutex::Autolock _l(mLock); - mNotificationClients.removeItem(pid); + sp<IBinder> binder = client->asBinder(); + int index = mNotificationClients.indexOfKey(binder); + if (index >= 0) { + mNotificationClients.removeItemsAt(index); + return true; + } + return false; +} +#endif + +void AudioFlinger::removeNotificationClient(sp<IBinder> binder) +{ + Mutex::Autolock _l(mLock); + + mNotificationClients.removeItem(binder); + + int pid = IPCThreadState::self()->getCallingPid(); ALOGV("%d died, releasing its sessions", pid); size_t num = mAudioSessionRefs.size(); bool removed = false; @@ -1102,6 +1439,12 @@ void AudioFlinger::removeNotificationClient(pid_t pid) // audioConfigChanged_l() must be called with AudioFlinger::mLock held void AudioFlinger::audioConfigChanged_l(int event, audio_io_handle_t ioHandle, const void *param2) { +#ifdef QCOM_HARDWARE + ALOGV("AudioFlinger::audioConfigChanged_l: event %d", event); + if (event == AudioSystem::EFFECT_CONFIG_CHANGED) { + mIsEffectConfigChanged = true; + } +#endif size_t size = mNotificationClients.size(); for (size_t i = 0; i < size; i++) { mNotificationClients.valueAt(i)->audioFlingerClient()->ioConfigChanged(event, ioHandle, @@ -1204,6 +1547,15 @@ status_t AudioFlinger::ThreadBase::setParameters(const String8& keyValuePairs) return status; } +#ifdef QCOM_HARDWARE +void AudioFlinger::ThreadBase::effectConfigChanged() { + mAudioFlinger->mLock.lock(); + ALOGV("New effect is being added to LPA chain, Notifying LPA Direct Track"); + mAudioFlinger->audioConfigChanged_l(AudioSystem::EFFECT_CONFIG_CHANGED, 0, NULL); + mAudioFlinger->mLock.unlock(); +} +#endif + void AudioFlinger::ThreadBase::sendIoConfigEvent(int event, int param) { Mutex::Autolock _l(mLock); @@ -2652,7 +3004,10 @@ bool AudioFlinger::PlaybackThread::threadLoop() // only process effects if we're going to write if (sleepTime == 0) { for (size_t i = 0; i < effectChains.size(); i ++) { - effectChains[i]->process_l(); +#ifdef QCOM_HARDWARE + if (effectChains[i] != mAudioFlinger->mLPAEffectChain) +#endif + effectChains[i]->process_l(); } } @@ -2844,11 +3199,13 @@ void AudioFlinger::MixerThread::threadLoop_mix() int64_t pts; status_t status = INVALID_OPERATION; +#ifndef ICS_AUDIO_BLOB if (mNormalSink != 0) { status = mNormalSink->getNextWriteTimestamp(&pts); } else { status = mOutputSink->getNextWriteTimestamp(&pts); } +#endif if (status != NO_ERROR) { pts = AudioBufferProvider::kInvalidPTS; @@ -5775,8 +6132,8 @@ void AudioFlinger::Client::releaseTimedTrack() AudioFlinger::NotificationClient::NotificationClient(const sp<AudioFlinger>& audioFlinger, const sp<IAudioFlingerClient>& client, - pid_t pid) - : mAudioFlinger(audioFlinger), mPid(pid), mAudioFlingerClient(client) + sp<IBinder> binder) + : mAudioFlinger(audioFlinger), mBinder(binder), mAudioFlingerClient(client) { } @@ -5787,9 +6144,313 @@ AudioFlinger::NotificationClient::~NotificationClient() void AudioFlinger::NotificationClient::binderDied(const wp<IBinder>& who) { sp<NotificationClient> keep(this); - mAudioFlinger->removeNotificationClient(mPid); + mAudioFlinger->removeNotificationClient(mBinder); +} + +// ---------------------------------------------------------------------------- +#ifdef QCOM_HARDWARE +AudioFlinger::DirectAudioTrack::DirectAudioTrack(const sp<AudioFlinger>& audioFlinger, + int output, AudioSessionDescriptor *outputDesc, + IDirectTrackClient* client, audio_output_flags_t outflag) + : BnDirectTrack(), mIsPaused(false), mAudioFlinger(audioFlinger), mOutput(output), mOutputDesc(outputDesc), + mClient(client), mEffectConfigChanged(false), mKillEffectsThread(false), mFlag(outflag) +{ + if (mFlag & AUDIO_OUTPUT_FLAG_LPA) { + createEffectThread(); + + mAudioFlingerClient = new AudioFlingerDirectTrackClient(this); + mAudioFlinger->registerClient(mAudioFlingerClient); + + allocateBufPool(); + } + mDeathRecipient = new PMDeathRecipient(this); + acquireWakeLock(); +} + +AudioFlinger::DirectAudioTrack::~DirectAudioTrack() { + if (mFlag & AUDIO_OUTPUT_FLAG_LPA) { + requestAndWaitForEffectsThreadExit(); + mAudioFlinger->deregisterClient(mAudioFlingerClient); + mAudioFlinger->deleteEffectSession(); + deallocateBufPool(); + } + AudioSystem::releaseOutput(mOutput); + releaseWakeLock(); + + { + Mutex::Autolock _l(pmLock); + if (mPowerManager != 0) { + sp<IBinder> binder = mPowerManager->asBinder(); + binder->unlinkToDeath(mDeathRecipient); + } + } +} + +status_t AudioFlinger::DirectAudioTrack::start() { + if(mIsPaused) { + mIsPaused = false; + mOutputDesc->stream->start(mOutputDesc->stream); + } + mOutputDesc->mActive = true; + AudioSystem::startOutput(mOutput, (audio_stream_type_t)mOutputDesc->mStreamType); + return NO_ERROR; +} + +void AudioFlinger::DirectAudioTrack::stop() { + mOutputDesc->mActive = false; + mOutputDesc->stream->stop(mOutputDesc->stream); + AudioSystem::stopOutput(mOutput, (audio_stream_type_t)mOutputDesc->mStreamType); +} + +void AudioFlinger::DirectAudioTrack::pause() { + if(!mIsPaused) { + mIsPaused = true; + mOutputDesc->stream->pause(mOutputDesc->stream); + mOutputDesc->mActive = false; + AudioSystem::stopOutput(mOutput, (audio_stream_type_t)mOutputDesc->mStreamType); + } +} + +ssize_t AudioFlinger::DirectAudioTrack::write(const void *buffer, size_t size) { + ALOGV("Writing to AudioSessionOut"); + int isAvail = 0; + mOutputDesc->stream->is_buffer_available(mOutputDesc->stream, &isAvail); + if (!isAvail) { + return 0; + } + + if (mFlag & AUDIO_OUTPUT_FLAG_LPA) { + mEffectLock.lock(); + List<BufferInfo>::iterator it = mEffectsPool.begin(); + BufferInfo buf = *it; + mEffectsPool.erase(it); + memcpy((char *) buf.localBuf, (char *)buffer, size); + buf.bytesToWrite = size; + mEffectsPool.push_back(buf); + mAudioFlinger->applyEffectsOn(static_cast<void *>(this), (int16_t*)buf.localBuf,(int16_t*)buffer,(int)size); + mEffectLock.unlock(); + } + return mOutputDesc->stream->write(mOutputDesc->stream, buffer, size); +} + +void AudioFlinger::DirectAudioTrack::flush() { + if (mFlag & AUDIO_OUTPUT_FLAG_LPA) { + mEffectsPool.clear(); + mEffectsPool = mBufPool; + } + mOutputDesc->stream->flush(mOutputDesc->stream); +} + +void AudioFlinger::DirectAudioTrack::mute(bool muted) { } +void AudioFlinger::DirectAudioTrack::setVolume(float left, float right) { + mOutputDesc->mVolumeLeft = left; + mOutputDesc->mVolumeRight = right; +} + +int64_t AudioFlinger::DirectAudioTrack::getTimeStamp() { + int64_t time; + mOutputDesc->stream->get_next_write_timestamp(mOutputDesc->stream, &time); + ALOGV("Timestamp %lld",time); + return time; +} + +void AudioFlinger::DirectAudioTrack::postEOS(int64_t delayUs) { + ALOGV("Notify Audio Track of EOS event"); + mClient->notify(DIRECT_TRACK_EOS); +} + +void AudioFlinger::DirectAudioTrack::allocateBufPool() { + void *dsp_buf = NULL; + void *local_buf = NULL; + + //1. get the ion buffer information + struct buf_info* buf = NULL; + mOutputDesc->stream->get_buffer_info(mOutputDesc->stream, &buf); + ALOGV("get buffer info %p",buf); + if (!buf) { + ALOGV("buffer is NULL"); + return; + } + int nSize = buf->bufsize; + int bufferCount = buf->nBufs; + + //2. allocate the buffer pool, allocate local buffers + for (int i = 0; i < bufferCount; i++) { + dsp_buf = (void *)buf->buffers[i]; + local_buf = malloc(nSize); + memset(local_buf, 0, nSize); + // Store this information for internal mapping / maintanence + BufferInfo buf(local_buf, dsp_buf, nSize); + buf.bytesToWrite = 0; + mBufPool.push_back(buf); + mEffectsPool.push_back(buf); + + ALOGV("The MEM that is allocated buffer is %x, size %d",(unsigned int)dsp_buf,nSize); + } + free(buf); +} + +void AudioFlinger::DirectAudioTrack::deallocateBufPool() { + + //1. Deallocate the local memory + //2. Remove all the buffers from bufpool + while (!mBufPool.empty()) { + List<BufferInfo>::iterator it = mBufPool.begin(); + BufferInfo &memBuffer = *it; + // free the local buffer corresponding to mem buffer + if (memBuffer.localBuf) { + free(memBuffer.localBuf); + memBuffer.localBuf = NULL; + } + ALOGV("Removing from bufpool"); + mBufPool.erase(it); + } +} + +status_t AudioFlinger::DirectAudioTrack::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + return BnDirectTrack::onTransact(code, data, reply, flags); +} + +void *AudioFlinger::DirectAudioTrack::EffectsThreadWrapper(void *me) { + static_cast<DirectAudioTrack *>(me)->EffectsThreadEntry(); + return NULL; +} + +void AudioFlinger::DirectAudioTrack::EffectsThreadEntry() { + while(1) { + mEffectLock.lock(); + if (!mEffectConfigChanged && !mKillEffectsThread) { + mEffectCv.wait(mEffectLock); + } + + if(mKillEffectsThread) { + mEffectLock.unlock(); + break; + } + + if (mEffectConfigChanged) { + mEffectConfigChanged = false; + for ( List<BufferInfo>::iterator it = mEffectsPool.begin(); + it != mEffectsPool.end(); it++) { + ALOGV("Apply effects on the buffer dspbuf %p, mEffectsPool.size() %d",it->dspBuf,mEffectsPool.size()); + mAudioFlinger->applyEffectsOn(static_cast<void *>(this), + (int16_t *)it->localBuf, + (int16_t *)it->dspBuf, + it->bytesToWrite); + if (mEffectConfigChanged) { + break; + } + } + + } + mEffectLock.unlock(); + } + ALOGV("Effects thread is dead"); + mEffectsThreadAlive = false; +} + +void AudioFlinger::DirectAudioTrack::requestAndWaitForEffectsThreadExit() { + if (!mEffectsThreadAlive) + return; + mKillEffectsThread = true; + mEffectCv.signal(); + pthread_join(mEffectsThread,NULL); + ALOGV("effects thread killed"); +} + +void AudioFlinger::DirectAudioTrack::createEffectThread() { + //Create the effects thread + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + mEffectsThreadAlive = true; + ALOGV("Creating Effects Thread"); + pthread_create(&mEffectsThread, &attr, EffectsThreadWrapper, this); +} +AudioFlinger::DirectAudioTrack::AudioFlingerDirectTrackClient::AudioFlingerDirectTrackClient(void *obj) +{ + ALOGV("AudioFlinger::DirectAudioTrack::AudioFlingerDirectTrackClient"); + pBaseClass = (DirectAudioTrack*)obj; +} + +void AudioFlinger::DirectAudioTrack::AudioFlingerDirectTrackClient::binderDied(const wp<IBinder>& who) { + pBaseClass->mAudioFlinger.clear(); + ALOGW("AudioFlinger server died!"); +} + +void AudioFlinger::DirectAudioTrack::AudioFlingerDirectTrackClient + ::ioConfigChanged(int event, audio_io_handle_t ioHandle, const void *param2) { + ALOGV("ioConfigChanged() event %d", event); + if (event == AudioSystem::EFFECT_CONFIG_CHANGED) { + ALOGV("Received notification for change in effect module"); + // Seek to current media time - flush the decoded buffers with the driver + pBaseClass->mEffectConfigChanged = true; + // Signal effects thread to re-apply effects + ALOGV("Signalling Effects Thread"); + pBaseClass->mEffectCv.signal(); + + } + ALOGV("ioConfigChanged Out"); +} + +void AudioFlinger::DirectAudioTrack::acquireWakeLock() +{ + Mutex::Autolock _l(pmLock); + + if (mPowerManager == 0) { + // use checkService() to avoid blocking if power service is not up yet + sp<IBinder> binder = + defaultServiceManager()->checkService(String16("power")); + if (binder == 0) { + ALOGW("Thread %s cannot connect to the power manager service", lockName); + } else { + mPowerManager = interface_cast<IPowerManager>(binder); + binder->linkToDeath(mDeathRecipient); + } + } + if (mPowerManager != 0 && mWakeLockToken == 0) { + sp<IBinder> binder = new BBinder(); + status_t status = mPowerManager->acquireWakeLock(POWERMANAGER_PARTIAL_WAKE_LOCK, + binder, + String16(lockName)); + if (status == NO_ERROR) { + mWakeLockToken = binder; + } + ALOGV("acquireWakeLock() status %d", status); + } +} + +void AudioFlinger::DirectAudioTrack::releaseWakeLock() +{ + Mutex::Autolock _l(pmLock); + + if (mWakeLockToken != 0) { + ALOGV("releaseWakeLock()"); + if (mPowerManager != 0) { + mPowerManager->releaseWakeLock(mWakeLockToken, 0); + } + mWakeLockToken.clear(); + } +} + +void AudioFlinger::DirectAudioTrack::clearPowerManager() +{ + releaseWakeLock(); + Mutex::Autolock _l(pmLock); + mPowerManager.clear(); +} + +void AudioFlinger::DirectAudioTrack::PMDeathRecipient::binderDied(const wp<IBinder>& who) +{ + parentClass->clearPowerManager(); + ALOGW("power manager service died !!!"); +} +#endif + // ---------------------------------------------------------------------------- AudioFlinger::TrackHandle::TrackHandle(const sp<AudioFlinger::PlaybackThread::Track>& track) @@ -5992,7 +6653,7 @@ AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger, ThreadBase(audioFlinger, id, AUDIO_DEVICE_NONE, device, RECORD), mInput(input), mResampler(NULL), mRsmpOutBuffer(NULL), mRsmpInBuffer(NULL), // mRsmpInIndex and mInputBytes set by readInputParameters() - mReqChannelCount(popcount(channelMask)), + mReqChannelCount(getInputChannelCount(channelMask)), mReqSampleRate(sampleRate) // mBytesRead is only meaningful while active, and so is cleared in start() // (but might be better to also clear here for dump?) @@ -6607,7 +7268,7 @@ bool AudioFlinger::RecordThread::checkForNewParameters_l() reconfig = true; } if (param.getInt(String8(AudioParameter::keyChannels), value) == NO_ERROR) { - reqChannelCount = popcount(value); + reqChannelCount = getInputChannelCount(value); reconfig = true; } if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) { @@ -6668,7 +7329,7 @@ bool AudioFlinger::RecordThread::checkForNewParameters_l() reqFormat == mInput->stream->common.get_format(&mInput->stream->common) && reqFormat == AUDIO_FORMAT_PCM_16_BIT && ((int)mInput->stream->common.get_sample_rate(&mInput->stream->common) <= (2 * reqSamplingRate)) && - popcount(mInput->stream->common.get_channels(&mInput->stream->common)) <= FCC_2 && + getInputChannelCount(mInput->stream->common.get_channels(&mInput->stream->common)) <= FCC_2 && (reqChannelCount <= FCC_2)) { status = NO_ERROR; } @@ -6739,7 +7400,7 @@ void AudioFlinger::RecordThread::readInputParameters() mSampleRate = mInput->stream->common.get_sample_rate(&mInput->stream->common); mChannelMask = mInput->stream->common.get_channels(&mInput->stream->common); - mChannelCount = (uint16_t)popcount(mChannelMask); + mChannelCount = (uint16_t)getInputChannelCount(mChannelMask); mFormat = mInput->stream->common.get_format(&mInput->stream->common); mFrameSize = audio_stream_frame_size(&mInput->stream->common); mInputBytes = mInput->stream->common.get_buffer_size(&mInput->stream->common); @@ -6877,6 +7538,7 @@ audio_module_handle_t AudioFlinger::loadHwModule_l(const char *name) { // scope for auto-lock pattern AutoMutex lock(mHardwareLock); +#if !defined(ICS_AUDIO_BLOB) && !defined(MR0_AUDIO_BLOB) if (0 == mAudioHwDevs.size()) { mHardwareStatus = AUDIO_HW_GET_MASTER_VOLUME; if (NULL != dev->get_master_volume) { @@ -6894,6 +7556,7 @@ audio_module_handle_t AudioFlinger::loadHwModule_l(const char *name) } } } +#endif mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME; if ((NULL != dev->set_master_volume) && @@ -6902,12 +7565,14 @@ audio_module_handle_t AudioFlinger::loadHwModule_l(const char *name) AudioHwDevice::AHWD_CAN_SET_MASTER_VOLUME); } +#if !defined(ICS_AUDIO_BLOB) && !defined(MR0_AUDIO_BLOB) mHardwareStatus = AUDIO_HW_SET_MASTER_MUTE; if ((NULL != dev->set_master_mute) && (OK == dev->set_master_mute(dev, mMasterMute))) { flags = static_cast<AudioHwDevice::Flags>(flags | AudioHwDevice::AHWD_CAN_SET_MASTER_MUTE); } +#endif mHardwareStatus = AUDIO_HW_IDLE; } @@ -6981,12 +7646,23 @@ audio_io_handle_t AudioFlinger::openOutput(audio_module_handle_t module, mHardwareStatus = AUDIO_HW_OUTPUT_OPEN; +#ifndef ICS_AUDIO_BLOB status = hwDevHal->open_output_stream(hwDevHal, id, *pDevices, (audio_output_flags_t)flags, &config, &outStream); +#else + status = hwDevHal->open_output_stream(hwDevHal, + *pDevices, + (int *)&config.format, + &config.channel_mask, + &config.sample_rate, + &outStream); + uint32_t newflags = flags | AUDIO_OUTPUT_FLAG_PRIMARY; + flags = (audio_output_flags_t)newflags; +#endif mHardwareStatus = AUDIO_HW_IDLE; ALOGV("openOutput() openOutputStream returned output %p, SamplingRate %d, Format %d, Channels %x, status %d", @@ -6998,7 +7674,18 @@ audio_io_handle_t AudioFlinger::openOutput(audio_module_handle_t module, if (status == NO_ERROR && outStream != NULL) { AudioStreamOut *output = new AudioStreamOut(outHwDev, outStream); - +#ifdef QCOM_HARDWARE + if (flags & AUDIO_OUTPUT_FLAG_LPA || flags & AUDIO_OUTPUT_FLAG_TUNNEL ) { + AudioSessionDescriptor *desc = new AudioSessionDescriptor(hwDevHal, outStream, flags); + desc->mActive = true; + //TODO: no stream type + //desc->mStreamType = streamType; + desc->mVolumeLeft = 1.0; + desc->mVolumeRight = 1.0; + desc->device = *pDevices; + mDirectAudioTracks.add(id, desc); + } else +#endif if ((flags & AUDIO_OUTPUT_FLAG_DIRECT) || (config.format != AUDIO_FORMAT_PCM_16_BIT) || (config.channel_mask != AUDIO_CHANNEL_OUT_STEREO)) { @@ -7008,16 +7695,39 @@ audio_io_handle_t AudioFlinger::openOutput(audio_module_handle_t module, thread = new MixerThread(this, output, id, *pDevices); ALOGV("openOutput() created mixer output: ID %d thread %p", id, thread); } - mPlaybackThreads.add(id, thread); +#ifdef QCOM_HARDWARE + if (thread != NULL) +#endif + mPlaybackThreads.add(id, thread); + +#ifdef QCOM_HARDWARE + // if the device is a A2DP, then this is an A2DP Output + if ( true == audio_is_a2dp_device((audio_devices_t) *pDevices) ) + { + mA2DPHandle = id; + ALOGV("A2DP device activated. The handle is set to %d", mA2DPHandle); + } +#endif if (pSamplingRate != NULL) *pSamplingRate = config.sample_rate; if (pFormat != NULL) *pFormat = config.format; if (pChannelMask != NULL) *pChannelMask = config.channel_mask; - if (pLatencyMs != NULL) *pLatencyMs = thread->latency(); - - // notify client processes of the new output creation - thread->audioConfigChanged_l(AudioSystem::OUTPUT_OPENED); - +#ifdef QCOM_HARDWARE + if (thread != NULL) { +#endif + if (pLatencyMs != NULL) *pLatencyMs = thread->latency(); + // notify client processes of the new output creation + thread->audioConfigChanged_l(AudioSystem::OUTPUT_OPENED); +#ifdef QCOM_HARDWARE + } + else { + *pLatencyMs = 0; + if ((flags & AUDIO_OUTPUT_FLAG_LPA) || (flags & AUDIO_OUTPUT_FLAG_TUNNEL)) { + AudioSessionDescriptor *desc = mDirectAudioTracks.valueFor(id); + *pLatencyMs = desc->stream->get_latency(desc->stream); + } + } +#endif // the first primary output opened designates the primary hw device if ((mPrimaryHardwareDev == NULL) && (flags & AUDIO_OUTPUT_FLAG_PRIMARY)) { ALOGI("Using module %d has the primary audio interface", module); @@ -7064,6 +7774,21 @@ status_t AudioFlinger::closeOutput_nonvirtual(audio_io_handle_t output) { // keep strong reference on the playback thread so that // it is not destroyed while exit() is executed +#ifdef QCOM_HARDWARE + AudioSessionDescriptor *desc = mDirectAudioTracks.valueFor(output); + if (desc) { + ALOGV("Closing DirectTrack output %d", output); + desc->mActive = false; + desc->stream->common.standby(&desc->stream->common); + desc->hwDev->close_output_stream(desc->hwDev, desc->stream); + desc->trackRefPtr = NULL; + mDirectAudioTracks.removeItem(output); + audioConfigChanged_l(AudioSystem::OUTPUT_CLOSED, output, NULL); + delete desc; + return NO_ERROR; + } +#endif + sp<PlaybackThread> thread; { Mutex::Autolock _l(mLock); @@ -7084,6 +7809,14 @@ status_t AudioFlinger::closeOutput_nonvirtual(audio_io_handle_t output) } audioConfigChanged_l(AudioSystem::OUTPUT_CLOSED, output, NULL); mPlaybackThreads.removeItem(output); +#ifdef QCOM_HARDWARE + if (mA2DPHandle == output) + { + mA2DPHandle = -1; + ALOGV("A2DP OutputClosed Notifying Client"); + audioConfigChanged_l(AudioSystem::A2DP_OUTPUT_STATE, mA2DPHandle, &mA2DPHandle); + } +#endif } thread->exit(); // The thread entity (active unit of execution) is no longer running here, @@ -7162,8 +7895,16 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module, audio_hw_device_t *inHwHal = inHwDev->hwDevice(); audio_io_handle_t id = nextUniqueId(); +#ifndef ICS_AUDIO_BLOB status = inHwHal->open_input_stream(inHwHal, id, *pDevices, &config, &inStream); +#else + status = inHwHal->open_input_stream(inHwHal, *pDevices, + (int *)&config.format, + &config.channel_mask, + &config.sample_rate, (audio_in_acoustics_t)0, + &inStream); +#endif ALOGV("openInput() openInputStream returned input %p, SamplingRate %d, Format %d, Channels %x, status %d", inStream, config.sample_rate, @@ -7177,10 +7918,18 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module, if (status == BAD_VALUE && reqFormat == config.format && config.format == AUDIO_FORMAT_PCM_16_BIT && (config.sample_rate <= 2 * reqSamplingRate) && - (popcount(config.channel_mask) <= FCC_2) && (popcount(reqChannels) <= FCC_2)) { + (getInputChannelCount(config.channel_mask) <= FCC_2) && (getInputChannelCount(reqChannels) <= FCC_2)) { ALOGV("openInput() reopening with proposed sampling rate and channel mask"); inStream = NULL; +#ifndef ICS_AUDIO_BLOB status = inHwHal->open_input_stream(inHwHal, id, *pDevices, &config, &inStream); +#else + status = inHwHal->open_input_stream(inHwHal, *pDevices, + (int *)&config.format, + &config.channel_mask, + &config.sample_rate, (audio_in_acoustics_t)0, + &inStream); +#endif } if (status == NO_ERROR && inStream != NULL) { @@ -7253,6 +8002,12 @@ status_t AudioFlinger::setStreamOutput(audio_stream_type_t stream, audio_io_hand PlaybackThread *thread = mPlaybackThreads.valueAt(i).get(); thread->invalidateTracks(stream); } +#ifdef QCOM_HARDWARE + if ( mA2DPHandle == output ) { + ALOGV("A2DP Activated and hence notifying the client"); + audioConfigChanged_l(AudioSystem::A2DP_OUTPUT_STATE, mA2DPHandle, &output); + } +#endif return NO_ERROR; } @@ -7792,6 +8547,21 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::ThreadBase::createEffect_l( addEffectChain_l(chain); chain->setStrategy(getStrategyForSession_l(sessionId)); chainCreated = true; +#ifdef QCOM_HARDWARE + if(sessionId == mAudioFlinger->mLPASessionId) { + // Clear reference to previous effect chain if any + if(mAudioFlinger->mLPAEffectChain.get()) { + mAudioFlinger->mLPAEffectChain.clear(); + } + ALOGV("New EffectChain is created for LPA session ID %d", sessionId); + mAudioFlinger->mLPAEffectChain = chain; + chain->setLPAFlag(true); + // For LPA, the volume will be applied in DSP. No need for volume + // control in the Effect chain, so setting it to unity. + uint32_t volume = 0x1000000; // Equals to 1.0 in 8.24 format + chain->setVolume_l(&volume,&volume); + } +#endif } else { effect = chain->getEffectFromDesc_l(desc); } @@ -7822,6 +8592,11 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::ThreadBase::createEffect_l( effect->setDevice(mInDevice); effect->setMode(mAudioFlinger->getMode()); effect->setAudioSource(mAudioSource); +#ifdef QCOM_HARDWARE + if(chain == mAudioFlinger->mLPAEffectChain) { + effect->setLPAFlag(true); + } +#endif } // create effect handle and connect it to effect module handle = new EffectHandle(effect, client, effectClient, priority); @@ -7928,7 +8703,10 @@ void AudioFlinger::ThreadBase::lockEffectChains_l( { effectChains = mEffectChains; for (size_t i = 0; i < mEffectChains.size(); i++) { - mEffectChains[i]->lock(); +#ifdef QCOM_HARDWARE + if (mEffectChains[i] != mAudioFlinger->mLPAEffectChain) +#endif + mEffectChains[i]->lock(); } } @@ -7936,7 +8714,10 @@ void AudioFlinger::ThreadBase::unlockEffectChains( const Vector< sp<AudioFlinger::EffectChain> >& effectChains) { for (size_t i = 0; i < effectChains.size(); i++) { - effectChains[i]->unlock(); +#ifdef QCOM_HARDWARE + if (mEffectChains[i] != mAudioFlinger->mLPAEffectChain) +#endif + effectChains[i]->unlock(); } } @@ -8168,6 +8949,9 @@ AudioFlinger::EffectModule::EffectModule(ThreadBase *thread, // mMaxDisableWaitCnt is set by configure() and not used before then // mDisableWaitCnt is set by process() and updateState() and not used before then mSuspended(false) +#ifdef QCOM_HARDWARE + ,mIsForLPA(false) +#endif { ALOGV("Constructor %p", this); int lStatus; @@ -8293,6 +9077,9 @@ AudioFlinger::EffectHandle *AudioFlinger::EffectModule::controlHandle_l() size_t AudioFlinger::EffectModule::disconnect(EffectHandle *handle, bool unpinIfLast) { +#ifdef QCOM_HARDWARE + setEnabled(false); +#endif ALOGV("disconnect() %p handle %p", this, handle); // keep a strong reference on this EffectModule to avoid calling the // destructor before we exit @@ -8399,8 +9186,19 @@ void AudioFlinger::EffectModule::reset_l() (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_RESET, 0, NULL, 0, NULL); } +#ifndef QCOM_HARDWARE status_t AudioFlinger::EffectModule::configure() { +#else +status_t AudioFlinger::EffectModule::configure(bool isForLPA, int sampleRate, int channelCount, int frameCount) +{ + uint32_t channels; + + // Acquire lock here to make sure that any other thread does not delete + // the effect handle and release the effect module. + Mutex::Autolock _l(mLock); +#endif + if (mEffectInterface == NULL) { return NO_INIT; } @@ -8412,6 +9210,23 @@ status_t AudioFlinger::EffectModule::configure() // TODO: handle configuration of effects replacing track process audio_channel_mask_t channelMask = thread->channelMask(); +#ifdef QCOM_HARDWARE + mIsForLPA = isForLPA; + if(isForLPA) { + if (channelCount == 1) { + channels = AUDIO_CHANNEL_OUT_MONO; + } else { + channels = AUDIO_CHANNEL_OUT_STEREO; + } + ALOGV("%s: LPA ON - channels %d", __func__, channels); + } else { + if (thread->channelCount() == 1) { + channels = AUDIO_CHANNEL_OUT_MONO; + } else { + channels = AUDIO_CHANNEL_OUT_STEREO; + } + } +#endif if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { mConfig.inputCfg.channels = AUDIO_CHANNEL_OUT_MONO; @@ -8421,7 +9236,13 @@ status_t AudioFlinger::EffectModule::configure() mConfig.outputCfg.channels = channelMask; mConfig.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT; mConfig.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT; - mConfig.inputCfg.samplingRate = thread->sampleRate(); +#ifdef QCOM_HARDWARE + if(isForLPA){ + mConfig.inputCfg.samplingRate = sampleRate; + ALOGV("%s: LPA ON - sampleRate %d", __func__, sampleRate); + } else +#endif + mConfig.inputCfg.samplingRate = thread->sampleRate(); mConfig.outputCfg.samplingRate = mConfig.inputCfg.samplingRate; mConfig.inputCfg.bufferProvider.cookie = NULL; mConfig.inputCfg.bufferProvider.getBuffer = NULL; @@ -8446,7 +9267,13 @@ status_t AudioFlinger::EffectModule::configure() } mConfig.inputCfg.mask = EFFECT_CONFIG_ALL; mConfig.outputCfg.mask = EFFECT_CONFIG_ALL; - mConfig.inputCfg.buffer.frameCount = thread->frameCount(); +#ifdef QCOM_HARDWARE + if(isForLPA) { + mConfig.inputCfg.buffer.frameCount = frameCount; + ALOGV("%s: LPA ON - frameCount %d", __func__, frameCount); + } else +#endif + mConfig.inputCfg.buffer.frameCount = thread->frameCount(); mConfig.outputCfg.buffer.frameCount = mConfig.inputCfg.buffer.frameCount; ALOGV("configure() %p thread %p buffer %p framecount %d", @@ -8626,10 +9453,15 @@ status_t AudioFlinger::EffectModule::setEnabled(bool enabled) // must be called with EffectModule::mLock held status_t AudioFlinger::EffectModule::setEnabled_l(bool enabled) { - +#ifdef QCOM_HARDWARE + bool effectStateChanged = false; +#endif ALOGV("setEnabled %p enabled %d", this, enabled); if (enabled != isEnabled()) { +#ifdef QCOM_HARDWARE + effectStateChanged = true; +#endif status_t status = AudioSystem::setEffectEnabled(mId, enabled); if (enabled && status != NO_ERROR) { return status; @@ -8667,6 +9499,16 @@ status_t AudioFlinger::EffectModule::setEnabled_l(bool enabled) } } } +#ifdef QCOM_HARDWARE + /* + Send notification event to LPA Player when an effect for + LPA output is enabled or disabled. + */ + if (effectStateChanged && mIsForLPA) { + sp<ThreadBase> thread = mThread.promote(); + thread->effectConfigChanged(); + } +#endif return NO_ERROR; } @@ -9116,6 +9958,18 @@ status_t AudioFlinger::EffectHandle::command(uint32_t cmdCode, return disable(); } +#ifdef QCOM_HARDWARE + ALOGV("EffectHandle::command: isOnLPA %d", mEffect->isOnLPA()); + if(mEffect->isOnLPA() && + ((cmdCode == EFFECT_CMD_SET_PARAM) || (cmdCode == EFFECT_CMD_SET_PARAM_DEFERRED) || + (cmdCode == EFFECT_CMD_SET_PARAM_COMMIT) || (cmdCode == EFFECT_CMD_SET_DEVICE) || + (cmdCode == EFFECT_CMD_SET_VOLUME) || (cmdCode == EFFECT_CMD_SET_AUDIO_MODE)) ) { + // Notify Direct track for the change in Effect module + // TODO: check if it is required to send mLPAHandle + ALOGV("Notifying Direct Track for the change in effect config"); + mClient->audioFlinger()->audioConfigChanged_l(AudioSystem::EFFECT_CONFIG_CHANGED, 0, NULL); + } +#endif return mEffect->command(cmdCode, cmdSize, pCmdData, replySize, pReplyData); } @@ -9184,6 +10038,9 @@ AudioFlinger::EffectChain::EffectChain(ThreadBase *thread, : mThread(thread), mSessionId(sessionId), mActiveTrackCnt(0), mTrackCnt(0), mTailBufferCount(0), mOwnInBuffer(false), mVolumeCtrlIdx(-1), mLeftVolume(UINT_MAX), mRightVolume(UINT_MAX), mNewLeftVolume(UINT_MAX), mNewRightVolume(UINT_MAX) +#ifdef QCOM_HARDWARE + ,mIsForLPATrack(false) +#endif { mStrategy = AudioSystem::getStrategyForStream(AUDIO_STREAM_MUSIC); if (thread == NULL) { @@ -9228,6 +10085,20 @@ sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromId_l(int return 0; } +#ifdef QCOM_HARDWARE +sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromIndex_l(int idx) +{ + sp<EffectModule> effect = NULL; + if(idx < 0 || idx >= mEffects.size()) { + ALOGE("EffectChain::getEffectFromIndex_l: invalid index %d", idx); + } + if(mEffects.size() > 0){ + effect = mEffects[idx]; + } + return effect; +} +#endif + // getEffectFromType_l() must be called with ThreadBase::mLock held sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromType_l( const effect_uuid_t *type) @@ -9294,7 +10165,11 @@ void AudioFlinger::EffectChain::process_l() } size_t size = mEffects.size(); +#ifdef QCOM_HARDWARE + if (doProcess || isForLPATrack()) { +#else if (doProcess) { +#endif for (size_t i = 0; i < size; i++) { mEffects[i]->process(); } diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index 49e2b2c..dcdc55c 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -1,6 +1,9 @@ /* ** ** 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. @@ -26,6 +29,10 @@ #include <media/IAudioFlinger.h> #include <media/IAudioFlingerClient.h> +#ifdef QCOM_HARDWARE +#include <media/IDirectTrack.h> +#include <media/IDirectTrackClient.h> +#endif #include <media/IAudioTrack.h> #include <media/IAudioRecord.h> #include <media/AudioSystem.h> @@ -52,6 +59,7 @@ #include "AudioWatchdog.h" #include <powermanager/IPowerManager.h> +#include <utils/List.h> namespace android { @@ -99,6 +107,19 @@ public: pid_t tid, int *sessionId, status_t *status); +#ifdef QCOM_HARDWARE + virtual sp<IDirectTrack> createDirectTrack( + pid_t pid, + uint32_t sampleRate, + audio_channel_mask_t channelMask, + audio_io_handle_t output, + int *sessionId, + IDirectTrackClient* client, + audio_stream_type_t streamType, + status_t *status); + + virtual void deleteEffectSession(); +#endif virtual sp<IAudioRecord> openRecord( pid_t pid, @@ -141,7 +162,9 @@ public: virtual String8 getParameters(audio_io_handle_t ioHandle, const String8& keys) const; virtual void registerClient(const sp<IAudioFlingerClient>& client); - +#ifdef QCOM_HARDWARE + virtual status_t deregisterClient(const sp<IAudioFlingerClient>& client); +#endif virtual size_t getInputBufferSize(uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask) const; @@ -216,6 +239,13 @@ public: Parcel* reply, uint32_t flags); +#ifdef QCOM_HARDWARE + void applyEffectsOn(void *token, + int16_t *buffer1, + int16_t *buffer2, + int size); +#endif + // end of IAudioFlinger interface class SyncEvent; @@ -314,7 +344,7 @@ private: public: NotificationClient(const sp<AudioFlinger>& audioFlinger, const sp<IAudioFlingerClient>& client, - pid_t pid); + sp<IBinder> binder); virtual ~NotificationClient(); sp<IAudioFlingerClient> audioFlingerClient() const { return mAudioFlingerClient; } @@ -327,7 +357,7 @@ private: NotificationClient& operator = (const NotificationClient&); const sp<AudioFlinger> mAudioFlinger; - const pid_t mPid; + sp<IBinder> mBinder; const sp<IAudioFlingerClient> mAudioFlingerClient; }; @@ -343,6 +373,9 @@ private: class EffectModule; class EffectHandle; class EffectChain; +#ifdef QCOM_HARDWARE + struct AudioSessionDescriptor; +#endif struct AudioStreamOut; struct AudioStreamIn; @@ -570,6 +603,9 @@ private: virtual status_t setParameters(const String8& keyValuePairs); virtual String8 getParameters(const String8& keys) = 0; virtual void audioConfigChanged_l(int event, int param = 0) = 0; +#ifdef QCOM_HARDWARE + void effectConfigChanged(); +#endif void sendIoConfigEvent(int event, int param = 0); void sendIoConfigEvent_l(int event, int param = 0); void sendPrioConfigEvent_l(pid_t pid, pid_t tid, int32_t prio); @@ -1400,6 +1436,115 @@ private: sp<PlaybackThread> getEffectThread_l(int sessionId, int EffectId); // server side of the client's IAudioTrack +#ifdef QCOM_HARDWARE + class DirectAudioTrack : public android::BnDirectTrack, + public AudioEventObserver + { + public: + DirectAudioTrack(const sp<AudioFlinger>& audioFlinger, + int output, AudioSessionDescriptor *outputDesc, + IDirectTrackClient* client, audio_output_flags_t outflag); + virtual ~DirectAudioTrack(); + virtual status_t start(); + virtual void stop(); + virtual void flush(); + virtual void mute(bool); + virtual void pause(); + virtual ssize_t write(const void *buffer, size_t bytes); + virtual void setVolume(float left, float right); + virtual int64_t getTimeStamp(); + virtual void postEOS(int64_t delayUs); + + virtual status_t onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags); + private: + + IDirectTrackClient* mClient; + AudioSessionDescriptor *mOutputDesc; + int mOutput; + bool mIsPaused; + audio_output_flags_t mFlag; + + class BufferInfo { + public: + BufferInfo(void *buf1, void *buf2, int32_t nSize) : + localBuf(buf1), dspBuf(buf2), memBufsize(nSize) + {} + + void *localBuf; + void *dspBuf; + uint32_t memBufsize; + uint32_t bytesToWrite; + }; + List<BufferInfo> mBufPool; + List<BufferInfo> mEffectsPool; + + void allocateBufPool(); + void deallocateBufPool(); + + //******Effects************* + static void *EffectsThreadWrapper(void *me); + void EffectsThreadEntry(); + // make sure the Effects thread also exited + void requestAndWaitForEffectsThreadExit(); + void createEffectThread(); + Condition mEffectCv; + Mutex mEffectLock; + pthread_t mEffectsThread; + bool mKillEffectsThread; + bool mEffectsThreadAlive; + bool mEffectConfigChanged; + + //Structure to recieve the Effect notification from the flinger. + class AudioFlingerDirectTrackClient: public IBinder::DeathRecipient, public BnAudioFlingerClient { + public: + AudioFlingerDirectTrackClient(void *obj); + + DirectAudioTrack *pBaseClass; + // DeathRecipient + virtual void binderDied(const wp<IBinder>& who); + + // IAudioFlingerClient + + // indicate a change in the configuration of an output or input: keeps the cached + // values for output/input parameters upto date in client process + virtual void ioConfigChanged(int event, audio_io_handle_t ioHandle, const void *param2); + + friend class DirectAudioTrack; + }; + // helper function to obtain AudioFlinger service handle + sp<AudioFlinger> mAudioFlinger; + sp<AudioFlingerDirectTrackClient> mAudioFlingerClient; + + void clearPowerManager(); + class PMDeathRecipient : public IBinder::DeathRecipient { + public: + PMDeathRecipient(void *obj){parentClass = (DirectAudioTrack *)obj;} + virtual ~PMDeathRecipient() {} + + // IBinder::DeathRecipient + virtual void binderDied(const wp<IBinder>& who); + + private: + DirectAudioTrack *parentClass; + PMDeathRecipient(const PMDeathRecipient&); + PMDeathRecipient& operator = (const PMDeathRecipient&); + + friend class DirectAudioTrack; + }; + + friend class PMDeathRecipient; + + Mutex pmLock; + void acquireWakeLock(); + void releaseWakeLock(); + + sp<IPowerManager> mPowerManager; + sp<IBinder> mWakeLockToken; + sp<PMDeathRecipient> mDeathRecipient; + }; +#endif + class TrackHandle : public android::BnAudioTrack { public: TrackHandle(const sp<PlaybackThread::Track>& track); @@ -1424,7 +1569,7 @@ private: }; void removeClient_l(pid_t pid); - void removeNotificationClient(pid_t pid); + void removeNotificationClient(sp<IBinder> binder); // record thread @@ -1636,7 +1781,14 @@ private: void *pReplyData); void reset_l(); +#ifdef QCOM_HARDWARE + status_t configure(bool isForLPA = false, + int sampleRate = 0, + int channelCount = 0, + int frameCount = 0); +#else status_t configure(); +#endif status_t init(); effect_state state() const { return mState; @@ -1683,7 +1835,10 @@ private: bool purgeHandles(); void lock() { mLock.lock(); } void unlock() { mLock.unlock(); } - +#ifdef QCOM_HARDWARE + bool isOnLPA() { return mIsForLPA;} + void setLPAFlag(bool isForLPA) {mIsForLPA = isForLPA; } +#endif void dump(int fd, const Vector<String16>& args); protected: @@ -1715,6 +1870,9 @@ mutable Mutex mLock; // mutex for process, commands and handl // sending disable command. uint32_t mDisableWaitCnt; // current process() calls count during disable period. bool mSuspended; // effect is suspended: temporarily disabled by framework +#ifdef QCOM_HARDWARE + bool mIsForLPA; +#endif }; // The EffectHandle class implements the IEffect interface. It provides resources @@ -1823,12 +1981,18 @@ mutable Mutex mLock; // mutex for process, commands and handl status_t addEffect_l(const sp<EffectModule>& handle); size_t removeEffect_l(const sp<EffectModule>& handle); +#ifdef QCOM_HARDWARE + size_t getNumEffects() { return mEffects.size(); } +#endif int sessionId() const { return mSessionId; } void setSessionId(int sessionId) { mSessionId = sessionId; } sp<EffectModule> getEffectFromDesc_l(effect_descriptor_t *descriptor); sp<EffectModule> getEffectFromId_l(int id); +#ifdef QCOM_HARDWARE + sp<EffectModule> getEffectFromIndex_l(int idx); +#endif sp<EffectModule> getEffectFromType_l(const effect_uuid_t *type); bool setVolume_l(uint32_t *left, uint32_t *right); void setDevice_l(audio_devices_t device); @@ -1874,6 +2038,10 @@ mutable Mutex mLock; // mutex for process, commands and handl void clearInputBuffer(); void dump(int fd, const Vector<String16>& args); +#ifdef QCOM_HARDWARE + bool isForLPATrack() {return mIsForLPATrack; } + void setLPAFlag(bool flag) {mIsForLPATrack = flag;} +#endif protected: friend class AudioFlinger; // for mThread, mEffects @@ -1922,6 +2090,9 @@ mutable Mutex mLock; // mutex for process, commands and handl uint32_t mNewLeftVolume; // new volume on left channel uint32_t mNewRightVolume; // new volume on right channel uint32_t mStrategy; // strategy for this effect chain +#ifdef QCOM_HARDWARE + bool mIsForLPATrack; +#endif // mSuspendedEffects lists all effects currently suspended in the chain. // Use effect type UUID timelow field as key. There is no real risk of identical // timeLow fields among effect type UUIDs. @@ -1983,7 +2154,21 @@ mutable Mutex mLock; // mutex for process, commands and handl AudioStreamIn(AudioHwDevice *dev, audio_stream_in_t *in) : audioHwDev(dev), stream(in) {} }; - +#ifdef QCOM_HARDWARE + struct AudioSessionDescriptor { + bool mActive; + int mStreamType; + float mVolumeLeft; + float mVolumeRight; + audio_hw_device_t *hwDev; + audio_stream_out_t *stream; + audio_output_flags_t flag; + void *trackRefPtr; + audio_devices_t device; + AudioSessionDescriptor(audio_hw_device_t *dev, audio_stream_out_t *out, audio_output_flags_t outflag) : + hwDev(dev), stream(out), flag(outflag) {} + }; +#endif // for mAudioSessionRefs only struct AudioSessionRef { AudioSessionRef(int sessionid, pid_t pid) : @@ -2043,14 +2228,26 @@ mutable Mutex mLock; // mutex for process, commands and handl DefaultKeyedVector< audio_io_handle_t, sp<RecordThread> > mRecordThreads; - DefaultKeyedVector< pid_t, sp<NotificationClient> > mNotificationClients; + DefaultKeyedVector< sp<IBinder>, sp<NotificationClient> > mNotificationClients; volatile int32_t mNextUniqueId; // updated by android_atomic_inc audio_mode_t mMode; bool mBtNrecIsOff; - +#ifdef QCOM_HARDWARE + DefaultKeyedVector<audio_io_handle_t, AudioSessionDescriptor *> mDirectAudioTracks; + int mA2DPHandle; // Handle to notify A2DP connection status +#endif // protected by mLock +#ifdef QCOM_HARDWARE + volatile bool mIsEffectConfigChanged; +#endif Vector<AudioSessionRef*> mAudioSessionRefs; - +#ifdef QCOM_HARDWARE + sp<EffectChain> mLPAEffectChain; + int mLPASessionId; + int mLPASampleRate; + int mLPANumChannels; + volatile bool mAllChainsLocked; +#endif float masterVolume_l() const; bool masterMute_l() const; audio_module_handle_t loadHwModule_l(const char *name); diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp index 1e4049a..ab6f38f 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, diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp index 8b99bd2..7dd46f2 100644 --- a/services/audioflinger/AudioPolicyService.cpp +++ b/services/audioflinger/AudioPolicyService.cpp @@ -388,12 +388,16 @@ status_t AudioPolicyService::setStreamVolumeIndex(audio_stream_type_t stream, return BAD_VALUE; } Mutex::Autolock _l(mLock); + +#ifndef ICS_AUDIO_BLOB if (mpAudioPolicy->set_stream_volume_index_for_device) { return mpAudioPolicy->set_stream_volume_index_for_device(mpAudioPolicy, stream, index, device); - } else { + } else +#endif + { return mpAudioPolicy->set_stream_volume_index(mpAudioPolicy, stream, index); } } @@ -409,12 +413,15 @@ status_t AudioPolicyService::getStreamVolumeIndex(audio_stream_type_t stream, return BAD_VALUE; } Mutex::Autolock _l(mLock); +#ifndef ICS_AUDIO_BLOB if (mpAudioPolicy->get_stream_volume_index_for_device) { return mpAudioPolicy->get_stream_volume_index_for_device(mpAudioPolicy, stream, index, device); - } else { + } else +#endif + { return mpAudioPolicy->get_stream_volume_index(mpAudioPolicy, stream, index); } } diff --git a/services/camera/libcameraservice/Camera2Client.cpp b/services/camera/libcameraservice/Camera2Client.cpp index 0f1e650..bddcb8c 100644 --- a/services/camera/libcameraservice/Camera2Client.cpp +++ b/services/camera/libcameraservice/Camera2Client.cpp @@ -1430,11 +1430,13 @@ void Camera2Client::notifyAutoFocus(uint8_t newState, int triggerId) { } } if (sendMovingMessage) { +#ifndef OMAP_ICS_CAMERA SharedCameraClient::Lock l(mSharedCameraClient); if (l.mCameraClient != 0) { l.mCameraClient->notifyCallback(CAMERA_MSG_FOCUS_MOVE, afInMotion ? 1 : 0, 0); } +#endif } if (sendCompletedMessage) { SharedCameraClient::Lock l(mSharedCameraClient); diff --git a/services/camera/libcameraservice/CameraClient.cpp b/services/camera/libcameraservice/CameraClient.cpp index b930c02..1cdb938 100644 --- a/services/camera/libcameraservice/CameraClient.cpp +++ b/services/camera/libcameraservice/CameraClient.cpp @@ -83,8 +83,14 @@ status_t CameraClient::initialize(camera_module_t *module) { (void *)mCameraId); // Enable zoom, error, focus, and metadata messages by default - enableMsgType(CAMERA_MSG_ERROR | CAMERA_MSG_ZOOM | CAMERA_MSG_FOCUS | - CAMERA_MSG_PREVIEW_METADATA | CAMERA_MSG_FOCUS_MOVE); + enableMsgType(CAMERA_MSG_ERROR | CAMERA_MSG_ZOOM | CAMERA_MSG_FOCUS +#ifndef QCOM_HARDWARE + | CAMERA_MSG_PREVIEW_METADATA +#endif +#ifndef OMAP_ICS_CAMERA + | CAMERA_MSG_FOCUS_MOVE +#endif + ); LOG1("CameraClient::initialize X (pid %d, id %d)", callingPid, mCameraId); return OK; @@ -244,9 +250,14 @@ void CameraClient::disconnect() { // Release the held ANativeWindow resources. if (mPreviewWindow != 0) { +#ifdef QCOM_HARDWARE + mHardware->setPreviewWindow(0); +#endif disconnectWindow(mPreviewWindow); mPreviewWindow = 0; +#ifndef QCOM_HARDWARE mHardware->setPreviewWindow(mPreviewWindow); +#endif } mHardware.clear(); @@ -285,6 +296,10 @@ status_t CameraClient::setPreviewWindow(const sp<IBinder>& binder, native_window_set_buffers_transform(window.get(), mOrientation); result = mHardware->setPreviewWindow(window); } +#ifdef QCOM_HARDWARE + } else { + result = mHardware->setPreviewWindow(window); +#endif } if (result == NO_ERROR) { @@ -344,6 +359,9 @@ void CameraClient::setPreviewCallbackFlag(int callback_flag) { // start preview mode status_t CameraClient::startPreview() { LOG1("startPreview (pid %d)", getCallingPid()); +#ifdef QCOM_HARDWARE + enableMsgType(CAMERA_MSG_PREVIEW_METADATA); +#endif return startCameraMode(CAMERA_PREVIEW_MODE); } @@ -393,6 +411,11 @@ status_t CameraClient::startPreviewMode() { native_window_set_buffers_transform(mPreviewWindow.get(), mOrientation); } + +#if defined(OMAP_ICS_CAMERA) || defined(OMAP_ENHANCEMENT_BURST_CAPTURE) + disableMsgType(CAMERA_MSG_COMPRESSED_BURST_IMAGE); +#endif + mHardware->setPreviewWindow(mPreviewWindow); result = mHardware->startPreview(); @@ -429,9 +452,22 @@ status_t CameraClient::startRecordingMode() { // stop preview mode void CameraClient::stopPreview() { LOG1("stopPreview (pid %d)", getCallingPid()); +#ifdef QCOM_HARDWARE + disableMsgType(CAMERA_MSG_PREVIEW_METADATA); +#endif Mutex::Autolock lock(mLock); if (checkPidAndHardware() != NO_ERROR) return; +#ifdef OMAP_ENHANCEMENT + // According to framework documentation, preview needs + // to be started for image capture. This will make sure + // that image capture related messages get disabled if + // not done already in their respective handlers. + // If these messages come when in the midddle of + // stopping preview we will deadlock the system in + // lockIfMessageWanted(). + disableMsgType(CAMERA_MSG_POSTVIEW_FRAME); +#endif disableMsgType(CAMERA_MSG_PREVIEW_FRAME); mHardware->stopPreview(); @@ -527,8 +563,18 @@ status_t CameraClient::takePicture(int msgType) { CAMERA_MSG_POSTVIEW_FRAME | CAMERA_MSG_RAW_IMAGE | CAMERA_MSG_RAW_IMAGE_NOTIFY | +#if defined(OMAP_ICS_CAMERA) || defined(OMAP_ENHANCEMENT_BURST_CAPTURE) + CAMERA_MSG_RAW_BURST | +#endif CAMERA_MSG_COMPRESSED_IMAGE); +#if defined(OMAP_ICS_CAMERA) || defined(OMAP_ENHANCEMENT_BURST_CAPTURE) + picMsgType |= CAMERA_MSG_COMPRESSED_BURST_IMAGE; +#endif + +#ifdef QCOM_HARDWARE + disableMsgType(CAMERA_MSG_PREVIEW_METADATA); +#endif enableMsgType(picMsgType); return mHardware->takePicture(); @@ -687,6 +733,12 @@ void CameraClient::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2, void* user) { LOG2("notifyCallback(%d)", msgType); + // Ignore CAF_RESTART callbacks from Samsung's camera driver + if (msgType == CAMERA_MSG_FOCUS && ext1 == 4) { + LOG2("Ignore CAF_RESTART callback"); + return; + } + Mutex* lock = getClientLockFromCookie(user); if (lock == NULL) return; Mutex::Autolock alock(*lock); @@ -740,6 +792,11 @@ void CameraClient::dataCallback(int32_t msgType, case CAMERA_MSG_COMPRESSED_IMAGE: client->handleCompressedPicture(dataPtr); break; +#if defined(OMAP_ICS_CAMERA) || defined(OMAP_ENHANCEMENT_BURST_CAPTURE) + case CAMERA_MSG_COMPRESSED_BURST_IMAGE: + client->handleCompressedBurstPicture(dataPtr); + break; +#endif default: client->handleGenericData(msgType, dataPtr, metadata); break; @@ -869,6 +926,20 @@ void CameraClient::handleCompressedPicture(const sp<IMemory>& mem) { } } +#if defined(OMAP_ICS_CAMERA) || defined(OMAP_ENHANCEMENT_BURST_CAPTURE) +// burst picture callback - compressed picture ready +void CameraClient::handleCompressedBurstPicture(const sp<IMemory>& mem) { + // Don't disable this message type yet. In this mode takePicture() will + // get called only once. When burst finishes this message will get automatically + // disabled in the respective call for restarting the preview. + + sp<ICameraClient> c = mCameraClient; + mLock.unlock(); + if (c != 0) { + c->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE, mem, NULL); + } +} +#endif void CameraClient::handleGenericNotify(int32_t msgType, int32_t ext1, int32_t ext2) { diff --git a/services/camera/libcameraservice/CameraClient.h b/services/camera/libcameraservice/CameraClient.h index 2f31c4e..9b10706 100644 --- a/services/camera/libcameraservice/CameraClient.h +++ b/services/camera/libcameraservice/CameraClient.h @@ -97,6 +97,9 @@ private: void handlePostview(const sp<IMemory>& mem); void handleRawPicture(const sp<IMemory>& mem); void handleCompressedPicture(const sp<IMemory>& mem); +#if defined(OMAP_ICS_CAMERA) || defined(OMAP_ENHANCEMENT_BURST_CAPTURE) + void handleCompressedBurstPicture(const sp<IMemory>& mem); +#endif void handleGenericNotify(int32_t msgType, int32_t ext1, int32_t ext2); void handleGenericData(int32_t msgType, const sp<IMemory>& dataPtr, camera_frame_metadata_t *metadata); diff --git a/services/camera/libcameraservice/CameraHardwareInterface.h b/services/camera/libcameraservice/CameraHardwareInterface.h index 05ac9fa..d67996e 100644 --- a/services/camera/libcameraservice/CameraHardwareInterface.h +++ b/services/camera/libcameraservice/CameraHardwareInterface.h @@ -113,6 +113,12 @@ public: ALOGV("%s(%s) buf %p", __FUNCTION__, mName.string(), buf.get()); if (mDevice->ops->set_preview_window) { +#ifdef QCOM_HARDWARE + ALOGV("%s buf %p mPreviewWindow %p", __FUNCTION__, buf.get(), mPreviewWindow.get()); + if (mPreviewWindow.get() && (buf.get() != mPreviewWindow.get())) { + mDevice->ops->set_preview_window(mDevice, 0); + } +#endif mPreviewWindow = buf; mHalPreviewWindow.user = this; ALOGV("%s &mHalPreviewWindow %p mHalPreviewWindow.user %p", __FUNCTION__, @@ -456,13 +462,17 @@ private: ALOGV("%s", __FUNCTION__); CameraHardwareInterface *__this = static_cast<CameraHardwareInterface *>(user); - sp<CameraHeapMemory> mem(static_cast<CameraHeapMemory *>(data->handle)); - if (index >= mem->mNumBufs) { + if (data != NULL) { + sp<CameraHeapMemory> mem(static_cast<CameraHeapMemory *>(data->handle)); + if (index >= mem->mNumBufs) { ALOGE("%s: invalid buffer index %d, max allowed is %d", __FUNCTION__, index, mem->mNumBufs); return; + } + __this->mDataCb(msg_type, mem->mBuffers[index], metadata, __this->mCbUser); + } else { + __this->mDataCb(msg_type, NULL, metadata, __this->mCbUser); } - __this->mDataCb(msg_type, mem->mBuffers[index], metadata, __this->mCbUser); } static void __data_cb_timestamp(nsecs_t timestamp, int32_t msg_type, diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index 124d24d..d8365eb 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -37,6 +37,7 @@ #include <utils/Log.h> #include <utils/String16.h> +#include <system/camera.h> #include "CameraService.h" #include "CameraClient.h" #include "Camera2Client.h" @@ -358,8 +359,18 @@ void CameraService::loadSound() { LOG1("CameraService::loadSound ref=%d", mSoundRef); if (mSoundRef++) return; - mSoundPlayer[SOUND_SHUTTER] = newMediaPlayer("/system/media/audio/ui/camera_click.ogg"); - mSoundPlayer[SOUND_RECORDING] = newMediaPlayer("/system/media/audio/ui/VideoRecord.ogg"); + char value[PROPERTY_VALUE_MAX]; + property_get("persist.camera.shutter.disable", value, "0"); + int disableSound = atoi(value); + + if(!disableSound) { + mSoundPlayer[SOUND_SHUTTER] = newMediaPlayer("/system/media/audio/ui/camera_click.ogg"); + mSoundPlayer[SOUND_RECORDING] = newMediaPlayer("/system/media/audio/ui/VideoRecord.ogg"); + } + else { + mSoundPlayer[SOUND_SHUTTER] = NULL; + mSoundPlayer[SOUND_RECORDING] = NULL; + } } void CameraService::releaseSound() { diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h index 4dab340..7844047 100644 --- a/services/camera/libcameraservice/CameraService.h +++ b/services/camera/libcameraservice/CameraService.h @@ -23,7 +23,11 @@ #include <hardware/camera.h> /* This needs to be increased if we can have more cameras */ +#ifdef OMAP_ENHANCEMENT +#define MAX_CAMERAS 3 +#else #define MAX_CAMERAS 2 +#endif namespace android { |