diff options
Diffstat (limited to 'services')
18 files changed, 636 insertions, 264 deletions
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index 93b1642..52fce34 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -181,7 +181,8 @@ AudioFlinger::AudioFlinger() mIsLowRamDevice(true), mIsDeviceTypeKnown(false), mGlobalEffectEnableTime(0), - mPrimaryOutputSampleRate(0) + mPrimaryOutputSampleRate(0), + mSystemReady(false) { getpid_cached = getpid(); char value[PROPERTY_VALUE_MAX]; @@ -1722,6 +1723,26 @@ audio_hw_sync_t AudioFlinger::getAudioHwSyncForSession(audio_session_t sessionId return (audio_hw_sync_t)value; } +status_t AudioFlinger::systemReady() +{ + Mutex::Autolock _l(mLock); + ALOGI("%s", __FUNCTION__); + if (mSystemReady) { + ALOGW("%s called twice", __FUNCTION__); + return NO_ERROR; + } + mSystemReady = true; + for (size_t i = 0; i < mPlaybackThreads.size(); i++) { + ThreadBase *thread = (ThreadBase *)mPlaybackThreads.valueAt(i).get(); + thread->systemReady(); + } + for (size_t i = 0; i < mRecordThreads.size(); i++) { + ThreadBase *thread = (ThreadBase *)mRecordThreads.valueAt(i).get(); + thread->systemReady(); + } + return NO_ERROR; +} + // setAudioHwSyncForSession_l() must be called with AudioFlinger::mLock held void AudioFlinger::setAudioHwSyncForSession_l(PlaybackThread *thread, audio_session_t sessionId) { @@ -1794,15 +1815,15 @@ sp<AudioFlinger::PlaybackThread> AudioFlinger::openOutput_l(audio_module_handle_ PlaybackThread *thread; if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) { - thread = new OffloadThread(this, outputStream, *output, devices); + thread = new OffloadThread(this, outputStream, *output, devices, mSystemReady); ALOGV("openOutput_l() created offload output: ID %d thread %p", *output, thread); } else if ((flags & AUDIO_OUTPUT_FLAG_DIRECT) || !isValidPcmSinkFormat(config->format) || !isValidPcmSinkChannelMask(config->channel_mask)) { - thread = new DirectOutputThread(this, outputStream, *output, devices); + thread = new DirectOutputThread(this, outputStream, *output, devices, mSystemReady); ALOGV("openOutput_l() created direct output: ID %d thread %p", *output, thread); } else { - thread = new MixerThread(this, outputStream, *output, devices); + thread = new MixerThread(this, outputStream, *output, devices, mSystemReady); ALOGV("openOutput_l() created mixer output: ID %d thread %p", *output, thread); } mPlaybackThreads.add(*output, thread); @@ -1873,7 +1894,7 @@ audio_io_handle_t AudioFlinger::openDuplicateOutput(audio_io_handle_t output1, } audio_io_handle_t id = nextUniqueId(); - DuplicatingThread *thread = new DuplicatingThread(this, thread1, id); + DuplicatingThread *thread = new DuplicatingThread(this, thread1, id, mSystemReady); thread->addOutputTrack(thread2); mPlaybackThreads.add(id, thread); // notify client processes of the new output creation @@ -2120,7 +2141,8 @@ sp<AudioFlinger::RecordThread> AudioFlinger::openInput_l(audio_module_handle_t m inputStream, *input, primaryOutputDevice_l(), - devices + devices, + mSystemReady #ifdef TEE_SINK , teeSink #endif diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index 51b2610..d087ced 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -257,6 +257,9 @@ public: /* Get the HW synchronization source used for an audio session */ virtual audio_hw_sync_t getAudioHwSyncForSession(audio_session_t sessionId); + /* Indicate JAVA services are ready (scheduling, power management ...) */ + virtual status_t systemReady(); + virtual status_t onTransact( uint32_t code, const Parcel& data, @@ -356,6 +359,15 @@ private: // check that channelMask is the "canonical" one we expect for the channelCount. return channelMask == audio_channel_out_mask_from_count(channelCount); } + case AUDIO_CHANNEL_REPRESENTATION_INDEX: + if (kEnableExtendedChannels) { + const uint32_t channelCount = audio_channel_count_from_out_mask(channelMask); + if (channelCount >= FCC_2 // mono is not supported at this time + && channelCount <= AudioMixer::MAX_NUM_CHANNELS) { + return true; + } + } + return false; default: return false; } @@ -752,6 +764,7 @@ private: uint32_t mPrimaryOutputSampleRate; // sample rate of the primary output, or zero if none // protected by mHardwareLock + bool mSystemReady; }; #undef INCLUDING_FROM_AUDIOFLINGER_H diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp index 586c737..01efc53 100644 --- a/services/audioflinger/AudioMixer.cpp +++ b/services/audioflinger/AudioMixer.cpp @@ -66,6 +66,13 @@ #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) #endif +// TODO: Move these macro/inlines to a header file. +template <typename T> +static inline +T max(const T& x, const T& y) { + return x > y ? x : y; +} + // Set kUseNewMixer to true to use the new mixer engine always. Otherwise the // original code will be used for stereo sinks, the new mixer for multichannel. static const bool kUseNewMixer = true; @@ -499,41 +506,99 @@ void AudioMixer::disable(int name) static inline bool setVolumeRampVariables(float newVolume, int32_t ramp, int16_t *pIntSetVolume, int32_t *pIntPrevVolume, int32_t *pIntVolumeInc, float *pSetVolume, float *pPrevVolume, float *pVolumeInc) { + // check floating point volume to see if it is identical to the previously + // set volume. + // We do not use a tolerance here (and reject changes too small) + // as it may be confusing to use a different value than the one set. + // If the resulting volume is too small to ramp, it is a direct set of the volume. if (newVolume == *pSetVolume) { return false; } - /* set the floating point volume variables */ - if (ramp != 0) { - *pVolumeInc = (newVolume - *pSetVolume) / ramp; - *pPrevVolume = *pSetVolume; + if (newVolume < 0) { + newVolume = 0; // should not have negative volumes } else { - *pVolumeInc = 0; - *pPrevVolume = newVolume; + switch (fpclassify(newVolume)) { + case FP_SUBNORMAL: + case FP_NAN: + newVolume = 0; + break; + case FP_ZERO: + break; // zero volume is fine + case FP_INFINITE: + // Infinite volume could be handled consistently since + // floating point math saturates at infinities, + // but we limit volume to unity gain float. + // ramp = 0; break; + // + newVolume = AudioMixer::UNITY_GAIN_FLOAT; + break; + case FP_NORMAL: + default: + // Floating point does not have problems with overflow wrap + // that integer has. However, we limit the volume to + // unity gain here. + // TODO: Revisit the volume limitation and perhaps parameterize. + if (newVolume > AudioMixer::UNITY_GAIN_FLOAT) { + newVolume = AudioMixer::UNITY_GAIN_FLOAT; + } + break; + } + } + + // set floating point volume ramp + if (ramp != 0) { + // when the ramp completes, *pPrevVolume is set to *pSetVolume, so there + // is no computational mismatch; hence equality is checked here. + ALOGD_IF(*pPrevVolume != *pSetVolume, "previous float ramp hasn't finished," + " prev:%f set_to:%f", *pPrevVolume, *pSetVolume); + const float inc = (newVolume - *pPrevVolume) / ramp; // could be inf, nan, subnormal + const float maxv = max(newVolume, *pPrevVolume); // could be inf, cannot be nan, subnormal + + if (isnormal(inc) // inc must be a normal number (no subnormals, infinite, nan) + && maxv + inc != maxv) { // inc must make forward progress + *pVolumeInc = inc; + // ramp is set now. + // Note: if newVolume is 0, then near the end of the ramp, + // it may be possible that the ramped volume may be subnormal or + // temporarily negative by a small amount or subnormal due to floating + // point inaccuracies. + } else { + ramp = 0; // ramp not allowed + } } - *pSetVolume = newVolume; - /* set the legacy integer volume variables */ - int32_t intVolume = newVolume * AudioMixer::UNITY_GAIN_INT; - if (intVolume > AudioMixer::UNITY_GAIN_INT) { - intVolume = AudioMixer::UNITY_GAIN_INT; - } else if (intVolume < 0) { - ALOGE("negative volume %.7g", newVolume); - intVolume = 0; // should never happen, but for safety check. + // compute and check integer volume, no need to check negative values + // The integer volume is limited to "unity_gain" to avoid wrapping and other + // audio artifacts, so it never reaches the range limit of U4.28. + // We safely use signed 16 and 32 bit integers here. + const float scaledVolume = newVolume * AudioMixer::UNITY_GAIN_INT; // not neg, subnormal, nan + const int32_t intVolume = (scaledVolume >= (float)AudioMixer::UNITY_GAIN_INT) ? + AudioMixer::UNITY_GAIN_INT : (int32_t)scaledVolume; + + // set integer volume ramp + if (ramp != 0) { + // integer volume is U4.12 (to use 16 bit multiplies), but ramping uses U4.28. + // when the ramp completes, *pIntPrevVolume is set to *pIntSetVolume << 16, so there + // is no computational mismatch; hence equality is checked here. + ALOGD_IF(*pIntPrevVolume != *pIntSetVolume << 16, "previous int ramp hasn't finished," + " prev:%d set_to:%d", *pIntPrevVolume, *pIntSetVolume << 16); + const int32_t inc = ((intVolume << 16) - *pIntPrevVolume) / ramp; + + if (inc != 0) { // inc must make forward progress + *pIntVolumeInc = inc; + } else { + ramp = 0; // ramp not allowed + } } - if (intVolume == *pIntSetVolume) { - *pIntVolumeInc = 0; - /* TODO: integer/float workaround: ignore floating volume ramp */ + + // if no ramp, or ramp not allowed, then clear float and integer increments + if (ramp == 0) { *pVolumeInc = 0; *pPrevVolume = newVolume; - return true; - } - if (ramp != 0) { - *pIntVolumeInc = ((intVolume - *pIntSetVolume) << 16) / ramp; - *pIntPrevVolume = (*pIntVolumeInc == 0 ? intVolume : *pIntSetVolume) << 16; - } else { *pIntVolumeInc = 0; *pIntPrevVolume = intVolume << 16; } + *pSetVolume = newVolume; *pIntSetVolume = intVolume; return true; } diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp index 8bccb47..949c91d 100644 --- a/services/audioflinger/Effects.cpp +++ b/services/audioflinger/Effects.cpp @@ -335,13 +335,21 @@ status_t AudioFlinger::EffectModule::configure() // TODO: handle configuration of effects replacing track process channelMask = thread->channelMask(); + mConfig.outputCfg.channels = channelMask; if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { mConfig.inputCfg.channels = AUDIO_CHANNEL_OUT_MONO; } else { mConfig.inputCfg.channels = channelMask; + // TODO: Update this logic when multichannel effects are implemented. + // For offloaded tracks consider mono output as stereo for proper effect initialization + if (channelMask == AUDIO_CHANNEL_OUT_MONO) { + mConfig.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; + mConfig.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; + ALOGV("Overriding effect input and output as STEREO"); + } } - 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(); diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 594ed05..7809eff 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -356,13 +356,47 @@ String8 devicesToString(audio_devices_t devices) AUDIO_DEVICE_OUT_SPEAKER, "SPEAKER", AUDIO_DEVICE_OUT_WIRED_HEADSET, "WIRED_HEADSET", AUDIO_DEVICE_OUT_WIRED_HEADPHONE, "WIRED_HEADPHONE", + AUDIO_DEVICE_OUT_BLUETOOTH_SCO, "BLUETOOTH_SCO", + AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET, "BLUETOOTH_SCO_HEADSET", + AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT, "BLUETOOTH_SCO_CARKIT", + AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, "BLUETOOTH_A2DP", + AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES, "BLUETOOTH_A2DP_HEADPHONES", + AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER, "BLUETOOTH_A2DP_SPEAKER", + AUDIO_DEVICE_OUT_AUX_DIGITAL, "AUX_DIGITAL", + AUDIO_DEVICE_OUT_HDMI, "HDMI", + AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET, "ANLG_DOCK_HEADSET", + AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET, "DGTL_DOCK_HEADSET", + AUDIO_DEVICE_OUT_USB_ACCESSORY, "USB_ACCESSORY", + AUDIO_DEVICE_OUT_USB_DEVICE, "USB_DEVICE", AUDIO_DEVICE_OUT_TELEPHONY_TX, "TELEPHONY_TX", + AUDIO_DEVICE_OUT_LINE, "LINE", + AUDIO_DEVICE_OUT_HDMI_ARC, "HDMI_ARC", + AUDIO_DEVICE_OUT_SPDIF, "SPDIF", + AUDIO_DEVICE_OUT_FM, "FM", + AUDIO_DEVICE_OUT_AUX_LINE, "AUX_LINE", + AUDIO_DEVICE_OUT_SPEAKER_SAFE, "SPEAKER_SAFE", AUDIO_DEVICE_NONE, "NONE", // must be last }, mappingsIn[] = { + AUDIO_DEVICE_IN_COMMUNICATION, "COMMUNICATION", + AUDIO_DEVICE_IN_AMBIENT, "AMBIENT", AUDIO_DEVICE_IN_BUILTIN_MIC, "BUILTIN_MIC", + AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, "BLUETOOTH_SCO_HEADSET", AUDIO_DEVICE_IN_WIRED_HEADSET, "WIRED_HEADSET", + AUDIO_DEVICE_IN_AUX_DIGITAL, "AUX_DIGITAL", AUDIO_DEVICE_IN_VOICE_CALL, "VOICE_CALL", + AUDIO_DEVICE_IN_TELEPHONY_RX, "TELEPHONY_RX", + AUDIO_DEVICE_IN_BACK_MIC, "BACK_MIC", AUDIO_DEVICE_IN_REMOTE_SUBMIX, "REMOTE_SUBMIX", + AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET, "ANLG_DOCK_HEADSET", + AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET, "DGTL_DOCK_HEADSET", + AUDIO_DEVICE_IN_USB_ACCESSORY, "USB_ACCESSORY", + AUDIO_DEVICE_IN_USB_DEVICE, "USB_DEVICE", + AUDIO_DEVICE_IN_FM_TUNER, "FM_TUNER", + AUDIO_DEVICE_IN_TV_TUNER, "TV_TUNER", + AUDIO_DEVICE_IN_LINE, "LINE", + AUDIO_DEVICE_IN_SPDIF, "SPDIF", + AUDIO_DEVICE_IN_BLUETOOTH_A2DP, "BLUETOOTH_A2DP", + AUDIO_DEVICE_IN_LOOPBACK, "LOOPBACK", AUDIO_DEVICE_NONE, "NONE", // must be last }; String8 result; @@ -487,7 +521,7 @@ const char *sourceToString(audio_source_t source) } AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id, - audio_devices_t outDevice, audio_devices_t inDevice, type_t type) + audio_devices_t outDevice, audio_devices_t inDevice, type_t type, bool systemReady) : Thread(false /*canCallJava*/), mType(type), mAudioFlinger(audioFlinger), @@ -498,7 +532,8 @@ AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, audio mStandby(false), mOutDevice(outDevice), mInDevice(inDevice), mAudioSource(AUDIO_SOURCE_DEFAULT), mId(id), // mName will be set by concrete (non-virtual) subclass - mDeathRecipient(new PMDeathRecipient(this)) + mDeathRecipient(new PMDeathRecipient(this)), + mSystemReady(systemReady) { memset(&mPatch, 0, sizeof(struct audio_patch)); } @@ -567,6 +602,11 @@ status_t AudioFlinger::ThreadBase::sendConfigEvent_l(sp<ConfigEvent>& event) { status_t status = NO_ERROR; + if (event->mRequiresSystemReady && !mSystemReady) { + event->mWaitStatus = false; + mPendingConfigEvents.add(event); + return status; + } mConfigEvents.add(event); ALOGV("sendConfigEvent_l() num events %d event %d", mConfigEvents.size(), event->mType); mWaitWorkCV.signal(); @@ -598,6 +638,12 @@ void AudioFlinger::ThreadBase::sendIoConfigEvent_l(audio_io_config_event event) sendConfigEvent_l(configEvent); } +void AudioFlinger::ThreadBase::sendPrioConfigEvent(pid_t pid, pid_t tid, int32_t prio) +{ + Mutex::Autolock _l(mLock); + sendPrioConfigEvent_l(pid, tid, prio); +} + // sendPrioConfigEvent_l() must be called with ThreadBase::mLock held void AudioFlinger::ThreadBase::sendPrioConfigEvent_l(pid_t pid, pid_t tid, int32_t prio) { @@ -697,49 +743,62 @@ void AudioFlinger::ThreadBase::processConfigEvents_l() String8 channelMaskToString(audio_channel_mask_t mask, bool output) { String8 s; - if (output) { - if (mask & AUDIO_CHANNEL_OUT_FRONT_LEFT) s.append("front-left, "); - if (mask & AUDIO_CHANNEL_OUT_FRONT_RIGHT) s.append("front-right, "); - if (mask & AUDIO_CHANNEL_OUT_FRONT_CENTER) s.append("front-center, "); - if (mask & AUDIO_CHANNEL_OUT_LOW_FREQUENCY) s.append("low freq, "); - if (mask & AUDIO_CHANNEL_OUT_BACK_LEFT) s.append("back-left, "); - if (mask & AUDIO_CHANNEL_OUT_BACK_RIGHT) s.append("back-right, "); - if (mask & AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER) s.append("front-left-of-center, "); - if (mask & AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER) s.append("front-right-of-center, "); - if (mask & AUDIO_CHANNEL_OUT_BACK_CENTER) s.append("back-center, "); - if (mask & AUDIO_CHANNEL_OUT_SIDE_LEFT) s.append("side-left, "); - if (mask & AUDIO_CHANNEL_OUT_SIDE_RIGHT) s.append("side-right, "); - if (mask & AUDIO_CHANNEL_OUT_TOP_CENTER) s.append("top-center ,"); - if (mask & AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT) s.append("top-front-left, "); - if (mask & AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER) s.append("top-front-center, "); - if (mask & AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT) s.append("top-front-right, "); - if (mask & AUDIO_CHANNEL_OUT_TOP_BACK_LEFT) s.append("top-back-left, "); - if (mask & AUDIO_CHANNEL_OUT_TOP_BACK_CENTER) s.append("top-back-center, " ); - if (mask & AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT) s.append("top-back-right, " ); - if (mask & ~AUDIO_CHANNEL_OUT_ALL) s.append("unknown, "); - } else { - if (mask & AUDIO_CHANNEL_IN_LEFT) s.append("left, "); - if (mask & AUDIO_CHANNEL_IN_RIGHT) s.append("right, "); - if (mask & AUDIO_CHANNEL_IN_FRONT) s.append("front, "); - if (mask & AUDIO_CHANNEL_IN_BACK) s.append("back, "); - if (mask & AUDIO_CHANNEL_IN_LEFT_PROCESSED) s.append("left-processed, "); - if (mask & AUDIO_CHANNEL_IN_RIGHT_PROCESSED) s.append("right-processed, "); - if (mask & AUDIO_CHANNEL_IN_FRONT_PROCESSED) s.append("front-processed, "); - if (mask & AUDIO_CHANNEL_IN_BACK_PROCESSED) s.append("back-processed, "); - if (mask & AUDIO_CHANNEL_IN_PRESSURE) s.append("pressure, "); - if (mask & AUDIO_CHANNEL_IN_X_AXIS) s.append("X, "); - if (mask & AUDIO_CHANNEL_IN_Y_AXIS) s.append("Y, "); - if (mask & AUDIO_CHANNEL_IN_Z_AXIS) s.append("Z, "); - if (mask & AUDIO_CHANNEL_IN_VOICE_UPLINK) s.append("voice-uplink, "); - if (mask & AUDIO_CHANNEL_IN_VOICE_DNLINK) s.append("voice-dnlink, "); - if (mask & ~AUDIO_CHANNEL_IN_ALL) s.append("unknown, "); - } - int len = s.length(); - if (s.length() > 2) { - char *str = s.lockBuffer(len); - s.unlockBuffer(len - 2); - } - return s; + const audio_channel_representation_t representation = audio_channel_mask_get_representation(mask); + + switch (representation) { + case AUDIO_CHANNEL_REPRESENTATION_POSITION: { + if (output) { + if (mask & AUDIO_CHANNEL_OUT_FRONT_LEFT) s.append("front-left, "); + if (mask & AUDIO_CHANNEL_OUT_FRONT_RIGHT) s.append("front-right, "); + if (mask & AUDIO_CHANNEL_OUT_FRONT_CENTER) s.append("front-center, "); + if (mask & AUDIO_CHANNEL_OUT_LOW_FREQUENCY) s.append("low freq, "); + if (mask & AUDIO_CHANNEL_OUT_BACK_LEFT) s.append("back-left, "); + if (mask & AUDIO_CHANNEL_OUT_BACK_RIGHT) s.append("back-right, "); + if (mask & AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER) s.append("front-left-of-center, "); + if (mask & AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER) s.append("front-right-of-center, "); + if (mask & AUDIO_CHANNEL_OUT_BACK_CENTER) s.append("back-center, "); + if (mask & AUDIO_CHANNEL_OUT_SIDE_LEFT) s.append("side-left, "); + if (mask & AUDIO_CHANNEL_OUT_SIDE_RIGHT) s.append("side-right, "); + if (mask & AUDIO_CHANNEL_OUT_TOP_CENTER) s.append("top-center ,"); + if (mask & AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT) s.append("top-front-left, "); + if (mask & AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER) s.append("top-front-center, "); + if (mask & AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT) s.append("top-front-right, "); + if (mask & AUDIO_CHANNEL_OUT_TOP_BACK_LEFT) s.append("top-back-left, "); + if (mask & AUDIO_CHANNEL_OUT_TOP_BACK_CENTER) s.append("top-back-center, " ); + if (mask & AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT) s.append("top-back-right, " ); + if (mask & ~AUDIO_CHANNEL_OUT_ALL) s.append("unknown, "); + } else { + if (mask & AUDIO_CHANNEL_IN_LEFT) s.append("left, "); + if (mask & AUDIO_CHANNEL_IN_RIGHT) s.append("right, "); + if (mask & AUDIO_CHANNEL_IN_FRONT) s.append("front, "); + if (mask & AUDIO_CHANNEL_IN_BACK) s.append("back, "); + if (mask & AUDIO_CHANNEL_IN_LEFT_PROCESSED) s.append("left-processed, "); + if (mask & AUDIO_CHANNEL_IN_RIGHT_PROCESSED) s.append("right-processed, "); + if (mask & AUDIO_CHANNEL_IN_FRONT_PROCESSED) s.append("front-processed, "); + if (mask & AUDIO_CHANNEL_IN_BACK_PROCESSED) s.append("back-processed, "); + if (mask & AUDIO_CHANNEL_IN_PRESSURE) s.append("pressure, "); + if (mask & AUDIO_CHANNEL_IN_X_AXIS) s.append("X, "); + if (mask & AUDIO_CHANNEL_IN_Y_AXIS) s.append("Y, "); + if (mask & AUDIO_CHANNEL_IN_Z_AXIS) s.append("Z, "); + if (mask & AUDIO_CHANNEL_IN_VOICE_UPLINK) s.append("voice-uplink, "); + if (mask & AUDIO_CHANNEL_IN_VOICE_DNLINK) s.append("voice-dnlink, "); + if (mask & ~AUDIO_CHANNEL_IN_ALL) s.append("unknown, "); + } + const int len = s.length(); + if (len > 2) { + char *str = s.lockBuffer(len); // needed? + s.unlockBuffer(len - 2); // remove trailing ", " + } + return s; + } + case AUDIO_CHANNEL_REPRESENTATION_INDEX: + s.appendFormat("index mask, bits:%#x", audio_channel_mask_get_bits(mask)); + return s; + default: + s.appendFormat("unknown mask, representation:%d bits:%#x", + representation, audio_channel_mask_get_bits(mask)); + return s; + } } void AudioFlinger::ThreadBase::dumpBase(int fd, const Vector<String16>& args __unused) @@ -880,8 +939,7 @@ void AudioFlinger::ThreadBase::updateWakeLockUids(const SortedVector<int> &uids) } void AudioFlinger::ThreadBase::getPowerManager_l() { - - if (mPowerManager == 0) { + if (mSystemReady && mPowerManager == 0) { // use checkService() to avoid blocking if power service is not up yet sp<IBinder> binder = defaultServiceManager()->checkService(String16("power")); @@ -895,7 +953,6 @@ void AudioFlinger::ThreadBase::getPowerManager_l() { } void AudioFlinger::ThreadBase::updateWakeLockUids_l(const SortedVector<int> &uids) { - getPowerManager_l(); if (mWakeLockToken == NULL) { ALOGE("no wake lock to update!"); @@ -1337,6 +1394,20 @@ void AudioFlinger::ThreadBase::getAudioPortConfig(struct audio_port_config *conf AUDIO_PORT_CONFIG_FORMAT; } +void AudioFlinger::ThreadBase::systemReady() +{ + Mutex::Autolock _l(mLock); + if (mSystemReady) { + return; + } + mSystemReady = true; + + for (size_t i = 0; i < mPendingConfigEvents.size(); i++) { + sendConfigEvent_l(mPendingConfigEvents.editItemAt(i)); + } + mPendingConfigEvents.clear(); +} + // ---------------------------------------------------------------------------- // Playback @@ -1346,8 +1417,9 @@ AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinge AudioStreamOut* output, audio_io_handle_t id, audio_devices_t device, - type_t type) - : ThreadBase(audioFlinger, id, device, AUDIO_DEVICE_NONE, type), + type_t type, + bool systemReady) + : ThreadBase(audioFlinger, id, device, AUDIO_DEVICE_NONE, type, systemReady), mNormalFrameCount(0), mSinkBuffer(NULL), mMixerBufferEnabled(AudioFlinger::kEnableExtendedPrecision), mMixerBuffer(NULL), @@ -1366,7 +1438,7 @@ AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinge mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false), mMixerStatus(MIXER_IDLE), mMixerStatusIgnoringFastTracks(MIXER_IDLE), - standbyDelay(AudioFlinger::mStandbyTimeInNsecs), + mStandbyDelayNs(AudioFlinger::mStandbyTimeInNsecs), mBytesRemaining(0), mCurrentWriteLength(0), mUseAsyncWrite(false), @@ -1572,10 +1644,12 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrac ) && // PCM data audio_is_linear_pcm(format) && - // identical channel mask to sink, or mono in and stereo sink + // TODO: extract as a data library function that checks that a computationally + // expensive downmixer is not required: isFastOutputChannelConversion() (channelMask == mChannelMask || - (channelMask == AUDIO_CHANNEL_OUT_MONO && - mChannelMask == AUDIO_CHANNEL_OUT_STEREO)) && + mChannelMask != AUDIO_CHANNEL_OUT_STEREO || + (channelMask == AUDIO_CHANNEL_OUT_MONO + /* && mChannelMask == AUDIO_CHANNEL_OUT_STEREO */)) && // hardware sample rate (sampleRate == mSampleRate) && // normal mixer has an associated fast mixer @@ -2418,9 +2492,9 @@ void AudioFlinger::PlaybackThread::threadLoop_exit() /* The derived values that are cached: - mSinkBufferSize from frame count * frame size - - activeSleepTime from activeSleepTimeUs() - - idleSleepTime from idleSleepTimeUs() - - standbyDelay from mActiveSleepTimeUs (DIRECT only) + - mActiveSleepTimeUs from activeSleepTimeUs() + - mIdleSleepTimeUs from idleSleepTimeUs() + - mStandbyDelayNs from mActiveSleepTimeUs (DIRECT only) - maxPeriod from frame count and sample rate (MIXER only) The parameters that affect these derived values are: @@ -2437,8 +2511,8 @@ The parameters that affect these derived values are: void AudioFlinger::PlaybackThread::cacheParameters_l() { mSinkBufferSize = mNormalFrameCount * mFrameSize; - activeSleepTime = activeSleepTimeUs(); - idleSleepTime = idleSleepTimeUs(); + mActiveSleepTimeUs = activeSleepTimeUs(); + mIdleSleepTimeUs = idleSleepTimeUs(); } void AudioFlinger::PlaybackThread::invalidateTracks(audio_stream_type_t streamType) @@ -2605,7 +2679,7 @@ bool AudioFlinger::PlaybackThread::threadLoop() { Vector< sp<Track> > tracksToRemove; - standbyTime = systemTime(); + mStandbyTimeNs = systemTime(); // MIXER nsecs_t lastWarning = 0; @@ -2617,7 +2691,7 @@ bool AudioFlinger::PlaybackThread::threadLoop() int lastGeneration = 0; cacheParameters_l(); - sleepTime = idleSleepTime; + mSleepTimeUs = mIdleSleepTimeUs; if (mType == MIXER) { sleepTimeShift = 0; @@ -2696,12 +2770,12 @@ bool AudioFlinger::PlaybackThread::threadLoop() if (released) { acquireWakeLock_l(); } - standbyTime = systemTime() + standbyDelay; - sleepTime = 0; + mStandbyTimeNs = systemTime() + mStandbyDelayNs; + mSleepTimeUs = 0; continue; } - if ((!mActiveTracks.size() && systemTime() > standbyTime) || + if ((!mActiveTracks.size() && systemTime() > mStandbyTimeNs) || isSuspended()) { // put audio hardware into standby after short delay if (shouldStandby_l()) { @@ -2736,8 +2810,8 @@ bool AudioFlinger::PlaybackThread::threadLoop() mBytesRemaining = 0; checkSilentMode_l(); - standbyTime = systemTime() + standbyDelay; - sleepTime = idleSleepTime; + mStandbyTimeNs = systemTime() + mStandbyDelayNs; + mSleepTimeUs = mIdleSleepTimeUs; if (mType == MIXER) { sleepTimeShift = 0; } @@ -2768,15 +2842,15 @@ bool AudioFlinger::PlaybackThread::threadLoop() threadLoop_mix(); } else if ((mMixerStatus != MIXER_DRAIN_TRACK) && (mMixerStatus != MIXER_DRAIN_ALL)) { - // threadLoop_sleepTime sets sleepTime to 0 if data + // threadLoop_sleepTime sets mSleepTimeUs to 0 if data // must be written to HAL threadLoop_sleepTime(); - if (sleepTime == 0) { + if (mSleepTimeUs == 0) { mCurrentWriteLength = mSinkBufferSize; } } // Either threadLoop_mix() or threadLoop_sleepTime() should have set - // mMixerBuffer with data if mMixerBufferValid is true and sleepTime == 0. + // mMixerBuffer with data if mMixerBufferValid is true and mSleepTimeUs == 0. // Merge mMixerBuffer data into mEffectBuffer (if any effects are valid) // or mSinkBuffer (if there are no effects). // @@ -2784,7 +2858,7 @@ bool AudioFlinger::PlaybackThread::threadLoop() // support higher precision, this needs to move. // // mMixerBufferValid is only set true by MixerThread::prepareTracks_l(). - // TODO use sleepTime == 0 as an additional condition. + // TODO use mSleepTimeUs == 0 as an additional condition. if (mMixerBufferValid) { void *buffer = mEffectBufferValid ? mEffectBuffer : mSinkBuffer; audio_format_t format = mEffectBufferValid ? mEffectBufferFormat : mFormat; @@ -2795,14 +2869,14 @@ bool AudioFlinger::PlaybackThread::threadLoop() mBytesRemaining = mCurrentWriteLength; if (isSuspended()) { - sleepTime = suspendSleepTimeUs(); + mSleepTimeUs = suspendSleepTimeUs(); // simulate write to HAL when suspended mBytesWritten += mSinkBufferSize; mBytesRemaining = 0; } // only process effects if we're going to write - if (sleepTime == 0 && mType != OFFLOAD) { + if (mSleepTimeUs == 0 && mType != OFFLOAD) { for (size_t i = 0; i < effectChains.size(); i ++) { effectChains[i]->process_l(); } @@ -2821,7 +2895,7 @@ bool AudioFlinger::PlaybackThread::threadLoop() // Only if the Effects buffer is enabled and there is data in the // Effects buffer (buffer valid), we need to // copy into the sink buffer. - // TODO use sleepTime == 0 as an additional condition. + // TODO use mSleepTimeUs == 0 as an additional condition. if (mEffectBufferValid) { //ALOGV("writing effect buffer to sink buffer format %#x", mFormat); memcpy_by_audio_format(mSinkBuffer, mFormat, mEffectBuffer, mEffectBufferFormat, @@ -2832,8 +2906,8 @@ bool AudioFlinger::PlaybackThread::threadLoop() unlockEffectChains(effectChains); if (!waitingAsyncCallback()) { - // sleepTime == 0 means we must write to audio hardware - if (sleepTime == 0) { + // mSleepTimeUs == 0 means we must write to audio hardware + if (mSleepTimeUs == 0) { if (mBytesRemaining) { ssize_t ret = threadLoop_write(); if (ret < 0) { @@ -2863,7 +2937,7 @@ bool AudioFlinger::PlaybackThread::threadLoop() } else { ATRACE_BEGIN("sleep"); - usleep(sleepTime); + usleep(mSleepTimeUs); ATRACE_END(); } } @@ -3118,8 +3192,8 @@ void AudioFlinger::PlaybackThread::getAudioPortConfig(struct audio_port_config * // ---------------------------------------------------------------------------- AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, - audio_io_handle_t id, audio_devices_t device, type_t type) - : PlaybackThread(audioFlinger, output, id, device, type), + audio_io_handle_t id, audio_devices_t device, bool systemReady, type_t type) + : PlaybackThread(audioFlinger, output, id, device, type, systemReady), // mAudioMixer below // mFastMixer below mFastMixerFutex(0) @@ -3252,11 +3326,7 @@ AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, Aud // start the fast mixer mFastMixer->run("FastMixer", PRIORITY_URGENT_AUDIO); pid_t tid = mFastMixer->getTid(); - int err = requestPriority(getpid_cached, tid, kPriorityFastMixer); - if (err != 0) { - ALOGW("Policy SCHED_FIFO priority %d is unavailable for pid %d tid %d; error %d", - kPriorityFastMixer, getpid_cached, tid, err); - } + sendPrioConfigEvent(getpid_cached, tid, kPriorityFastMixer); #ifdef AUDIO_WATCHDOG // create and start the watchdog @@ -3264,11 +3334,7 @@ AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, Aud mAudioWatchdog->setDump(&mAudioWatchdogDump); mAudioWatchdog->run("AudioWatchdog", PRIORITY_URGENT_AUDIO); tid = mAudioWatchdog->getTid(); - err = requestPriority(getpid_cached, tid, kPriorityFastMixer); - if (err != 0) { - ALOGW("Policy SCHED_FIFO priority %d is unavailable for pid %d tid %d; error %d", - kPriorityFastMixer, getpid_cached, tid, err); - } + sendPrioConfigEvent(getpid_cached, tid, kPriorityFastMixer); #endif } @@ -3467,11 +3533,11 @@ void AudioFlinger::MixerThread::threadLoop_mix() // Only increase sleep time if the mixer is ready for two consecutive times to avoid // that a steady state of alternating ready/not ready conditions keeps the sleep time // such that we would underrun the audio HAL. - if ((sleepTime == 0) && (sleepTimeShift > 0)) { + if ((mSleepTimeUs == 0) && (sleepTimeShift > 0)) { sleepTimeShift--; } - sleepTime = 0; - standbyTime = systemTime() + standbyDelay; + mSleepTimeUs = 0; + mStandbyTimeNs = systemTime() + mStandbyDelayNs; //TODO: delay standby when effects have a tail } @@ -3480,11 +3546,11 @@ void AudioFlinger::MixerThread::threadLoop_sleepTime() { // If no tracks are ready, sleep once for the duration of an output // buffer size, then write 0s to the output - if (sleepTime == 0) { + if (mSleepTimeUs == 0) { if (mMixerStatus == MIXER_TRACKS_ENABLED) { - sleepTime = activeSleepTime >> sleepTimeShift; - if (sleepTime < kMinThreadSleepTimeUs) { - sleepTime = kMinThreadSleepTimeUs; + mSleepTimeUs = mActiveSleepTimeUs >> sleepTimeShift; + if (mSleepTimeUs < kMinThreadSleepTimeUs) { + mSleepTimeUs = kMinThreadSleepTimeUs; } // reduce sleep time in case of consecutive application underruns to avoid // starving the audio HAL. As activeSleepTimeUs() is larger than a buffer @@ -3494,7 +3560,7 @@ void AudioFlinger::MixerThread::threadLoop_sleepTime() sleepTimeShift++; } } else { - sleepTime = idleSleepTime; + mSleepTimeUs = mIdleSleepTimeUs; } } else if (mBytesWritten != 0 || (mMixerStatus == MIXER_TRACKS_ENABLED)) { // clear out mMixerBuffer or mSinkBuffer, to ensure buffers are cleared @@ -3504,7 +3570,7 @@ void AudioFlinger::MixerThread::threadLoop_sleepTime() } else { memset(mSinkBuffer, 0, mSinkBufferSize); } - sleepTime = 0; + mSleepTimeUs = 0; ALOGV_IF(mBytesWritten == 0 && (mMixerStatus == MIXER_TRACKS_ENABLED), "anticipated start"); } @@ -4294,16 +4360,16 @@ void AudioFlinger::MixerThread::cacheParameters_l() // ---------------------------------------------------------------------------- AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger, - AudioStreamOut* output, audio_io_handle_t id, audio_devices_t device) - : PlaybackThread(audioFlinger, output, id, device, DIRECT) + AudioStreamOut* output, audio_io_handle_t id, audio_devices_t device, bool systemReady) + : PlaybackThread(audioFlinger, output, id, device, DIRECT, systemReady) // mLeftVolFloat, mRightVolFloat { } AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, audio_io_handle_t id, uint32_t device, - ThreadBase::type_t type) - : PlaybackThread(audioFlinger, output, id, device, type) + ThreadBase::type_t type, bool systemReady) + : PlaybackThread(audioFlinger, output, id, device, type, systemReady) // mLeftVolFloat, mRightVolFloat { } @@ -4443,7 +4509,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep track->mRetryCount = kMaxTrackRetriesDirect; mActiveTrack = t; mixerStatus = MIXER_TRACKS_READY; - if (usesHwAvSync() && mHwPaused) { + if (mHwPaused) { doHwResume = true; mHwPaused = false; } @@ -4495,7 +4561,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep android_atomic_or(CBLK_DISABLED, &cblk->mFlags); } else if (last) { mixerStatus = MIXER_TRACKS_ENABLED; - if (usesHwAvSync() && !mHwPaused && !mStandby) { + if (mHwSupportsPause && !mHwPaused && !mStandby) { doHwPause = true; mHwPaused = true; } @@ -4553,8 +4619,8 @@ void AudioFlinger::DirectOutputThread::threadLoop_mix() mActiveTrack->releaseBuffer(&buffer); } mCurrentWriteLength = curBuf - (int8_t *)mSinkBuffer; - sleepTime = 0; - standbyTime = systemTime() + standbyDelay; + mSleepTimeUs = 0; + mStandbyTimeNs = systemTime() + mStandbyDelayNs; mActiveTrack.clear(); } @@ -4562,18 +4628,18 @@ void AudioFlinger::DirectOutputThread::threadLoop_sleepTime() { // do not write to HAL when paused if (mHwPaused || (usesHwAvSync() && mStandby)) { - sleepTime = idleSleepTime; + mSleepTimeUs = mIdleSleepTimeUs; return; } - if (sleepTime == 0) { + if (mSleepTimeUs == 0) { if (mMixerStatus == MIXER_TRACKS_ENABLED) { - sleepTime = activeSleepTime; + mSleepTimeUs = mActiveSleepTimeUs; } else { - sleepTime = idleSleepTime; + mSleepTimeUs = mIdleSleepTimeUs; } } else if (mBytesWritten != 0 && audio_is_linear_pcm(mFormat)) { memset(mSinkBuffer, 0, mFrameCount * mFrameSize); - sleepTime = 0; + mSleepTimeUs = 0; } } @@ -4609,7 +4675,7 @@ bool AudioFlinger::DirectOutputThread::shouldStandby_l() mTracks[mTracks.size() - 1]->mState == TrackBase::IDLE; } - return !mStandby && !(trackPaused || (usesHwAvSync() && mHwPaused && !trackStopped)); + return !mStandby && !(trackPaused || (mHwPaused && !trackStopped)); } // getTrackName_l() must be called with ThreadBase::mLock held @@ -4714,11 +4780,11 @@ void AudioFlinger::DirectOutputThread::cacheParameters_l() // hardware resources as soon as possible // no delay on outputs with HW A/V sync if (usesHwAvSync()) { - standbyDelay = 0; - } else if (audio_is_linear_pcm(mFormat)) { - standbyDelay = microseconds(activeSleepTime*2); + mStandbyDelayNs = 0; + } else if ((mType == OFFLOAD) && !audio_is_linear_pcm(mFormat)) { + mStandbyDelayNs = kOffloadStandbyDelayNs; } else { - standbyDelay = kOffloadStandbyDelayNs; + mStandbyDelayNs = microseconds(mActiveSleepTimeUs*2); } } @@ -4832,8 +4898,8 @@ void AudioFlinger::AsyncCallbackThread::resetDraining() // ---------------------------------------------------------------------------- AudioFlinger::OffloadThread::OffloadThread(const sp<AudioFlinger>& audioFlinger, - AudioStreamOut* output, audio_io_handle_t id, uint32_t device) - : DirectOutputThread(audioFlinger, output, id, device, OFFLOAD), + AudioStreamOut* output, audio_io_handle_t id, uint32_t device, bool systemReady) + : DirectOutputThread(audioFlinger, output, id, device, OFFLOAD, systemReady), mPausedBytesRemaining(0) { //FIXME: mStandby should be set to true by ThreadBase constructor @@ -4898,7 +4964,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::OffloadThread::prepareTr if (track->isPausing()) { track->setPaused(); if (last) { - if (!mHwPaused) { + if (mHwSupportsPause && !mHwPaused) { doHwPause = true; mHwPaused = true; } @@ -4934,7 +5000,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::OffloadThread::prepareTr // resume an interrupted write } // enable write to audio HAL - sleepTime = 0; + mSleepTimeUs = 0; // Do not handle new data in this iteration even if track->framesReady() mixerStatus = MIXER_TRACKS_ENABLED; @@ -4994,8 +5060,8 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::OffloadThread::prepareTr // do not modify drain sequence if we are already draining. This happens // when resuming from pause after drain. if ((mDrainSequence & 1) == 0) { - sleepTime = 0; - standbyTime = systemTime() + standbyDelay; + mSleepTimeUs = 0; + mStandbyTimeNs = systemTime() + mStandbyDelayNs; mixerStatus = MIXER_DRAIN_TRACK; mDrainSequence += 2; } @@ -5110,9 +5176,9 @@ void AudioFlinger::OffloadThread::onAddNewTrack_l() // ---------------------------------------------------------------------------- AudioFlinger::DuplicatingThread::DuplicatingThread(const sp<AudioFlinger>& audioFlinger, - AudioFlinger::MixerThread* mainThread, audio_io_handle_t id) + AudioFlinger::MixerThread* mainThread, audio_io_handle_t id, bool systemReady) : MixerThread(audioFlinger, mainThread->getOutput(), id, mainThread->outDevice(), - DUPLICATING), + systemReady, DUPLICATING), mWaitTimeMs(UINT_MAX) { addOutputTrack(mainThread); @@ -5137,19 +5203,19 @@ void AudioFlinger::DuplicatingThread::threadLoop_mix() memset(mSinkBuffer, 0, mSinkBufferSize); } } - sleepTime = 0; + mSleepTimeUs = 0; writeFrames = mNormalFrameCount; mCurrentWriteLength = mSinkBufferSize; - standbyTime = systemTime() + standbyDelay; + mStandbyTimeNs = systemTime() + mStandbyDelayNs; } void AudioFlinger::DuplicatingThread::threadLoop_sleepTime() { - if (sleepTime == 0) { + if (mSleepTimeUs == 0) { if (mMixerStatus == MIXER_TRACKS_ENABLED) { - sleepTime = activeSleepTime; + mSleepTimeUs = mActiveSleepTimeUs; } else { - sleepTime = idleSleepTime; + mSleepTimeUs = mIdleSleepTimeUs; } } else if (mBytesWritten != 0) { if (mMixerStatus == MIXER_TRACKS_ENABLED) { @@ -5159,7 +5225,7 @@ void AudioFlinger::DuplicatingThread::threadLoop_sleepTime() // flush remaining overflow buffers in output tracks writeFrames = 0; } - sleepTime = 0; + mSleepTimeUs = 0; } } @@ -5292,12 +5358,13 @@ AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger, AudioStreamIn *input, audio_io_handle_t id, audio_devices_t outDevice, - audio_devices_t inDevice + audio_devices_t inDevice, + bool systemReady #ifdef TEE_SINK , const sp<NBAIO_Sink>& teeSink #endif ) : - ThreadBase(audioFlinger, id, outDevice, inDevice, RECORD), + ThreadBase(audioFlinger, id, outDevice, inDevice, RECORD, systemReady), mInput(input), mActiveTracksGen(0), mRsmpInBuffer(NULL), // mRsmpInFrames and mRsmpInFramesP2 are set by readInputParameters_l() mRsmpInRear(0) @@ -5416,12 +5483,7 @@ AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger, // start the fast capture mFastCapture->run("FastCapture", ANDROID_PRIORITY_URGENT_AUDIO); pid_t tid = mFastCapture->getTid(); - int err = requestPriority(getpid_cached, tid, kPriorityFastMixer); - if (err != 0) { - ALOGW("Policy SCHED_FIFO priority %d is unavailable for pid %d tid %d; error %d", - kPriorityFastCapture, getpid_cached, tid, err); - } - + sendPrioConfigEvent(getpid_cached, tid, kPriorityFastMixer); #ifdef AUDIO_WATCHDOG // FIXME #endif diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h index 37bacae..07c226e 100644 --- a/services/audioflinger/Threads.h +++ b/services/audioflinger/Threads.h @@ -35,7 +35,8 @@ public: static const char *threadTypeToString(type_t type); ThreadBase(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id, - audio_devices_t outDevice, audio_devices_t inDevice, type_t type); + audio_devices_t outDevice, audio_devices_t inDevice, type_t type, + bool systemReady); virtual ~ThreadBase(); virtual status_t readyToRun(); @@ -92,10 +93,13 @@ public: Condition mCond; // condition for status return status_t mStatus; // status communicated to sender bool mWaitStatus; // true if sender is waiting for status + bool mRequiresSystemReady; // true if must wait for system ready to enter event queue sp<ConfigEventData> mData; // event specific parameter data protected: - ConfigEvent(int type) : mType(type), mStatus(NO_ERROR), mWaitStatus(false), mData(NULL) {} + ConfigEvent(int type, bool requiresSystemReady = false) : + mType(type), mStatus(NO_ERROR), mWaitStatus(false), + mRequiresSystemReady(requiresSystemReady), mData(NULL) {} }; class IoConfigEventData : public ConfigEventData { @@ -136,7 +140,7 @@ public: class PrioConfigEvent : public ConfigEvent { public: PrioConfigEvent(pid_t pid, pid_t tid, int32_t prio) : - ConfigEvent(CFG_EVENT_PRIO) { + ConfigEvent(CFG_EVENT_PRIO, true) { mData = new PrioConfigEventData(pid, tid, prio); } virtual ~PrioConfigEvent() {} @@ -258,6 +262,7 @@ public: status_t sendConfigEvent_l(sp<ConfigEvent>& event); void sendIoConfigEvent(audio_io_config_event event); void sendIoConfigEvent_l(audio_io_config_event event); + void sendPrioConfigEvent(pid_t pid, pid_t tid, int32_t prio); void sendPrioConfigEvent_l(pid_t pid, pid_t tid, int32_t prio); status_t sendSetParameterConfigEvent_l(const String8& keyValuePair); status_t sendCreateAudioPatchConfigEvent(const struct audio_patch *patch, @@ -359,6 +364,8 @@ public: virtual sp<IMemory> pipeMemory() const { return 0; } + void systemReady(); + mutable Mutex mLock; protected: @@ -418,6 +425,7 @@ protected: size_t mBufferSize; // HAL buffer size for read() or write() Vector< sp<ConfigEvent> > mConfigEvents; + Vector< sp<ConfigEvent> > mPendingConfigEvents; // events awaiting system ready // These fields are written and read by thread itself without lock or barrier, // and read by other threads without lock or barrier via standby(), outDevice() @@ -445,6 +453,7 @@ protected: mSuspendedSessions; static const size_t kLogSize = 4 * 1024; sp<NBLog::Writer> mNBLogWriter; + bool mSystemReady; }; // --- PlaybackThread --- @@ -470,7 +479,7 @@ public: static const int8_t kMaxTrackRetriesOffload = 20; PlaybackThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, - audio_io_handle_t id, audio_devices_t device, type_t type); + audio_io_handle_t id, audio_devices_t device, type_t type, bool systemReady); virtual ~PlaybackThread(); void dump(int fd, const Vector<String16>& args); @@ -746,14 +755,14 @@ private: bool mInWrite; // FIXME rename these former local variables of threadLoop to standard "m" names - nsecs_t standbyTime; + nsecs_t mStandbyTimeNs; size_t mSinkBufferSize; // cached copies of activeSleepTimeUs() and idleSleepTimeUs() made by cacheParameters_l() - uint32_t activeSleepTime; - uint32_t idleSleepTime; + uint32_t mActiveSleepTimeUs; + uint32_t mIdleSleepTimeUs; - uint32_t sleepTime; + uint32_t mSleepTimeUs; // mixer status returned by prepareTracks_l() mixer_state mMixerStatus; // current cycle @@ -766,7 +775,7 @@ private: uint32_t sleepTimeShift; // same as AudioFlinger::mStandbyTimeInNsecs except for DIRECT which uses a shorter value - nsecs_t standbyDelay; + nsecs_t mStandbyDelayNs; // MIXER only nsecs_t maxPeriod; @@ -842,6 +851,7 @@ public: AudioStreamOut* output, audio_io_handle_t id, audio_devices_t device, + bool systemReady, type_t type = MIXER); virtual ~MixerThread(); @@ -903,7 +913,7 @@ class DirectOutputThread : public PlaybackThread { public: DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, - audio_io_handle_t id, audio_devices_t device); + audio_io_handle_t id, audio_devices_t device, bool systemReady); virtual ~DirectOutputThread(); // Thread virtuals @@ -933,7 +943,8 @@ protected: float mRightVolFloat; DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, - audio_io_handle_t id, uint32_t device, ThreadBase::type_t type); + audio_io_handle_t id, uint32_t device, ThreadBase::type_t type, + bool systemReady); void processVolume_l(Track *track, bool lastTrack); // prepareTracks_l() tells threadLoop_mix() the name of the single active track @@ -946,7 +957,7 @@ class OffloadThread : public DirectOutputThread { public: OffloadThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, - audio_io_handle_t id, uint32_t device); + audio_io_handle_t id, uint32_t device, bool systemReady); virtual ~OffloadThread() {}; virtual void flushHw_l(); @@ -1001,7 +1012,7 @@ private: class DuplicatingThread : public MixerThread { public: DuplicatingThread(const sp<AudioFlinger>& audioFlinger, MixerThread* mainThread, - audio_io_handle_t id); + audio_io_handle_t id, bool systemReady); virtual ~DuplicatingThread(); // Thread virtuals @@ -1177,7 +1188,8 @@ public: AudioStreamIn *input, audio_io_handle_t id, audio_devices_t outDevice, - audio_devices_t inDevice + audio_devices_t inDevice, + bool systemReady #ifdef TEE_SINK , const sp<NBAIO_Sink>& teeSink #endif @@ -1294,6 +1306,7 @@ private: // one-time initialization, no locks required sp<FastCapture> mFastCapture; // non-0 if there is also // a fast capture + // FIXME audio watchdog thread // contents are not guaranteed to be consistent, no locks required diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp index d1ee400..665cce9 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp @@ -171,7 +171,7 @@ status_t AudioPolicyManager::setDeviceConnectionStateInt(audio_devices_t device, } updateDevicesAndOutputs(); - if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL) { + if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput()) { audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/); updateCallRouting(newDevice); } @@ -261,7 +261,7 @@ status_t AudioPolicyManager::setDeviceConnectionStateInt(audio_devices_t device, closeAllInputs(); - if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL) { + if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput()) { audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/); updateCallRouting(newDevice); } @@ -302,6 +302,9 @@ void AudioPolicyManager::updateCallRouting(audio_devices_t rxDevice, int delayMs audio_patch_handle_t afPatchHandle; DeviceVector deviceList; + if(!hasPrimaryOutput()) { + return; + } audio_devices_t txDevice = getDeviceAndMixForInputSource(AUDIO_SOURCE_VOICE_COMMUNICATION); ALOGV("updateCallRouting device rxDevice %08x txDevice %08x", rxDevice, txDevice); @@ -449,8 +452,6 @@ void AudioPolicyManager::setPhoneState(audio_mode_t state) checkOutputForAllStrategies(); updateDevicesAndOutputs(); - sp<SwAudioOutputDescriptor> hwOutputDesc = mPrimaryOutput; - int delayMs = 0; if (isStateInCall(state)) { nsecs_t sysTime = systemTime(); @@ -477,29 +478,31 @@ void AudioPolicyManager::setPhoneState(audio_mode_t state) } } - // Note that despite the fact that getNewOutputDevice() is called on the primary output, - // the device returned is not necessarily reachable via this output - audio_devices_t rxDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/); - // force routing command to audio hardware when ending call - // even if no device change is needed - if (isStateInCall(oldState) && rxDevice == AUDIO_DEVICE_NONE) { - rxDevice = hwOutputDesc->device(); - } - - if (state == AUDIO_MODE_IN_CALL) { - updateCallRouting(rxDevice, delayMs); - } else if (oldState == AUDIO_MODE_IN_CALL) { - if (mCallRxPatch != 0) { - mpClientInterface->releaseAudioPatch(mCallRxPatch->mAfPatchHandle, 0); - mCallRxPatch.clear(); + if (hasPrimaryOutput()) { + // Note that despite the fact that getNewOutputDevice() is called on the primary output, + // the device returned is not necessarily reachable via this output + audio_devices_t rxDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/); + // force routing command to audio hardware when ending call + // even if no device change is needed + if (isStateInCall(oldState) && rxDevice == AUDIO_DEVICE_NONE) { + rxDevice = mPrimaryOutput->device(); } - if (mCallTxPatch != 0) { - mpClientInterface->releaseAudioPatch(mCallTxPatch->mAfPatchHandle, 0); - mCallTxPatch.clear(); + + if (state == AUDIO_MODE_IN_CALL) { + updateCallRouting(rxDevice, delayMs); + } else if (oldState == AUDIO_MODE_IN_CALL) { + if (mCallRxPatch != 0) { + mpClientInterface->releaseAudioPatch(mCallRxPatch->mAfPatchHandle, 0); + mCallRxPatch.clear(); + } + if (mCallTxPatch != 0) { + mpClientInterface->releaseAudioPatch(mCallTxPatch->mAfPatchHandle, 0); + mCallTxPatch.clear(); + } + setOutputDevice(mPrimaryOutput, rxDevice, force, 0); + } else { + setOutputDevice(mPrimaryOutput, rxDevice, force, 0); } - setOutputDevice(mPrimaryOutput, rxDevice, force, 0); - } else { - setOutputDevice(mPrimaryOutput, rxDevice, force, 0); } // if entering in call state, handle special case of active streams // pertaining to sonification strategy see handleIncallSonification() @@ -543,7 +546,7 @@ void AudioPolicyManager::setForceUse(audio_policy_force_use_t usage, checkA2dpSuspend(); checkOutputForAllStrategies(); updateDevicesAndOutputs(); - if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL) { + if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput()) { audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, true /*fromCache*/); updateCallRouting(newDevice); } @@ -579,24 +582,43 @@ sp<IOProfile> AudioPolicyManager::getProfileForDirectOutput( audio_channel_mask_t channelMask, audio_output_flags_t flags) { + // only retain flags that will drive the direct output profile selection + // if explicitly requested + static const uint32_t kRelevantFlags = + (AUDIO_OUTPUT_FLAG_HW_AV_SYNC | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD); + flags = + (audio_output_flags_t)((flags & kRelevantFlags) | AUDIO_OUTPUT_FLAG_DIRECT); + + sp<IOProfile> profile; + for (size_t i = 0; i < mHwModules.size(); i++) { if (mHwModules[i]->mHandle == 0) { continue; } for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) { - sp<IOProfile> profile = mHwModules[i]->mOutputProfiles[j]; - bool found = profile->isCompatibleProfile(device, String8(""), + sp<IOProfile> curProfile = mHwModules[i]->mOutputProfiles[j]; + if (!curProfile->isCompatibleProfile(device, String8(""), samplingRate, NULL /*updatedSamplingRate*/, format, NULL /*updatedFormat*/, channelMask, NULL /*updatedChannelMask*/, - flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD ? - AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD : AUDIO_OUTPUT_FLAG_DIRECT); - if (found && (mAvailableOutputDevices.types() & profile->mSupportedDevices.types())) { - return profile; + flags)) { + continue; + } + // reject profiles not corresponding to a device currently available + if ((mAvailableOutputDevices.types() & curProfile->mSupportedDevices.types()) == 0) { + continue; + } + // if several profiles are compatible, give priority to one with offload capability + if (profile != 0 && ((curProfile->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0)) { + continue; + } + profile = curProfile; + if ((profile->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) { + break; } } } - return 0; + return profile; } audio_io_handle_t AudioPolicyManager::getOutput(audio_stream_type_t stream, @@ -819,10 +841,27 @@ audio_io_handle_t AudioPolicyManager::getOutputForDevice( if (outputDesc != NULL) { closeOutput(outputDesc->mIoHandle); } + + // if the selected profile is offloaded and no offload info was specified, + // create a default one + audio_offload_info_t defaultOffloadInfo = AUDIO_INFO_INITIALIZER; + if ((profile->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) && !offloadInfo) { + flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD); + defaultOffloadInfo.sample_rate = samplingRate; + defaultOffloadInfo.channel_mask = channelMask; + defaultOffloadInfo.format = format; + defaultOffloadInfo.stream_type = stream; + defaultOffloadInfo.bit_rate = 0; + defaultOffloadInfo.duration_us = -1; + defaultOffloadInfo.has_video = true; // conservative + defaultOffloadInfo.is_streaming = true; // likely + offloadInfo = &defaultOffloadInfo; + } + outputDesc = new SwAudioOutputDescriptor(profile, mpClientInterface); outputDesc->mDevice = device; outputDesc->mLatency = 0; - outputDesc->mFlags =(audio_output_flags_t) (outputDesc->mFlags | flags); + outputDesc->mFlags = (audio_output_flags_t)(outputDesc->mFlags | flags); audio_config_t config = AUDIO_CONFIG_INITIALIZER; config.sample_rate = samplingRate; config.channel_mask = channelMask; @@ -854,10 +893,6 @@ audio_io_handle_t AudioPolicyManager::getOutputForDevice( if (audio_is_linear_pcm(format) && samplingRate <= MAX_MIXER_SAMPLING_RATE) { goto non_direct_output; } - // fall back to mixer output if possible when the direct output could not be open - if (audio_is_linear_pcm(format) && samplingRate <= MAX_MIXER_SAMPLING_RATE) { - goto non_direct_output; - } return AUDIO_IO_HANDLE_NONE; } outputDesc->mSamplingRate = config.sample_rate; @@ -1226,7 +1261,7 @@ void AudioPolicyManager::releaseOutput(audio_io_handle_t output, // If effects where present on the output, audioflinger moved them to the primary // output by default: move them back to the appropriate output. audio_io_handle_t dstOutput = getOutputForEffect(); - if (dstOutput != mPrimaryOutput->mIoHandle) { + if (hasPrimaryOutput() && dstOutput != mPrimaryOutput->mIoHandle) { mpClientInterface->moveEffects(AUDIO_SESSION_OUTPUT_MIX, mPrimaryOutput->mIoHandle, dstOutput); } @@ -1934,7 +1969,8 @@ status_t AudioPolicyManager::dump(int fd) snprintf(buffer, SIZE, "\nAudioPolicyManager Dump: %p\n", this); result.append(buffer); - snprintf(buffer, SIZE, " Primary Output: %d\n", mPrimaryOutput->mIoHandle); + snprintf(buffer, SIZE, " Primary Output: %d\n", + hasPrimaryOutput() ? mPrimaryOutput->mIoHandle : AUDIO_IO_HANDLE_NONE); result.append(buffer); snprintf(buffer, SIZE, " Phone state: %d\n", mEngine->getPhoneState()); result.append(buffer); @@ -2896,7 +2932,7 @@ AudioPolicyManager::~AudioPolicyManager() status_t AudioPolicyManager::initCheck() { - return (mPrimaryOutput == 0) ? NO_INIT : NO_ERROR; + return hasPrimaryOutput() ? NO_ERROR : NO_INIT; } #ifdef AUDIO_POLICY_TEST @@ -3271,7 +3307,8 @@ status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor> de policyMix->setOutput(desc); desc->mPolicyMix = policyMix->getMix(); - } else if ((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) { + } else if (((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) && + hasPrimaryOutput()) { // no duplicated output for direct outputs and // outputs used by dynamic policy mixes audio_io_handle_t duplicatedOutput = AUDIO_IO_HANDLE_NONE; @@ -4600,6 +4637,10 @@ void AudioPolicyManager::setStreamMute(audio_stream_type_t stream, void AudioPolicyManager::handleIncallSonification(audio_stream_type_t stream, bool starting, bool stateChange) { + if(!hasPrimaryOutput()) { + return; + } + // if the stream pertains to sonification strategy and we are in call we must // mute the stream if it is low visibility. If it is high visibility, we must play a tone // in the device used for phone strategy and play the tone if the selected device does not diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h index ea16864..f9d1198 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.h +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h @@ -553,10 +553,16 @@ protected: audio_devices_t availablePrimaryOutputDevices() const { + if (!hasPrimaryOutput()) { + return AUDIO_DEVICE_NONE; + } return mPrimaryOutput->supportedDevices() & mAvailableOutputDevices.types(); } audio_devices_t availablePrimaryInputDevices() const { + if (!hasPrimaryOutput()) { + return AUDIO_DEVICE_NONE; + } return mAvailableInputDevices.getDevicesFromHwModule(mPrimaryOutput->getModuleHandle()); } @@ -576,6 +582,8 @@ protected: void clearSessionRoutes(uid_t uid); void checkStrategyRoute(routing_strategy strategy, audio_io_handle_t ouptutToSkip); + status_t hasPrimaryOutput() const { return mPrimaryOutput != 0; } + uid_t mUidCached; AudioPolicyClientInterface *mpClientInterface; // audio policy client interface sp<SwAudioOutputDescriptor> mPrimaryOutput; // primary output descriptor diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index 527e80b..6f073ed 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -33,6 +33,7 @@ #include <binder/MemoryBase.h> #include <binder/MemoryHeapBase.h> #include <binder/ProcessInfoService.h> +#include <camera/ICameraServiceProxy.h> #include <cutils/atomic.h> #include <cutils/properties.h> #include <gui/Surface.h> @@ -230,6 +231,18 @@ void CameraService::onFirstRef() } CameraDeviceFactory::registerService(this); + + CameraService::pingCameraServiceProxy(); +} + +void CameraService::pingCameraServiceProxy() { + sp<IServiceManager> sm = defaultServiceManager(); + sp<IBinder> binder = sm->getService(String16("media.camera.proxy")); + if (binder == nullptr) { + return; + } + sp<ICameraServiceProxy> proxyBinder = interface_cast<ICameraServiceProxy>(binder); + proxyBinder->pingForUserUpdate(); } CameraService::~CameraService() { @@ -992,6 +1005,10 @@ status_t CameraService::handleEvictionsLocked(const String8& cameraId, int clien "(PID %" PRId32 ", priority %" PRId32 ")", i->getKey().string(), String8{i->getValue()->getPackageName()}.string(), i->getOwnerId(), i->getPriority()); + ALOGE(" Conflicts with: Device %s, client package %s (PID %" + PRId32 ", priority %" PRId32 ")", i->getKey().string(), + String8{i->getValue()->getPackageName()}.string(), i->getOwnerId(), + i->getPriority()); } // Log the client's attempt @@ -2051,7 +2068,7 @@ String8 CameraService::CameraClientManager::toString() const { auto conflicting = i->getConflicting(); auto clientSp = i->getValue(); String8 packageName; - userid_t clientUserId; + userid_t clientUserId = 0; if (clientSp.get() != nullptr) { packageName = String8{clientSp->getPackageName()}; uid_t clientUid = clientSp->getClientUid(); diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h index 2e4743f..3298772 100644 --- a/services/camera/libcameraservice/CameraService.h +++ b/services/camera/libcameraservice/CameraService.h @@ -720,6 +720,8 @@ private: static String8 toString(std::set<userid_t> intSet); + static void pingCameraServiceProxy(); + }; template<class Func> diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp index 05ede92..f2d6ab2 100644 --- a/services/camera/libcameraservice/api1/Camera2Client.cpp +++ b/services/camera/libcameraservice/api1/Camera2Client.cpp @@ -1881,6 +1881,16 @@ void Camera2Client::notifyAutoExposure(uint8_t newState, int triggerId) { mCaptureSequencer->notifyAutoExposure(newState, triggerId); } +void Camera2Client::notifyShutter(const CaptureResultExtras& resultExtras, + nsecs_t timestamp) { + (void)resultExtras; + (void)timestamp; + + ALOGV("%s: Shutter notification for request id %" PRId32 " at time %" PRId64, + __FUNCTION__, resultExtras.requestId, timestamp); + mCaptureSequencer->notifyShutter(resultExtras, timestamp); +} + camera2::SharedParameters& Camera2Client::getParameters() { return mParameters; } diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h index a988037..3784aab 100644 --- a/services/camera/libcameraservice/api1/Camera2Client.h +++ b/services/camera/libcameraservice/api1/Camera2Client.h @@ -106,6 +106,8 @@ public: virtual void notifyAutoFocus(uint8_t newState, int triggerId); virtual void notifyAutoExposure(uint8_t newState, int triggerId); + virtual void notifyShutter(const CaptureResultExtras& resultExtras, + nsecs_t timestamp); /** * Interface used by independent components of Camera2Client. diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp index 9849f4d..d847e0f 100644 --- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp +++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp @@ -43,6 +43,8 @@ CaptureSequencer::CaptureSequencer(wp<Camera2Client> client): mNewFrameReceived(false), mNewCaptureReceived(false), mShutterNotified(false), + mHalNotifiedShutter(false), + mShutterCaptureId(-1), mClient(client), mCaptureState(IDLE), mStateTransitionCount(0), @@ -106,6 +108,16 @@ void CaptureSequencer::notifyAutoExposure(uint8_t newState, int triggerId) { } } +void CaptureSequencer::notifyShutter(const CaptureResultExtras& resultExtras, + nsecs_t timestamp) { + ATRACE_CALL(); + Mutex::Autolock l(mInputMutex); + if (!mHalNotifiedShutter && resultExtras.requestId == mShutterCaptureId) { + mHalNotifiedShutter = true; + mShutterNotifySignal.signal(); + } +} + void CaptureSequencer::onResultAvailable(const CaptureResult &result) { ATRACE_CALL(); ALOGV("%s: New result available.", __FUNCTION__); @@ -335,6 +347,11 @@ CaptureSequencer::CaptureState CaptureSequencer::manageStart( } else { nextState = STANDARD_START; } + { + Mutex::Autolock l(mInputMutex); + mShutterCaptureId = mCaptureId; + mHalNotifiedShutter = false; + } mShutterNotified = false; return nextState; @@ -541,6 +558,7 @@ CaptureSequencer::CaptureState CaptureSequencer::manageStandardCapture( return DONE; } } + // TODO: Capture should be atomic with setStreamingRequest here res = client->getCameraDevice()->capture(captureCopy); if (res != OK) { @@ -560,6 +578,31 @@ CaptureSequencer::CaptureState CaptureSequencer::manageStandardCaptureWait( ATRACE_CALL(); Mutex::Autolock l(mInputMutex); + + // Wait for shutter callback + while (!mHalNotifiedShutter) { + if (mTimeoutCount <= 0) { + break; + } + res = mShutterNotifySignal.waitRelative(mInputMutex, kWaitDuration); + if (res == TIMED_OUT) { + mTimeoutCount--; + return STANDARD_CAPTURE_WAIT; + } + } + + if (mHalNotifiedShutter) { + if (!mShutterNotified) { + SharedParameters::Lock l(client->getParameters()); + /* warning: this also locks a SharedCameraCallbacks */ + shutterNotifyLocked(l.mParameters, client, mMsgType); + mShutterNotified = true; + } + } else if (mTimeoutCount <= 0) { + ALOGW("Timed out waiting for shutter notification"); + return DONE; + } + // Wait for new metadata result (mNewFrame) while (!mNewFrameReceived) { res = mNewFrameSignal.waitRelative(mInputMutex, kWaitDuration); @@ -569,15 +612,6 @@ CaptureSequencer::CaptureState CaptureSequencer::manageStandardCaptureWait( } } - // Approximation of the shutter being closed - // - TODO: use the hal3 exposure callback in Camera3Device instead - if (mNewFrameReceived && !mShutterNotified) { - SharedParameters::Lock l(client->getParameters()); - /* warning: this also locks a SharedCameraCallbacks */ - shutterNotifyLocked(l.mParameters, client, mMsgType); - mShutterNotified = true; - } - // Wait until jpeg was captured by JpegProcessor while (mNewFrameReceived && !mNewCaptureReceived) { res = mNewCaptureSignal.waitRelative(mInputMutex, kWaitDuration); @@ -591,6 +625,7 @@ CaptureSequencer::CaptureState CaptureSequencer::manageStandardCaptureWait( return DONE; } if (mNewFrameReceived && mNewCaptureReceived) { + if (mNewFrameId != mCaptureId) { ALOGW("Mismatched capture frame IDs: Expected %d, got %d", mCaptureId, mNewFrameId); @@ -667,7 +702,6 @@ CaptureSequencer::CaptureState CaptureSequencer::manageBurstCaptureWait( sp<Camera2Client> &/*client*/) { status_t res; ATRACE_CALL(); - while (!mNewCaptureReceived) { res = mNewCaptureSignal.waitRelative(mInputMutex, kWaitDuration); if (res == TIMED_OUT) { diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h index d42ab13..10252fb 100644 --- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h +++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h @@ -62,6 +62,10 @@ class CaptureSequencer: // Notifications about AE state changes void notifyAutoExposure(uint8_t newState, int triggerId); + // Notifications about shutter (capture start) + void notifyShutter(const CaptureResultExtras& resultExtras, + nsecs_t timestamp); + // Notification from the frame processor virtual void onResultAvailable(const CaptureResult &result); @@ -95,7 +99,10 @@ class CaptureSequencer: sp<MemoryBase> mCaptureBuffer; Condition mNewCaptureSignal; - bool mShutterNotified; + bool mShutterNotified; // Has CaptureSequencer sent shutter to Client + bool mHalNotifiedShutter; // Has HAL sent shutter to CaptureSequencer + int32_t mShutterCaptureId; // The captureId which is waiting for shutter notification + Condition mShutterNotifySignal; /** * Internal to CaptureSequencer diff --git a/services/camera/libcameraservice/common/CameraModule.cpp b/services/camera/libcameraservice/common/CameraModule.cpp index c662853..2f0117d 100644 --- a/services/camera/libcameraservice/common/CameraModule.cpp +++ b/services/camera/libcameraservice/common/CameraModule.cpp @@ -31,7 +31,7 @@ void CameraModule::deriveCameraCharacteristicsKeys( // Keys added in HAL3.3 if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_3) { - const size_t NUM_DERIVED_KEYS_HAL3_3 = 3; + const size_t NUM_DERIVED_KEYS_HAL3_3 = 5; Vector<uint8_t> controlModes; uint8_t data = ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE; chars.update(ANDROID_CONTROL_AE_LOCK_AVAILABLE, &data, /*count*/1); @@ -80,6 +80,29 @@ void CameraModule::deriveCameraCharacteristicsKeys( chars.update(ANDROID_CONTROL_AVAILABLE_MODES, controlModes); + entry = chars.find(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS); + // HAL3.2 devices passing existing CTS test should all support all LSC modes and LSC map + bool lensShadingModeSupported = false; + if (entry.count > 0) { + for (size_t i = 0; i < entry.count; i++) { + if (entry.data.i32[i] == ANDROID_SHADING_MODE) { + lensShadingModeSupported = true; + break; + } + } + } + Vector<uint8_t> lscModes; + Vector<uint8_t> lscMapModes; + lscModes.push(ANDROID_SHADING_MODE_FAST); + lscModes.push(ANDROID_SHADING_MODE_HIGH_QUALITY); + lscMapModes.push(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF); + if (lensShadingModeSupported) { + lscModes.push(ANDROID_SHADING_MODE_OFF); + lscMapModes.push(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_ON); + } + chars.update(ANDROID_SHADING_AVAILABLE_MODES, lscModes); + chars.update(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES, lscMapModes); + entry = chars.find(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS); Vector<int32_t> availableCharsKeys; availableCharsKeys.setCapacity(entry.count + NUM_DERIVED_KEYS_HAL3_3); @@ -87,9 +110,12 @@ void CameraModule::deriveCameraCharacteristicsKeys( availableCharsKeys.push(entry.data.i32[i]); } availableCharsKeys.push(ANDROID_CONTROL_AE_LOCK_AVAILABLE); - availableCharsKeys.push(ANDROID_CONTROL_AWB_LOCK_AVAILABLE_TRUE); + availableCharsKeys.push(ANDROID_CONTROL_AWB_LOCK_AVAILABLE); availableCharsKeys.push(ANDROID_CONTROL_AVAILABLE_MODES); + availableCharsKeys.push(ANDROID_SHADING_AVAILABLE_MODES); + availableCharsKeys.push(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES); chars.update(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, availableCharsKeys); + } return; } diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp index 445c9c2..45d9421 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.cpp +++ b/services/camera/libcameraservice/device3/Camera3Device.cpp @@ -2613,6 +2613,21 @@ status_t Camera3Device::RequestThread::clear( if (listener != NULL) { for (RequestList::iterator it = mRequestQueue.begin(); it != mRequestQueue.end(); ++it) { + // Abort the input buffers for reprocess requests. + if ((*it)->mInputStream != NULL) { + camera3_stream_buffer_t inputBuffer; + status_t res = (*it)->mInputStream->getInputBuffer(&inputBuffer); + if (res != OK) { + ALOGW("%s: %d: couldn't get input buffer while clearing the request " + "list: %s (%d)", __FUNCTION__, __LINE__, strerror(-res), res); + } else { + res = (*it)->mInputStream->returnInputBuffer(inputBuffer); + if (res != OK) { + ALOGE("%s: %d: couldn't return input buffer while clearing the request " + "list: %s (%d)", __FUNCTION__, __LINE__, strerror(-res), res); + } + } + } // Set the frame number this request would have had, if it // had been submitted; this frame number will not be reused. // The requestId and burstId fields were set when the request was @@ -2752,29 +2767,11 @@ bool Camera3Device::RequestThread::threadLoop() { __FUNCTION__); } - camera3_stream_buffer_t inputBuffer; uint32_t totalNumBuffers = 0; // Fill in buffers - if (nextRequest->mInputStream != NULL) { - res = nextRequest->mInputStream->getInputBuffer(&inputBuffer); - if (res != OK) { - // Can't get input buffer from gralloc queue - this could be due to - // disconnected queue or other producer misbehavior, so not a fatal - // error - ALOGE("RequestThread: Can't get input buffer, skipping request:" - " %s (%d)", strerror(-res), res); - Mutex::Autolock l(mRequestLock); - if (mListener != NULL) { - mListener->notifyError( - ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST, - nextRequest->mResultExtras); - } - cleanUpFailedRequest(request, nextRequest, outputBuffers); - return true; - } - request.input_buffer = &inputBuffer; + request.input_buffer = &nextRequest->mInputBuffer; totalNumBuffers += 1; } else { request.input_buffer = NULL; @@ -2792,11 +2789,13 @@ bool Camera3Device::RequestThread::threadLoop() { // error ALOGE("RequestThread: Can't get output buffer, skipping request:" " %s (%d)", strerror(-res), res); - Mutex::Autolock l(mRequestLock); - if (mListener != NULL) { - mListener->notifyError( - ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST, - nextRequest->mResultExtras); + { + Mutex::Autolock l(mRequestLock); + if (mListener != NULL) { + mListener->notifyError( + ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST, + nextRequest->mResultExtras); + } } cleanUpFailedRequest(request, nextRequest, outputBuffers); return true; @@ -2865,6 +2864,12 @@ bool Camera3Device::RequestThread::threadLoop() { nextRequest->mSettings.unlock(request.settings); } + // Unset as current request + { + Mutex::Autolock l(mRequestLock); + mNextRequest.clear(); + } + // Remove any previously queued triggers (after unlock) res = removeTriggers(mPrevRequest); if (res != OK) { @@ -2890,6 +2895,13 @@ bool Camera3Device::RequestThread::isStreamPending( sp<Camera3StreamInterface>& stream) { Mutex::Autolock l(mRequestLock); + if (mNextRequest != nullptr) { + for (const auto& s : mNextRequest->mOutputStreams) { + if (stream == s) return true; + } + if (stream == mNextRequest->mInputStream) return true; + } + for (const auto& request : mRequestQueue) { for (const auto& s : request->mOutputStreams) { if (stream == s) return true; @@ -2915,15 +2927,18 @@ void Camera3Device::RequestThread::cleanUpFailedRequest( if (request.settings != NULL) { nextRequest->mSettings.unlock(request.settings); } - if (request.input_buffer != NULL) { - request.input_buffer->status = CAMERA3_BUFFER_STATUS_ERROR; - nextRequest->mInputStream->returnInputBuffer(*(request.input_buffer)); + if (nextRequest->mInputStream != NULL) { + nextRequest->mInputBuffer.status = CAMERA3_BUFFER_STATUS_ERROR; + nextRequest->mInputStream->returnInputBuffer(nextRequest->mInputBuffer); } for (size_t i = 0; i < request.num_output_buffers; i++) { outputBuffers.editItemAt(i).status = CAMERA3_BUFFER_STATUS_ERROR; nextRequest->mOutputStreams.editItemAt(i)->returnBuffer( outputBuffers[i], 0); } + + Mutex::Autolock l(mRequestLock); + mNextRequest.clear(); } sp<Camera3Device::CaptureRequest> @@ -3006,7 +3021,28 @@ sp<Camera3Device::CaptureRequest> nextRequest->mResultExtras.frameNumber = mFrameNumber++; nextRequest->mResultExtras.afTriggerId = mCurrentAfTriggerId; nextRequest->mResultExtras.precaptureTriggerId = mCurrentPreCaptureTriggerId; + + // Since RequestThread::clear() removes buffers from the input stream, + // get the right buffer here before unlocking mRequestLock + if (nextRequest->mInputStream != NULL) { + res = nextRequest->mInputStream->getInputBuffer(&nextRequest->mInputBuffer); + if (res != OK) { + // Can't get input buffer from gralloc queue - this could be due to + // disconnected queue or other producer misbehavior, so not a fatal + // error + ALOGE("%s: Can't get input buffer, skipping request:" + " %s (%d)", __FUNCTION__, strerror(-res), res); + if (mListener != NULL) { + mListener->notifyError( + ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST, + nextRequest->mResultExtras); + } + return NULL; + } + } } + mNextRequest = nextRequest; + return nextRequest; } diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h index 4fbcb2e..b9313fc 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.h +++ b/services/camera/libcameraservice/device3/Camera3Device.h @@ -234,6 +234,7 @@ class Camera3Device : public: CameraMetadata mSettings; sp<camera3::Camera3Stream> mInputStream; + camera3_stream_buffer_t mInputBuffer; Vector<sp<camera3::Camera3OutputStreamInterface> > mOutputStreams; CaptureResultExtras mResultExtras; @@ -501,6 +502,10 @@ class Camera3Device : Condition mRequestSignal; RequestList mRequestQueue; RequestList mRepeatingRequests; + // The next request being prepped for submission to the HAL, no longer + // on the request queue. Read-only even with mRequestLock held, outside + // of threadLoop + sp<const CaptureRequest> mNextRequest; bool mReconfigured; diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp index 081aff7..9de6fe2 100644 --- a/services/soundtrigger/SoundTriggerHwService.cpp +++ b/services/soundtrigger/SoundTriggerHwService.cpp @@ -787,6 +787,7 @@ void SoundTriggerHwService::Module::setCaptureState_l(bool active) mHwDevice->stop_recognition(mHwDevice, model->mHandle); // keep model in ACTIVE state so that event is processed by onCallbackEvent() struct sound_trigger_phrase_recognition_event phraseEvent; + memset(&phraseEvent, 0, sizeof(struct sound_trigger_phrase_recognition_event)); switch (model->mType) { case SOUND_MODEL_TYPE_KEYPHRASE: phraseEvent.num_phrases = model->mConfig.num_phrases; |