diff options
46 files changed, 1321 insertions, 484 deletions
diff --git a/audio/Android.bp b/audio/Android.bp index 4905fe57..27dfbf8e 100644 --- a/audio/Android.bp +++ b/audio/Android.bp @@ -13,9 +13,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -cc_library_shared { - name: "android.hardware.audio@6.0-impl.ranchu", +cc_binary { + name: "android.hardware.audio.service.ranchu", vendor: true, + init_rc: ["android.hardware.audio.service.ranchu.rc"], vintf_fragments: ["android.hardware.audio@6.0-impl.ranchu.xml"], relative_install_path: "hw", defaults: ["hidl_defaults"], @@ -27,6 +28,8 @@ cc_library_shared { "stream_in.cpp", "stream_out.cpp", "io_thread.cpp", + "device_port_source.cpp", + "device_port_sink.cpp", "talsa.cpp", "util.cpp", ], @@ -34,7 +37,9 @@ cc_library_shared { "android.hardware.audio@6.0", "android.hardware.audio.common@6.0", "android.hardware.audio.common@6.0-util", + "libaudioutils", "libbase", + "libbinder", "libcutils", "libhidlbase", "liblog", @@ -47,6 +52,13 @@ cc_library_shared { "libaudio_system_headers", ], cflags: [ - "-DLOG_TAG=\"android.hardware.audio@6.0-impl.ranchu\"", + "-DLOG_TAG=\"android.hardware.audio.service.ranchu\"", + ], + // android.hardware.audio.service.ranchu loads android.hardware.audio@6.0-impl + // which loads audio.r_submix.default which provides the r_submix device, + // see b/161485545. Should be retired once a better r_submix is available. + required: [ + "android.hardware.audio@6.0-impl", + "audio.r_submix.default", ], } diff --git a/audio/android.hardware.audio.service.ranchu.rc b/audio/android.hardware.audio.service.ranchu.rc new file mode 100644 index 00000000..777c2297 --- /dev/null +++ b/audio/android.hardware.audio.service.ranchu.rc @@ -0,0 +1,9 @@ +service vendor.audio-hal /vendor/bin/hw/android.hardware.audio.service.ranchu + class hal + user audioserver + # media gid needed for /dev/fm (radio) and for /data/misc/media (tee) + group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct wakelock context_hub + capabilities BLOCK_SUSPEND + ioprio rt 4 + task_profiles ProcessCapacityHigh HighPerformance + onrestart restart audioserver diff --git a/audio/debug.h b/audio/debug.h new file mode 100644 index 00000000..60d884ae --- /dev/null +++ b/audio/debug.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#if 1 + +#include <log/log.h> + +#define FAILURE(x) \ + (ALOGE("%s:%s:%d failure: %s", __FILE__, __func__, __LINE__, #x), x) + +#else + +#define FAILURE(x) x + +#endif diff --git a/audio/device_factory.cpp b/audio/device_factory.cpp index e0bbf1f5..32a9a04a 100644 --- a/audio/device_factory.cpp +++ b/audio/device_factory.cpp @@ -14,10 +14,11 @@ * limitations under the License. */ -#include "device_factory.h" -#include "primary_device.h" #include <system/audio.h> #include <log/log.h> +#include "device_factory.h" +#include "primary_device.h" +#include "debug.h" namespace android { namespace hardware { @@ -27,23 +28,34 @@ namespace implementation { using ::android::hardware::Void; -Return<void> DevicesFactory::openDevice(const hidl_string& device, - openDevice_cb _hidl_cb) { - Result result = Result::OK; - std::unique_ptr<IDevice> dev; +#ifdef __LP64__ +#define LIB_PATH_PREFIX "vendor/lib64/hw/" +#else +#define LIB_PATH_PREFIX "vendor/lib/hw/" +#endif - if (device == AUDIO_HARDWARE_MODULE_ID_PRIMARY) { - dev = std::make_unique<PrimaryDevice>(); - } else { - result = Result::INVALID_ARGUMENTS; - } +DevicesFactory::DevicesFactory() { + mLegacyLib.reset(dlopen( + LIB_PATH_PREFIX "android.hardware.audio@6.0-impl.so", RTLD_NOW)); + LOG_ALWAYS_FATAL_IF(!mLegacyLib); + + typedef IDevicesFactory *(*Func)(const char *); + const auto func = reinterpret_cast<Func>( + dlsym(mLegacyLib.get(), "HIDL_FETCH_IDevicesFactory")); + LOG_ALWAYS_FATAL_IF(!func); + + mLegacyFactory.reset((*func)("default")); + LOG_ALWAYS_FATAL_IF(!mLegacyFactory); +} - if (!dev) { - ALOGE("DevicesFactory::%s:%d: failed, device='%s' result='%s'", - __func__, __LINE__, device.c_str(), toString(result).c_str()); +Return<void> DevicesFactory::openDevice(const hidl_string& device, + openDevice_cb _hidl_cb) { + if (device == AUDIO_HARDWARE_MODULE_ID_PRIMARY) + _hidl_cb(Result::OK, new PrimaryDevice); + else { + mLegacyFactory->openDevice(device, _hidl_cb); } - _hidl_cb(result, dev.release()); return Void(); } diff --git a/audio/device_factory.h b/audio/device_factory.h index ac653d0d..cc33be5a 100644 --- a/audio/device_factory.h +++ b/audio/device_factory.h @@ -15,7 +15,9 @@ */ #pragma once +#include <memory> #include <android/hardware/audio/6.0/IDevicesFactory.h> +#include <dlfcn.h> namespace android { namespace hardware { @@ -29,8 +31,20 @@ using ::android::hardware::Return; using namespace ::android::hardware::audio::V6_0; struct DevicesFactory : public IDevicesFactory { + DevicesFactory(); + Return<void> openDevice(const hidl_string& device, openDevice_cb _hidl_cb) override; Return<void> openPrimaryDevice(openPrimaryDevice_cb _hidl_cb) override; + +private: + struct DLDeleter { + void operator()(void* dl) const { + ::dlclose(dl); + } + }; + + std::unique_ptr<void, DLDeleter> mLegacyLib; + std::unique_ptr<IDevicesFactory> mLegacyFactory; }; } // namespace implementation diff --git a/audio/device_port_sink.cpp b/audio/device_port_sink.cpp new file mode 100644 index 00000000..0a34eb21 --- /dev/null +++ b/audio/device_port_sink.cpp @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <log/log.h> +#include <utils/Timers.h> +#include "device_port_sink.h" +#include "talsa.h" +#include "util.h" +#include "debug.h" + +namespace android { +namespace hardware { +namespace audio { +namespace V6_0 { +namespace implementation { + +namespace { + +struct TinyalsaSink : public DevicePortSink { + TinyalsaSink(unsigned pcmCard, unsigned pcmDevice, + const AudioConfig &cfg, uint64_t &frames) + : mFrames(frames) + , mPcm(talsa::pcmOpen(pcmCard, pcmDevice, + util::countChannels(cfg.channelMask), + cfg.sampleRateHz, + cfg.frameCount, + true /* isOut */)) {} + + Result getPresentationPosition(uint64_t &frames, TimeSpec &ts) override { + frames = mFrames; + ts = util::nsecs2TimeSpec(systemTime(SYSTEM_TIME_MONOTONIC)); + return Result::OK; + } + + int write(const void *data, size_t nBytes) override { + const int res = ::pcm_write(mPcm.get(), data, nBytes); + if (res < 0) { + return FAILURE(res); + } else if (res == 0) { + mFrames += ::pcm_bytes_to_frames(mPcm.get(), nBytes); + return nBytes; + } else { + mFrames += ::pcm_bytes_to_frames(mPcm.get(), res); + return res; + } + } + + static std::unique_ptr<TinyalsaSink> create(unsigned pcmCard, + unsigned pcmDevice, + const AudioConfig &cfg, + uint64_t &frames) { + auto src = std::make_unique<TinyalsaSink>(pcmCard, pcmDevice, cfg, frames); + if (src->mPcm) { + return src; + } else { + return FAILURE(nullptr); + } + } + +private: + uint64_t &mFrames; + talsa::PcmPtr mPcm; +}; + +struct NullSink : public DevicePortSink { + NullSink(const AudioConfig &cfg, uint64_t &frames) + : mFrames(frames) + , mSampleRateHz(cfg.sampleRateHz) + , mNChannels(util::countChannels(cfg.channelMask)) + , mTimestamp(systemTime(SYSTEM_TIME_MONOTONIC)) {} + + Result getPresentationPosition(uint64_t &frames, TimeSpec &ts) override { + simulatePresentationPosition(); + frames = mFrames; + ts = util::nsecs2TimeSpec(mTimestamp); + return Result::OK; + } + + int write(const void *, size_t nBytes) override { + simulatePresentationPosition(); + mAvailableFrames += nBytes / mNChannels / sizeof(int16_t); + return nBytes; + } + + void simulatePresentationPosition() { + const nsecs_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC); + const nsecs_t deltaNs = nowNs - mTimestamp; + const uint64_t deltaFrames = uint64_t(mSampleRateHz) * ns2ms(deltaNs) / 1000; + const uint64_t f = std::min(deltaFrames, mAvailableFrames); + + mFrames += f; + mAvailableFrames -= f; + if (mAvailableFrames) { + mTimestamp += us2ns(f * 1000000 / mSampleRateHz); + } else { + mTimestamp = nowNs; + } + } + + static std::unique_ptr<NullSink> create(const AudioConfig &cfg, + uint64_t &frames) { + return std::make_unique<NullSink>(cfg, frames); + } + +private: + uint64_t &mFrames; + const unsigned mSampleRateHz; + const unsigned mNChannels; + uint64_t mAvailableFrames = 0; + nsecs_t mTimestamp; +}; + +} // namespace + +std::unique_ptr<DevicePortSink> +DevicePortSink::create(const DeviceAddress &address, + const AudioConfig &cfg, + const hidl_bitfield<AudioOutputFlag> &flags, + uint64_t &frames) { + (void)flags; + + if (cfg.format != AudioFormat::PCM_16_BIT) { + ALOGE("%s:%d Only PCM_16_BIT is supported", __func__, __LINE__); + return FAILURE(nullptr); + } + + switch (address.device) { + case AudioDevice::OUT_SPEAKER: + return TinyalsaSink::create(talsa::kPcmCard, talsa::kPcmDevice, + cfg, frames); + + case AudioDevice::OUT_TELEPHONY_TX: + return NullSink::create(cfg, frames); + + default: + ALOGE("%s:%d unsupported device: %x", __func__, __LINE__, address.device); + return FAILURE(nullptr); + } +} + +} // namespace implementation +} // namespace V6_0 +} // namespace audio +} // namespace hardware +} // namespace android diff --git a/audio/device_port_sink.h b/audio/device_port_sink.h new file mode 100644 index 00000000..5714cd06 --- /dev/null +++ b/audio/device_port_sink.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include <memory> +#include <android/hardware/audio/common/6.0/types.h> +#include <android/hardware/audio/6.0/types.h> + +namespace android { +namespace hardware { +namespace audio { +namespace V6_0 { +namespace implementation { + +using namespace ::android::hardware::audio::common::V6_0; +using namespace ::android::hardware::audio::V6_0; + +struct DevicePortSink { + virtual ~DevicePortSink() {} + virtual Result getPresentationPosition(uint64_t &frames, TimeSpec &ts) = 0; + virtual int write(const void *data, size_t nBytes) = 0; + + static std::unique_ptr<DevicePortSink> create(const DeviceAddress &, + const AudioConfig &, + const hidl_bitfield<AudioOutputFlag> &, + uint64_t &frames); +}; + +} // namespace implementation +} // namespace V6_0 +} // namespace audio +} // namespace hardware +} // namespace android diff --git a/audio/device_port_source.cpp b/audio/device_port_source.cpp new file mode 100644 index 00000000..a82d281f --- /dev/null +++ b/audio/device_port_source.cpp @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <cmath> +#include <chrono> +#include <thread> +#include <audio_utils/channels.h> +#include <audio_utils/format.h> +#include <log/log.h> +#include <utils/Timers.h> +#include "device_port_source.h" +#include "talsa.h" +#include "util.h" +#include "debug.h" + +namespace android { +namespace hardware { +namespace audio { +namespace V6_0 { +namespace implementation { + +namespace { + +struct TinyalsaSource : public DevicePortSource { + TinyalsaSource(unsigned pcmCard, unsigned pcmDevice, + const AudioConfig &cfg, uint64_t &frames) + : mFrames(frames) + , mPcm(talsa::pcmOpen(pcmCard, pcmDevice, + util::countChannels(cfg.channelMask), + cfg.sampleRateHz, + cfg.frameCount, + false /* isOut */)) {} + + Result getCapturePosition(uint64_t &frames, uint64_t &time) override { + frames = mFrames; + time = systemTime(SYSTEM_TIME_MONOTONIC); + return Result::OK; + } + + int read(void *data, size_t toReadBytes) override { + const int res = ::pcm_read(mPcm.get(), data, toReadBytes); + if (res < 0) { + return FAILURE(res); + } else if (res == 0) { + mFrames += ::pcm_bytes_to_frames(mPcm.get(), toReadBytes); + return toReadBytes; + } else { + mFrames += ::pcm_bytes_to_frames(mPcm.get(), res); + return res; + } + } + + static std::unique_ptr<TinyalsaSource> create(unsigned pcmCard, + unsigned pcmDevice, + const AudioConfig &cfg, + uint64_t &frames) { + auto src = std::make_unique<TinyalsaSource>(pcmCard, pcmDevice, cfg, frames); + if (src->mPcm) { + return src; + } else { + return FAILURE(nullptr); + } + } + +private: + uint64_t &mFrames; + talsa::PcmPtr mPcm; +}; + +template <class G> struct GeneratedSource : public DevicePortSource { + GeneratedSource(const AudioConfig &cfg, uint64_t &frames, G generator) + : mFrames(frames) + , mStartNs(systemTime(SYSTEM_TIME_MONOTONIC)) + , mSampleRateHz(cfg.sampleRateHz) + , mNChannels(util::countChannels(cfg.channelMask)) + , mGenerator(std::move(generator)) {} + + Result getCapturePosition(uint64_t &frames, uint64_t &time) override { + const nsecs_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC); + const uint64_t nowFrames = getNowFrames(nowNs); + mFrames += (nowFrames - mPreviousFrames); + mPreviousFrames = nowFrames; + frames = mFrames; + time = nowNs; + return Result::OK; + } + + uint64_t getNowFrames(const nsecs_t nowNs) const { + return uint64_t(mSampleRateHz) * ns2ms(nowNs - mStartNs) / 1000; + } + + int read(void *data, size_t toReadBytes) override { + int16_t *samples = static_cast<int16_t *>(data); + const unsigned nChannels = mNChannels; + const unsigned requestedFrames = toReadBytes / nChannels / sizeof(*samples); + + unsigned availableFrames; + while (true) { + const nsecs_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC); + availableFrames = getNowFrames(nowNs) - mSentFrames; + if (availableFrames < requestedFrames / 2) { + const unsigned neededMoreFrames = requestedFrames / 2 - availableFrames; + + using namespace std::chrono_literals; + std::this_thread::sleep_for(1s * neededMoreFrames / mSampleRateHz); + } else { + break; + } + } + + const unsigned nFrames = std::min(requestedFrames, availableFrames); + mGenerator(samples, nFrames); + const size_t sizeBytes = nFrames * nChannels * sizeof(*samples); + if (nChannels > 1) { + adjust_channels(samples, 1, samples, nChannels, + sizeof(*samples), sizeBytes); + } + + mSentFrames += nFrames; + return sizeBytes; + } + +private: + uint64_t &mFrames; + const nsecs_t mStartNs; + const unsigned mSampleRateHz; + const unsigned mNChannels; + uint64_t mPreviousFrames = 0; + uint64_t mSentFrames = 0; + G mGenerator; +}; + +std::vector<int16_t> convertFloatsToInt16(const std::vector<float> &pcmFloat) { + std::vector<int16_t> pcmI16(pcmFloat.size()); + + memcpy_by_audio_format(pcmI16.data(), AUDIO_FORMAT_PCM_16_BIT, + pcmFloat.data(), AUDIO_FORMAT_PCM_FLOAT, + pcmFloat.size()); + + return pcmI16; +} + +// https://en.wikipedia.org/wiki/Busy_signal +struct BusySignalGenerator { + explicit BusySignalGenerator(const uint32_t sampleRateHz) : mSampleRateHz(sampleRateHz) { + // 24/480 = 31/620, mValues must contain 50ms of audio samples + const size_t sz = sampleRateHz / 20; + std::vector<float> pcm(sz); + for (unsigned i = 0; i < sz; ++i) { + const double a = double(i) * M_PI * 2 / sampleRateHz; + pcm[i] = .5 * (sin(480 * a) + sin(620 * a)); + } + mValues = convertFloatsToInt16(pcm); + } + + void operator()(int16_t* s, size_t n) { + const unsigned rate = mSampleRateHz; + const unsigned rateHalf = rate / 2; + const int16_t *const vals = mValues.data(); + const size_t valsSz = mValues.size(); + size_t i = mI; + + while (n > 0) { + size_t len; + if (i < rateHalf) { + const size_t valsOff = i % valsSz; + len = std::min(n, std::min(rateHalf - i, valsSz - valsOff)); + memcpy(s, vals + valsOff, len * sizeof(*s)); + } else { + len = std::min(n, rate - i); + memset(s, 0, len * sizeof(*s)); + } + s += len; + i = (i + len) % rate; + n -= len; + } + + mI = i; + } + +private: + const unsigned mSampleRateHz; + std::vector<int16_t> mValues; + size_t mI = 0; +}; + +struct RepeatGenerator { + explicit RepeatGenerator(const std::vector<float> &pcm) + : mValues(convertFloatsToInt16(pcm)) {} + + void operator()(int16_t* s, size_t n) { + const int16_t *const vals = mValues.data(); + const size_t valsSz = mValues.size(); + size_t i = mI; + + while (n > 0) { + const size_t len = std::min(n, valsSz - i); + memcpy(s, vals + i, len * sizeof(*s)); + s += len; + i = (i + len) % valsSz; + n -= len; + } + + mI = i; + } + +private: + const std::vector<int16_t> mValues; + size_t mI = 0; +}; + +std::vector<float> generateSinePattern(uint32_t sampleRateHz, + double freq, + double amp) { + std::vector<float> result(3 * sampleRateHz / freq + .5); + + for (size_t i = 0; i < result.size(); ++i) { + const double a = double(i) * M_PI * 2 / sampleRateHz; + result[i] = amp * sin(a * freq); + } + + return result; +} + +template <class G> std::unique_ptr<GeneratedSource<G>> +createGeneratedSource(const AudioConfig &cfg, uint64_t &frames, G generator) { + return std::make_unique<GeneratedSource<G>>(cfg, frames, std::move(generator)); +} + +} // namespace + +std::unique_ptr<DevicePortSource> +DevicePortSource::create(const DeviceAddress &address, + const AudioConfig &cfg, + const hidl_bitfield<AudioOutputFlag> &flags, + uint64_t &frames) { + (void)flags; + + if (cfg.format != AudioFormat::PCM_16_BIT) { + ALOGE("%s:%d Only PCM_16_BIT is supported", __func__, __LINE__); + return FAILURE(nullptr); + } + + switch (address.device) { + case AudioDevice::IN_BUILTIN_MIC: + return TinyalsaSource::create(talsa::kPcmCard, talsa::kPcmDevice, + cfg, frames); + + case AudioDevice::IN_TELEPHONY_RX: + return createGeneratedSource(cfg, frames, + BusySignalGenerator(cfg.sampleRateHz)); + + case AudioDevice::IN_FM_TUNER: + return createGeneratedSource( + cfg, frames, + RepeatGenerator(generateSinePattern(cfg.sampleRateHz, 440.0, 1.0))); + + default: + ALOGE("%s:%d unsupported device: %x", __func__, __LINE__, address.device); + return FAILURE(nullptr); + } +} + +} // namespace implementation +} // namespace V6_0 +} // namespace audio +} // namespace hardware +} // namespace android diff --git a/audio/device_port_source.h b/audio/device_port_source.h new file mode 100644 index 00000000..3cc39ffe --- /dev/null +++ b/audio/device_port_source.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include <memory> +#include <android/hardware/audio/common/6.0/types.h> +#include <android/hardware/audio/6.0/types.h> + +namespace android { +namespace hardware { +namespace audio { +namespace V6_0 { +namespace implementation { + +using namespace ::android::hardware::audio::common::V6_0; +using namespace ::android::hardware::audio::V6_0; + +struct DevicePortSource { + virtual ~DevicePortSource() {} + virtual Result getCapturePosition(uint64_t &frames, uint64_t &time) = 0; + virtual int read(void *data, size_t nBytes) = 0; + + static std::unique_ptr<DevicePortSource> create(const DeviceAddress &, + const AudioConfig &, + const hidl_bitfield<AudioOutputFlag> &, + uint64_t &frames); +}; + +} // namespace implementation +} // namespace V6_0 +} // namespace audio +} // namespace hardware +} // namespace android diff --git a/audio/entry.cpp b/audio/entry.cpp index 1d48f432..7cbeb6d1 100644 --- a/audio/entry.cpp +++ b/audio/entry.cpp @@ -14,12 +14,37 @@ * limitations under the License. */ +#include <binder/ProcessState.h> +#include <hwbinder/ProcessState.h> +#include <hidl/LegacySupport.h> #include "device_factory.h" -using android::hardware::audio::V6_0::IDevicesFactory; -using android::hardware::audio::V6_0::implementation::DevicesFactory; +int main(int, char**) { + using ::android::sp; + using ::android::OK; + using ::android::hardware::audio::V6_0::IDevicesFactory; + using ::android::hardware::audio::V6_0::implementation::DevicesFactory; + using ::android::hardware::registerPassthroughServiceImplementation; -extern "C" IDevicesFactory* HIDL_FETCH_IDevicesFactory(const char* name) { - (void)name; - return new DevicesFactory(); + ::android::ProcessState::initWithDriver("/dev/vndbinder"); + ::android::ProcessState::self()->startThreadPool(); + ::android::hardware::configureRpcThreadpool(16, true /* callerWillJoin */); + + sp<IDevicesFactory> factory(new DevicesFactory()); + if (factory->registerAsService() != ::android::NO_ERROR) { + return -EINVAL; + } + + if (registerPassthroughServiceImplementation( + "android.hardware.audio.effect@6.0::IEffectsFactory") != OK) { + return -EINVAL; + } + + if (registerPassthroughServiceImplementation( + "android.hardware.soundtrigger@2.2::ISoundTriggerHw") != OK) { + return -EINVAL; + } + + ::android::hardware::joinRpcThreadpool(); + return 0; } diff --git a/audio/io_thread.cpp b/audio/io_thread.cpp index 81982b36..b87c5e4c 100644 --- a/audio/io_thread.cpp +++ b/audio/io_thread.cpp @@ -15,6 +15,7 @@ */ #include "io_thread.h" +#include "debug.h" namespace android { namespace hardware { @@ -24,7 +25,15 @@ namespace implementation { bool IOThread::notify(const uint32_t mask) { EventFlag *evf = getEventFlag(); - return evf ? (NO_ERROR == evf->wake(mask)) : false; + if (evf) { + if (NO_ERROR == evf->wake(mask)) { + return true; + } else { + return FAILURE(false); + } + } else { + return FAILURE(false); + } } bool IOThread::standby() { diff --git a/audio/policy/audio_policy_configuration.xml b/audio/policy/audio_policy_configuration.xml index f631bb0d..34e8aff5 100644 --- a/audio/policy/audio_policy_configuration.xml +++ b/audio/policy/audio_policy_configuration.xml @@ -24,6 +24,9 @@ <!-- Primary Audio HAL --> <xi:include href="primary_audio_policy_configuration.xml"/> + <!-- Remote Submix Audio HAL --> + <xi:include href="r_submix_audio_policy_configuration.xml"/> + </modules> <!-- End of Modules section --> diff --git a/audio/policy/primary_audio_policy_configuration.xml b/audio/policy/primary_audio_policy_configuration.xml index f9ac2c3c..33a47d7f 100644 --- a/audio/policy/primary_audio_policy_configuration.xml +++ b/audio/policy/primary_audio_policy_configuration.xml @@ -4,6 +4,9 @@ <attachedDevices> <item>Speaker</item> <item>Built-In Mic</item> + <item>Telephony Tx</item> + <item>Telephony Rx</item> + <item>FM Tuner</item> </attachedDevices> <defaultOutputDevice>Speaker</defaultOutputDevice> <mixPorts> @@ -15,18 +18,47 @@ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" samplingRates="44100" channelMasks="AUDIO_CHANNEL_IN_STEREO"/> </mixPort> + + <mixPort name="telephony_tx" role="source"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="44100" channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO"/> + </mixPort> + <mixPort name="telephony_rx" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="44100" channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO"/> + </mixPort> + + <mixPort name="fm_tuner" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="44100" channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO"/> + </mixPort> </mixPorts> <devicePorts> <devicePort tagName="Speaker" type="AUDIO_DEVICE_OUT_SPEAKER" role="sink"> </devicePort> + <devicePort tagName="Telephony Tx" type="AUDIO_DEVICE_OUT_TELEPHONY_TX" role="sink"> + </devicePort> <devicePort tagName="Built-In Mic" type="AUDIO_DEVICE_IN_BUILTIN_MIC" role="source"> </devicePort> + <devicePort tagName="Telephony Rx" type="AUDIO_DEVICE_IN_TELEPHONY_RX" role="source"> + </devicePort> + + <devicePort tagName="FM Tuner" type="AUDIO_DEVICE_IN_FM_TUNER" role="source"> + </devicePort> </devicePorts> <routes> <route type="mix" sink="Speaker" sources="primary output"/> <route type="mix" sink="primary input" sources="Built-In Mic"/> + + <route type="mix" sink="telephony_rx" + sources="Telephony Rx"/> + <route type="mix" sink="Telephony Tx" + sources="telephony_tx"/> + + <route type="mix" sink="fm_tuner" + sources="FM Tuner"/> </routes> </module> diff --git a/audio/primary_device.cpp b/audio/primary_device.cpp index 838a1557..9f39d088 100644 --- a/audio/primary_device.cpp +++ b/audio/primary_device.cpp @@ -20,6 +20,7 @@ #include "stream_in.h" #include "stream_out.h" #include "util.h" +#include "debug.h" namespace android { namespace hardware { @@ -28,7 +29,7 @@ namespace V6_0 { namespace implementation { constexpr size_t kInBufferDurationMs = 15; -constexpr size_t kOutBufferDurationMs = 15; +constexpr size_t kOutBufferDurationMs = 22; using ::android::hardware::Void; @@ -48,28 +49,28 @@ PrimaryDevice::PrimaryDevice() } Return<Result> PrimaryDevice::initCheck() { - return mMixer ? Result::OK : Result::NOT_INITIALIZED; + return mMixer ? Result::OK : FAILURE(Result::NOT_INITIALIZED); } Return<Result> PrimaryDevice::setMasterVolume(float volume) { - if (volume < 0 || volume > 1.0) { - return Result::INVALID_ARGUMENTS; + if (isnan(volume) || volume < 0 || volume > 1.0) { + return FAILURE(Result::INVALID_ARGUMENTS); } if (!mMixerMasterVolumeCtl) { - return Result::INVALID_STATE; + return FAILURE(Result::INVALID_STATE); } talsa::mixerSetPercentAll(mMixerMasterVolumeCtl, int(100 * volume)); + mMasterVolume = volume; return Result::OK; } Return<void> PrimaryDevice::getMasterVolume(getMasterVolume_cb _hidl_cb) { if (mMixerMasterVolumeCtl) { - _hidl_cb(Result::OK, - mixer_ctl_get_percent(mMixerMasterVolumeCtl, 0) / 100.0); + _hidl_cb(Result::OK, mMasterVolume); } else { - _hidl_cb(Result::INVALID_STATE, 0); + _hidl_cb(FAILURE(Result::INVALID_STATE), 0); } return Void(); @@ -80,7 +81,7 @@ Return<Result> PrimaryDevice::PrimaryDevice::setMicMute(bool mute) { talsa::mixerSetValueAll(mMixerCaptureSwitchCtl, mute ? 0 : 1); return Result::OK; } else { - return Result::INVALID_STATE; + return FAILURE(Result::INVALID_STATE); } } @@ -89,7 +90,7 @@ Return<void> PrimaryDevice::getMicMute(getMicMute_cb _hidl_cb) { const int value = mixer_ctl_get_value(mMixerCaptureSwitchCtl, 0); _hidl_cb(Result::OK, value == 0); } else { - _hidl_cb(Result::INVALID_STATE, 0); + _hidl_cb(FAILURE(Result::INVALID_STATE), 0); } return Void(); } @@ -99,7 +100,7 @@ Return<Result> PrimaryDevice::setMasterMute(bool mute) { talsa::mixerSetValueAll(mMixerMasterPaybackSwitchCtl, mute ? 0 : 1); return Result::OK; } else { - return Result::INVALID_STATE; + return FAILURE(Result::INVALID_STATE); } } @@ -108,7 +109,7 @@ Return<void> PrimaryDevice::getMasterMute(getMasterMute_cb _hidl_cb) { const int value = mixer_ctl_get_value(mMixerMasterPaybackSwitchCtl, 0); _hidl_cb(Result::OK, value == 0); } else { - _hidl_cb(Result::NOT_SUPPORTED, 0); + _hidl_cb(FAILURE(Result::NOT_SUPPORTED), 0); } return Void(); @@ -126,7 +127,7 @@ Return<void> PrimaryDevice::getInputBufferSize(const AudioConfig& config, _hidl_cb(Result::OK, sz); } else { ALOGE("PrimaryDevice::%s:%d failed", __func__, __LINE__); - _hidl_cb(Result::INVALID_ARGUMENTS, 0); + _hidl_cb(FAILURE(Result::INVALID_ARGUMENTS), 0); } return Void(); @@ -147,7 +148,7 @@ Return<void> PrimaryDevice::openOutputStream(int32_t ioHandle, config); } else { ALOGE("PrimaryDevice::%s:%d failed", __func__, __LINE__); - _hidl_cb(Result::INVALID_ARGUMENTS, nullptr, suggestedConfig); + _hidl_cb(FAILURE(Result::INVALID_ARGUMENTS), nullptr, suggestedConfig); } return Void(); @@ -168,49 +169,76 @@ Return<void> PrimaryDevice::openInputStream(int32_t ioHandle, config); } else { ALOGE("PrimaryDevice::%s:%d failed", __func__, __LINE__); - _hidl_cb(Result::INVALID_ARGUMENTS, nullptr, suggestedConfig); + _hidl_cb(FAILURE(Result::INVALID_ARGUMENTS), nullptr, suggestedConfig); } return Void(); } Return<bool> PrimaryDevice::supportsAudioPatches() { - return false; + return true; } Return<void> PrimaryDevice::createAudioPatch(const hidl_vec<AudioPortConfig>& sources, const hidl_vec<AudioPortConfig>& sinks, createAudioPatch_cb _hidl_cb) { - (void)sources; - (void)sinks; - _hidl_cb(Result::NOT_SUPPORTED, 0); + if (sources.size() == 1 && sinks.size() == 1) { + AudioPatch patch; + patch.source = sources[0]; + patch.sink = sinks[0]; + + AudioPatchHandle handle; + while (true) { + handle = mNextAudioPatchHandle; + mNextAudioPatchHandle = std::max(handle + 1, 0); + if (mAudioPatches.insert({handle, patch}).second) { + break; + } + } + + _hidl_cb(Result::OK, handle); + } else { + _hidl_cb(FAILURE(Result::NOT_SUPPORTED), 0); + } + return Void(); } -Return<void> PrimaryDevice::updateAudioPatch(int32_t previousPatch, +Return<void> PrimaryDevice::updateAudioPatch(AudioPatchHandle previousPatchHandle, const hidl_vec<AudioPortConfig>& sources, const hidl_vec<AudioPortConfig>& sinks, updateAudioPatch_cb _hidl_cb) { - (void)previousPatch; - (void)sources; - (void)sinks; - _hidl_cb(Result::NOT_SUPPORTED, 0); + const auto i = mAudioPatches.find(previousPatchHandle); + if (i == mAudioPatches.end()) { + _hidl_cb(FAILURE(Result::INVALID_ARGUMENTS), previousPatchHandle); + } else { + if (sources.size() == 1 && sinks.size() == 1) { + AudioPatch patch; + patch.source = sources[0]; + patch.sink = sinks[0]; + i->second = patch; + + _hidl_cb(Result::OK, previousPatchHandle); + } else { + _hidl_cb(Result::NOT_SUPPORTED, previousPatchHandle); + } + } + return Void(); } -Return<Result> PrimaryDevice::releaseAudioPatch(int32_t patch) { - (void)patch; - return Result::NOT_SUPPORTED; +Return<Result> PrimaryDevice::releaseAudioPatch(AudioPatchHandle patchHandle) { + return (mAudioPatches.erase(patchHandle) == 1) ? Result::OK : FAILURE(Result::INVALID_ARGUMENTS); } Return<void> PrimaryDevice::getAudioPort(const AudioPort& port, getAudioPort_cb _hidl_cb) { - _hidl_cb(Result::NOT_SUPPORTED, port); + _hidl_cb(FAILURE(Result::NOT_SUPPORTED), port); return Void(); } Return<Result> PrimaryDevice::setAudioPortConfig(const AudioPortConfig& config) { (void)config; - return Result::NOT_SUPPORTED; + return FAILURE(Result::NOT_SUPPORTED); } Return<Result> PrimaryDevice::setScreenState(bool turnedOn) { @@ -219,7 +247,7 @@ Return<Result> PrimaryDevice::setScreenState(bool turnedOn) { } Return<void> PrimaryDevice::getHwAvSync(getHwAvSync_cb _hidl_cb) { - _hidl_cb(Result::NOT_SUPPORTED, {}); + _hidl_cb(FAILURE(Result::NOT_SUPPORTED), {}); return Void(); } @@ -230,7 +258,7 @@ Return<void> PrimaryDevice::getParameters(const hidl_vec<ParameterValue>& contex if (keys.size() == 0) { _hidl_cb(Result::OK, {}); } else { - _hidl_cb(Result::NOT_SUPPORTED, {}); + _hidl_cb(FAILURE(Result::NOT_SUPPORTED), {}); } return Void(); } @@ -250,12 +278,12 @@ Return<void> PrimaryDevice::getMicrophones(getMicrophones_cb _hidl_cb) { Return<Result> PrimaryDevice::setConnectedState(const DeviceAddress& dev_addr, bool connected) { (void)dev_addr; (void)connected; - return Result::NOT_SUPPORTED; + return FAILURE(Result::NOT_SUPPORTED); } Return<Result> PrimaryDevice::close() { if (mNStreams > 0) { - return Result::INVALID_STATE; + return FAILURE(Result::INVALID_STATE); } else if (mMixer) { mMixerMasterVolumeCtl = nullptr; mMixerCaptureVolumeCtl = nullptr; @@ -264,24 +292,24 @@ Return<Result> PrimaryDevice::close() { mMixer.reset(); return Result::OK; } else { - return Result::INVALID_STATE; + return FAILURE(Result::INVALID_STATE); } } Return<Result> PrimaryDevice::addDeviceEffect(AudioPortHandle device, uint64_t effectId) { (void)device; (void)effectId; - return Result::NOT_SUPPORTED; + return FAILURE(Result::NOT_SUPPORTED); } Return<Result> PrimaryDevice::removeDeviceEffect(AudioPortHandle device, uint64_t effectId) { (void)device; (void)effectId; - return Result::NOT_SUPPORTED; + return FAILURE(Result::NOT_SUPPORTED); } Return<Result> PrimaryDevice::setVoiceVolume(float volume) { - return (volume >= 0 && volume <= 1.0) ? Result::OK : Result::INVALID_ARGUMENTS; + return (volume >= 0 && volume <= 1.0) ? Result::OK : FAILURE(Result::INVALID_ARGUMENTS); } Return<Result> PrimaryDevice::setMode(AudioMode mode) { @@ -293,78 +321,78 @@ Return<Result> PrimaryDevice::setMode(AudioMode mode) { return Result::OK; default: - return Result::INVALID_ARGUMENTS; + return FAILURE(Result::INVALID_ARGUMENTS); } } Return<Result> PrimaryDevice::setBtScoHeadsetDebugName(const hidl_string& name) { (void)name; - return Result::NOT_SUPPORTED; + return FAILURE(Result::NOT_SUPPORTED); } Return<void> PrimaryDevice::getBtScoNrecEnabled(getBtScoNrecEnabled_cb _hidl_cb) { - _hidl_cb(Result::NOT_SUPPORTED, false); + _hidl_cb(FAILURE(Result::NOT_SUPPORTED), false); return Void(); } Return<Result> PrimaryDevice::setBtScoNrecEnabled(bool enabled) { (void)enabled; - return Result::NOT_SUPPORTED; + return FAILURE(Result::NOT_SUPPORTED); } Return<void> PrimaryDevice::getBtScoWidebandEnabled(getBtScoWidebandEnabled_cb _hidl_cb) { - _hidl_cb(Result::NOT_SUPPORTED, false); + _hidl_cb(FAILURE(Result::NOT_SUPPORTED), false); return Void(); } Return<Result> PrimaryDevice::setBtScoWidebandEnabled(bool enabled) { (void)enabled; - return Result::NOT_SUPPORTED; + return FAILURE(Result::NOT_SUPPORTED); } Return<void> PrimaryDevice::getTtyMode(getTtyMode_cb _hidl_cb) { - _hidl_cb(Result::NOT_SUPPORTED, TtyMode::OFF); + _hidl_cb(FAILURE(Result::NOT_SUPPORTED), TtyMode::OFF); return Void(); } Return<Result> PrimaryDevice::setTtyMode(IPrimaryDevice::TtyMode mode) { (void)mode; - return Result::NOT_SUPPORTED; + return FAILURE(Result::NOT_SUPPORTED); } Return<void> PrimaryDevice::getHacEnabled(getHacEnabled_cb _hidl_cb) { - _hidl_cb(Result::NOT_SUPPORTED, false); + _hidl_cb(FAILURE(Result::NOT_SUPPORTED), false); return Void(); } Return<Result> PrimaryDevice::setHacEnabled(bool enabled) { (void)enabled; - return Result::NOT_SUPPORTED; + return FAILURE(Result::NOT_SUPPORTED); } Return<void> PrimaryDevice::getBtHfpEnabled(getBtHfpEnabled_cb _hidl_cb) { - _hidl_cb(Result::NOT_SUPPORTED, false); + _hidl_cb(FAILURE(Result::NOT_SUPPORTED), false); return Void(); } Return<Result> PrimaryDevice::setBtHfpEnabled(bool enabled) { (void)enabled; - return Result::NOT_SUPPORTED; + return FAILURE(Result::NOT_SUPPORTED); } Return<Result> PrimaryDevice::setBtHfpSampleRate(uint32_t sampleRateHz) { (void)sampleRateHz; - return Result::NOT_SUPPORTED; + return FAILURE(Result::NOT_SUPPORTED); } Return<Result> PrimaryDevice::setBtHfpVolume(float volume) { (void)volume; - return Result::NOT_SUPPORTED; + return FAILURE(Result::NOT_SUPPORTED); } Return<Result> PrimaryDevice::updateRotation(IPrimaryDevice::Rotation rotation) { (void)rotation; - return Result::NOT_SUPPORTED; + return FAILURE(Result::NOT_SUPPORTED); } void PrimaryDevice::unrefDevice(IDevice *dev) { diff --git a/audio/primary_device.h b/audio/primary_device.h index 72b5c756..05964f3e 100644 --- a/audio/primary_device.h +++ b/audio/primary_device.h @@ -17,6 +17,7 @@ #pragma once #include <android/hardware/audio/6.0/IPrimaryDevice.h> #include <atomic> +#include <unordered_map> #include "talsa.h" namespace android { @@ -62,11 +63,11 @@ struct PrimaryDevice : public IPrimaryDevice { Return<void> createAudioPatch(const hidl_vec<AudioPortConfig>& sources, const hidl_vec<AudioPortConfig>& sinks, createAudioPatch_cb _hidl_cb) override; - Return<void> updateAudioPatch(int32_t previousPatch, + Return<void> updateAudioPatch(AudioPatchHandle previousPatch, const hidl_vec<AudioPortConfig>& sources, const hidl_vec<AudioPortConfig>& sinks, updateAudioPatch_cb _hidl_cb) override; - Return<Result> releaseAudioPatch(int32_t patch) override; + Return<Result> releaseAudioPatch(AudioPatchHandle patch) override; Return<void> getAudioPort(const AudioPort& port, getAudioPort_cb _hidl_cb) override; Return<Result> setAudioPortConfig(const AudioPortConfig& config) override; Return<Result> setScreenState(bool turnedOn) override; @@ -107,7 +108,16 @@ private: talsa::mixer_ctl_t *mMixerCaptureVolumeCtl = nullptr; talsa::mixer_ctl_t *mMixerMasterPaybackSwitchCtl = nullptr; talsa::mixer_ctl_t *mMixerCaptureSwitchCtl = nullptr; + float mMasterVolume = 1.0f; std::atomic<int> mNStreams = 0; + + struct AudioPatch { + AudioPortConfig source; + AudioPortConfig sink; + }; + + AudioPatchHandle mNextAudioPatchHandle = 0; + std::unordered_map<AudioPatchHandle, AudioPatch> mAudioPatches; }; } // namespace implementation diff --git a/audio/stream_common.cpp b/audio/stream_common.cpp index 3ac4da8b..6235f9a8 100644 --- a/audio/stream_common.cpp +++ b/audio/stream_common.cpp @@ -17,6 +17,7 @@ #include <log/log.h> #include "stream_common.h" #include "util.h" +#include "debug.h" namespace android { namespace hardware { @@ -64,7 +65,7 @@ void StreamCommon::getSupportedSampleRates(AudioFormat format, Result StreamCommon::setSampleRate(uint32_t sampleRateHz) const { (void)sampleRateHz; - return Result::NOT_SUPPORTED; + return FAILURE(Result::NOT_SUPPORTED); } hidl_bitfield<AudioChannelMask> StreamCommon::getChannelMask() const { @@ -82,7 +83,7 @@ void StreamCommon::getSupportedChannelMasks(AudioFormat format, Result StreamCommon::setChannelMask(hidl_bitfield<AudioChannelMask> mask) const { (void)mask; - return Result::NOT_SUPPORTED; + return FAILURE(Result::NOT_SUPPORTED); } AudioFormat StreamCommon::getFormat() const { @@ -95,7 +96,7 @@ void StreamCommon::getSupportedFormats(IStream::getSupportedFormats_cb _hidl_cb) Result StreamCommon::setFormat(AudioFormat format) const { (void)format; - return Result::NOT_SUPPORTED; + return FAILURE(Result::NOT_SUPPORTED); } void StreamCommon::getAudioProperties(IStream::getAudioProperties_cb _hidl_cb) const { @@ -108,7 +109,7 @@ void StreamCommon::getDevices(IStream::getDevices_cb _hidl_cb) const { Result StreamCommon::setDevices(const hidl_vec<DeviceAddress>& devices) const { (void)devices; - return Result::NOT_SUPPORTED; + return FAILURE(Result::NOT_SUPPORTED); } } // namespace implementation diff --git a/audio/stream_in.cpp b/audio/stream_in.cpp index 89ca7e60..c3ef62f2 100644 --- a/audio/stream_in.cpp +++ b/audio/stream_in.cpp @@ -20,9 +20,10 @@ #include <hidl/MQDescriptor.h> #include <hidl/Status.h> #include "stream_in.h" +#include "device_port_source.h" #include "deleters.h" -#include "talsa.h" #include "util.h" +#include "debug.h" #include <sys/resource.h> #include <pthread.h> #include <cutils/sched_policy.h> @@ -45,15 +46,8 @@ struct ReadThread : public IOThread { typedef MessageQueue<IStreamIn::ReadStatus, kSynchronizedReadWrite> StatusMQ; typedef MessageQueue<uint8_t, kSynchronizedReadWrite> DataMQ; - ReadThread(StreamIn *stream, - const unsigned nChannels, - const size_t sampleRateHz, - const size_t frameCount, - const size_t bufferSize) + ReadThread(StreamIn *stream, const size_t bufferSize) : mStream(stream) - , mNChannels(nChannels) - , mSampleRateHz(sampleRateHz) - , mFrameCount(frameCount) , mCommandMQ(1) , mStatusMQ(1) , mDataMQ(bufferSize, true /* EventFlag */) { @@ -117,22 +111,20 @@ struct ReadThread : public IOThread { } if (efState & STAND_BY_REQUEST) { - mPcm.reset(); + mSource.reset(); mBuffer.reset(); } if (efState & (MessageQueueFlagBits::NOT_FULL | 0)) { - if (!mPcm) { + if (!mSource) { mBuffer.reset(new uint8_t[mDataMQ.getQuantumCount()]); LOG_ALWAYS_FATAL_IF(!mBuffer); - mPcm = talsa::pcmOpen( - talsa::kPcmCard, talsa::kPcmDevice, - mNChannels, mSampleRateHz, mFrameCount, - false /* isOut */); - LOG_ALWAYS_FATAL_IF(!mPcm); - - mPos.reset(); + mSource = DevicePortSource::create(mStream->getDeviceAddress(), + mStream->getAudioConfig(), + mStream->getAudioOutputFlags(), + mStream->getFrameCounter()); + LOG_ALWAYS_FATAL_IF(!mSource); } processCommand(); @@ -160,7 +152,7 @@ struct ReadThread : public IOThread { default: ALOGE("ReadThread::%s:%d: Unknown read thread command code %d", __func__, __LINE__, rParameters.command); - rStatus.retval = Result::NOT_SUPPORTED; + rStatus.retval = FAILURE(Result::NOT_SUPPORTED); break; } @@ -184,8 +176,6 @@ struct ReadThread : public IOThread { if (!mDataMQ.write(&mBuffer[0], read)) { ALOGE("ReadThread::%s:%d: mDataMQ.write failed", __func__, __LINE__); } - - mPos.addFrames(pcm_bytes_to_frames(mPcm.get(), read)); status.reply.read = read; } @@ -193,15 +183,12 @@ struct ReadThread : public IOThread { } Result doReadImpl(uint8_t *const data, const size_t toRead, size_t &read) { - const int res = pcm_read(mPcm.get(), data, toRead); + const int res = mSource->read(data, toRead); if (res < 0) { memset(data, 0, toRead); read = toRead; - - ALOGE("ReadThread::%s:%d pcm_read failed with %s", + ALOGE("StreamInReadThread::%s:%d pcm_read failed with %s", __func__, __LINE__, strerror(-res)); - } else if (res == 0) { - read = toRead; } else { read = res; } @@ -212,25 +199,20 @@ struct ReadThread : public IOThread { IStreamIn::ReadStatus doGetCapturePosition() { IStreamIn::ReadStatus status; - status.retval = Result::OK; - nsecs_t t = 0; - mPos.now(mSampleRateHz, status.reply.capturePosition.frames, t); - status.reply.capturePosition.time = t; + status.retval = mSource->getCapturePosition( + status.reply.capturePosition.frames, + status.reply.capturePosition.time); return status; } StreamIn *const mStream; - const unsigned mNChannels; - const size_t mSampleRateHz; - const size_t mFrameCount; CommandMQ mCommandMQ; StatusMQ mStatusMQ; DataMQ mDataMQ; std::unique_ptr<EventFlag, deleters::forEventFlag> mEfGroup; std::unique_ptr<uint8_t[]> mBuffer; - talsa::PcmPtr mPcm; - util::StreamPosition mPos; + std::unique_ptr<DevicePortSource> mSource; std::thread mThread; std::promise<pthread_t> mTid; }; @@ -251,7 +233,7 @@ StreamIn::StreamIn(sp<IDevice> dev, } StreamIn::~StreamIn() { - close(); + closeImpl(true); } Return<uint64_t> StreamIn::getFrameSize() { @@ -314,12 +296,12 @@ Return<void> StreamIn::getAudioProperties(getAudioProperties_cb _hidl_cb) { Return<Result> StreamIn::addEffect(uint64_t effectId) { (void)effectId; - return Result::INVALID_ARGUMENTS; + return FAILURE(Result::INVALID_ARGUMENTS); } Return<Result> StreamIn::removeEffect(uint64_t effectId) { (void)effectId; - return Result::INVALID_ARGUMENTS; + return FAILURE(Result::INVALID_ARGUMENTS); } Return<Result> StreamIn::standby() { @@ -343,7 +325,7 @@ Return<void> StreamIn::getParameters(const hidl_vec<ParameterValue>& context, const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) { (void)context; - _hidl_cb((keys.size() > 0) ? Result::NOT_SUPPORTED : Result::OK, {}); + _hidl_cb((keys.size() > 0) ? FAILURE(Result::NOT_SUPPORTED) : Result::OK, {}); return Void(); } @@ -356,48 +338,56 @@ Return<Result> StreamIn::setParameters(const hidl_vec<ParameterValue>& context, Return<Result> StreamIn::setHwAvSync(uint32_t hwAvSync) { (void)hwAvSync; - return Result::NOT_SUPPORTED; + return FAILURE(Result::NOT_SUPPORTED); } Return<Result> StreamIn::start() { - return Result::NOT_SUPPORTED; + return FAILURE(Result::NOT_SUPPORTED); } Return<Result> StreamIn::stop() { - return Result::NOT_SUPPORTED; + return FAILURE(Result::NOT_SUPPORTED); } Return<void> StreamIn::createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) { (void)minSizeFrames; - _hidl_cb(Result::NOT_SUPPORTED, {}); + _hidl_cb(FAILURE(Result::NOT_SUPPORTED), {}); return Void(); } Return<void> StreamIn::getMmapPosition(getMmapPosition_cb _hidl_cb) { - _hidl_cb(Result::NOT_SUPPORTED, {}); + _hidl_cb(FAILURE(Result::NOT_SUPPORTED), {}); return Void(); } -Return<Result> StreamIn::close() { +Result StreamIn::closeImpl(const bool fromDctor) { if (mDev) { mReadThread.reset(); mUnrefDevice(mDev.get()); mDev = nullptr; return Result::OK; + } else if (fromDctor) { + // closeImpl is always called from the dctor, it is ok if mDev is null, + // we don't want to log the error in this case. + return Result::OK; } else { - return Result::INVALID_STATE; + return FAILURE(Result::INVALID_STATE); } } +Return<Result> StreamIn::close() { + return closeImpl(false); +} + Return<void> StreamIn::getAudioSource(getAudioSource_cb _hidl_cb) { - _hidl_cb(Result::NOT_SUPPORTED, {}); + _hidl_cb(FAILURE(Result::NOT_SUPPORTED), {}); return Void(); } Return<Result> StreamIn::setGain(float gain) { (void)gain; - return Result::NOT_SUPPORTED; + return FAILURE(Result::NOT_SUPPORTED); } Return<void> StreamIn::updateSinkMetadata(const SinkMetadata& sinkMetadata) { @@ -409,20 +399,16 @@ Return<void> StreamIn::prepareForReading(uint32_t frameSize, uint32_t framesCount, prepareForReading_cb _hidl_cb) { if (!frameSize || !framesCount || frameSize > 256 || framesCount > (1u << 20)) { - _hidl_cb(Result::INVALID_ARGUMENTS, {}, {}, {}, {}); + _hidl_cb(FAILURE(Result::INVALID_ARGUMENTS), {}, {}, {}, {}); return Void(); } if (mReadThread) { // INVALID_STATE if the method was already called. - _hidl_cb(Result::INVALID_STATE, {}, {}, {}, {}); + _hidl_cb(FAILURE(Result::INVALID_STATE), {}, {}, {}, {}); return Void(); } - auto t = std::make_unique<ReadThread>(this, - util::countChannels(mCommon.getChannelMask()), - mCommon.getSampleRate(), - mCommon.getFrameCount(), - frameSize * framesCount); + auto t = std::make_unique<ReadThread>(this, frameSize * framesCount); if (t->isRunning()) { _hidl_cb(Result::OK, @@ -433,7 +419,7 @@ Return<void> StreamIn::prepareForReading(uint32_t frameSize, mReadThread = std::move(t); } else { - _hidl_cb(Result::INVALID_ARGUMENTS, {}, {}, {}, {}); + _hidl_cb(FAILURE(Result::INVALID_ARGUMENTS), {}, {}, {}, {}); } return Void(); @@ -444,7 +430,7 @@ Return<uint32_t> StreamIn::getInputFramesLost() { } Return<void> StreamIn::getCapturePosition(getCapturePosition_cb _hidl_cb) { - _hidl_cb(Result::NOT_SUPPORTED, 0, 0); // see ReadThread::doGetCapturePosition + _hidl_cb(FAILURE(Result::NOT_SUPPORTED), 0, 0); // see ReadThread::doGetCapturePosition return Void(); } @@ -455,12 +441,12 @@ Return<void> StreamIn::getActiveMicrophones(getActiveMicrophones_cb _hidl_cb) { Return<Result> StreamIn::setMicrophoneDirection(MicrophoneDirection direction) { (void)direction; - return Result::NOT_SUPPORTED; + return FAILURE(Result::NOT_SUPPORTED); } Return<Result> StreamIn::setMicrophoneFieldDimension(float zoom) { (void)zoom; - return Result::NOT_SUPPORTED; + return FAILURE(Result::NOT_SUPPORTED); } } // namespace implementation diff --git a/audio/stream_in.h b/audio/stream_in.h index 13b28d81..2a769814 100644 --- a/audio/stream_in.h +++ b/audio/stream_in.h @@ -87,12 +87,23 @@ struct StreamIn : public IStreamIn { Return<Result> setMicrophoneDirection(MicrophoneDirection direction) override; Return<Result> setMicrophoneFieldDimension(float zoom) override; + const DeviceAddress &getDeviceAddress() const { return mCommon.m_device; } + const AudioConfig &getAudioConfig() const { return mCommon.m_config; } + const hidl_bitfield<AudioOutputFlag> &getAudioOutputFlags() const { return mCommon.m_flags; } + + uint64_t &getFrameCounter() { return mFrames; } + private: + Result closeImpl(bool fromDctor); + sp<IDevice> mDev; void (* const mUnrefDevice)(IDevice*); const StreamCommon mCommon; const SinkMetadata mSinkMetadata; std::unique_ptr<IOThread> mReadThread; + + // The count is not reset to zero when output enters standby. + uint64_t mFrames = 0; }; } // namespace implementation diff --git a/audio/stream_out.cpp b/audio/stream_out.cpp index 8de19638..72b826fe 100644 --- a/audio/stream_out.cpp +++ b/audio/stream_out.cpp @@ -21,9 +21,10 @@ #include <hidl/Status.h> #include <math.h> #include "stream_out.h" -#include "talsa.h" +#include "device_port_sink.h" #include "deleters.h" #include "util.h" +#include "debug.h" #include <sys/resource.h> #include <pthread.h> #include <cutils/sched_policy.h> @@ -48,15 +49,8 @@ struct WriteThread : public IOThread { typedef MessageQueue<IStreamOut::WriteStatus, kSynchronizedReadWrite> StatusMQ; typedef MessageQueue<uint8_t, kSynchronizedReadWrite> DataMQ; - WriteThread(StreamOut *stream, - const unsigned nChannels, - const size_t sampleRateHz, - const size_t frameCount, - const size_t mqBufferSize) + WriteThread(StreamOut *stream, const size_t mqBufferSize) : mStream(stream) - , mNChannels(nChannels) - , mSampleRateHz(sampleRateHz) - , mFrameCount(frameCount) , mCommandMQ(1) , mStatusMQ(1) , mDataMQ(mqBufferSize, true /* EventFlag */) { @@ -120,22 +114,19 @@ struct WriteThread : public IOThread { } if (efState & STAND_BY_REQUEST) { - mPcm.reset(); - mBuffer.reset(); + mSink.reset(); } if (efState & (MessageQueueFlagBits::NOT_EMPTY | 0)) { - if (!mPcm) { + if (!mSink) { mBuffer.reset(new uint8_t[mDataMQ.getQuantumCount()]); LOG_ALWAYS_FATAL_IF(!mBuffer); - mPcm = talsa::pcmOpen( - talsa::kPcmCard, talsa::kPcmDevice, - mNChannels, mSampleRateHz, mFrameCount, - true /* isOut */); - LOG_ALWAYS_FATAL_IF(!mPcm); - - mPos.reset(); + mSink = DevicePortSink::create(mStream->getDeviceAddress(), + mStream->getAudioConfig(), + mStream->getAudioOutputFlags(), + mStream->getFrameCounter()); + LOG_ALWAYS_FATAL_IF(!mSink); } processCommand(); @@ -167,7 +158,7 @@ struct WriteThread : public IOThread { default: ALOGE("WriteThread::%s:%d: Unknown write thread command code %d", __func__, __LINE__, wCommand); - wStatus.retval = Result::NOT_SUPPORTED; + wStatus.retval = FAILURE(Result::NOT_SUPPORTED); break; } @@ -186,9 +177,8 @@ struct WriteThread : public IOThread { const size_t availToRead = mDataMQ.availableToRead(); size_t written = 0; if (mDataMQ.read(&mBuffer[0], availToRead)) { + applyVolume(&mBuffer[0], availToRead, mStream->getVolumeNumerator()); status.retval = doWriteImpl(&mBuffer[0], availToRead, written); - - mPos.addFrames(pcm_bytes_to_frames(mPcm.get(), written)); status.reply.written = written; } else { ALOGE("WriteThread::%s:%d: mDataMQ.read failed", __func__, __LINE__); @@ -198,10 +188,25 @@ struct WriteThread : public IOThread { return status; } + static void applyVolume(void *buf, const size_t szBytes, const int32_t numerator) { + constexpr int32_t kDenominator = StreamOut::kVolumeDenominator; + + if (numerator == kDenominator) { + return; + } + + int16_t *samples = static_cast<int16_t *>(buf); + std::for_each(samples, + samples + szBytes / sizeof(*samples), + [numerator](int16_t &x) { + x = (x * numerator + kDenominator / 2) / kDenominator; + }); + } + IStreamOut::WriteStatus doGetPresentationPosition() { IStreamOut::WriteStatus status; - status.retval = doGetPresentationPositionImpl( + status.retval = mSink->getPresentationPosition( status.reply.presentationPosition.frames, status.reply.presentationPosition.timeStamp); @@ -220,35 +225,25 @@ struct WriteThread : public IOThread { Result doWriteImpl(const uint8_t *const data, const size_t toWrite, size_t &written) { - const int res = pcm_write(mPcm.get(), data, toWrite); - if (res) { - ALOGE("WriteThread::%s:%d: pcm_write failed with %s", + const int res = mSink->write(data, toWrite); + if (res < 0) { + ALOGE("WriteThread::%s:%d: DevicePortSink::write failed with %s", __func__, __LINE__, strerror(-res)); + written = toWrite; + } else { + written = res; } - written = toWrite; - return Result::OK; - } - - Result doGetPresentationPositionImpl(uint64_t &frames, TimeSpec &ts) { - nsecs_t t = 0; - mPos.now(mSampleRateHz, frames, t); - ts.tvSec = ns2s(t); - ts.tvNSec = t - s2ns(ts.tvSec); return Result::OK; } StreamOut *const mStream; - const unsigned mNChannels; - const size_t mSampleRateHz; - const size_t mFrameCount; CommandMQ mCommandMQ; StatusMQ mStatusMQ; DataMQ mDataMQ; std::unique_ptr<EventFlag, deleters::forEventFlag> mEfGroup; std::unique_ptr<uint8_t[]> mBuffer; - talsa::PcmPtr mPcm; - util::StreamPosition mPos; + std::unique_ptr<DevicePortSink> mSink; std::thread mThread; std::promise<pthread_t> mTid; }; @@ -265,11 +260,10 @@ StreamOut::StreamOut(sp<IDevice> dev, : mDev(std::move(dev)) , mUnrefDevice(unrefDevice) , mCommon(ioHandle, device, config, flags) - , mSourceMetadata(sourceMetadata) { -} + , mSourceMetadata(sourceMetadata) {} StreamOut::~StreamOut() { - close(); + closeImpl(true); } Return<uint64_t> StreamOut::getFrameSize() { @@ -332,12 +326,12 @@ Return<void> StreamOut::getAudioProperties(getAudioProperties_cb _hidl_cb) { Return<Result> StreamOut::addEffect(uint64_t effectId) { (void)effectId; - return Result::INVALID_ARGUMENTS; + return FAILURE(Result::INVALID_ARGUMENTS); } Return<Result> StreamOut::removeEffect(uint64_t effectId) { (void)effectId; - return Result::INVALID_ARGUMENTS; + return FAILURE(Result::INVALID_ARGUMENTS); } Return<Result> StreamOut::standby() { @@ -361,7 +355,7 @@ Return<void> StreamOut::getParameters(const hidl_vec<ParameterValue>& context, const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) { (void)context; - _hidl_cb((keys.size() > 0) ? Result::NOT_SUPPORTED : Result::OK, {}); + _hidl_cb((keys.size() > 0) ? FAILURE(Result::NOT_SUPPORTED) : Result::OK, {}); return Void(); } @@ -374,37 +368,45 @@ Return<Result> StreamOut::setParameters(const hidl_vec<ParameterValue>& context, Return<Result> StreamOut::setHwAvSync(uint32_t hwAvSync) { (void)hwAvSync; - return Result::NOT_SUPPORTED; + return FAILURE(Result::NOT_SUPPORTED); } -Return<Result> StreamOut::close() { +Result StreamOut::closeImpl(const bool fromDctor) { if (mDev) { mWriteThread.reset(); mUnrefDevice(mDev.get()); mDev = nullptr; return Result::OK; + } else if (fromDctor) { + // closeImpl is always called from the dctor, it is ok if mDev is null, + // we don't want to log the error in this case. + return Result::OK; } else { - return Result::INVALID_STATE; + return FAILURE(Result::INVALID_STATE); } } +Return<Result> StreamOut::close() { + return closeImpl(false); +} + Return<Result> StreamOut::start() { - return Result::NOT_SUPPORTED; + return FAILURE(Result::NOT_SUPPORTED); } Return<Result> StreamOut::stop() { - return Result::NOT_SUPPORTED; + return FAILURE(Result::NOT_SUPPORTED); } Return<void> StreamOut::createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) { (void)minSizeFrames; - _hidl_cb(Result::NOT_SUPPORTED, {}); + _hidl_cb(FAILURE(Result::NOT_SUPPORTED), {}); return Void(); } Return<void> StreamOut::getMmapPosition(getMmapPosition_cb _hidl_cb) { - _hidl_cb(Result::NOT_SUPPORTED, {}); + _hidl_cb(FAILURE(Result::NOT_SUPPORTED), {}); return Void(); } @@ -413,9 +415,13 @@ Return<uint32_t> StreamOut::getLatency() { } Return<Result> StreamOut::setVolume(float left, float right) { - (void)left; - (void)right; - return Result::NOT_SUPPORTED; + if (isnan(left) || left < 0.0f || left > 1.0f + || right < 0.0f || right > 1.0f || isnan(right)) { + return FAILURE(Result::INVALID_ARGUMENTS); + } + + mVolumeNumerator = int16_t((left + right) * kVolumeDenominator / 2); + return Result::OK; } Return<void> StreamOut::updateSourceMetadata(const SourceMetadata& sourceMetadata) { @@ -427,20 +433,16 @@ Return<void> StreamOut::prepareForWriting(uint32_t frameSize, uint32_t framesCount, prepareForWriting_cb _hidl_cb) { if (!frameSize || !framesCount || frameSize > 256 || framesCount > (1u << 20)) { - _hidl_cb(Result::INVALID_ARGUMENTS, {}, {}, {}, {}); + _hidl_cb(FAILURE(Result::INVALID_ARGUMENTS), {}, {}, {}, {}); return Void(); } if (mWriteThread) { // INVALID_STATE if the method was already called. - _hidl_cb(Result::INVALID_STATE, {}, {}, {}, {}); + _hidl_cb(FAILURE(Result::INVALID_STATE), {}, {}, {}, {}); return Void(); } - auto t = std::make_unique<WriteThread>(this, - util::countChannels(mCommon.getChannelMask()), - mCommon.getSampleRate(), - mCommon.getFrameCount(), - frameSize * framesCount); + auto t = std::make_unique<WriteThread>(this, frameSize * framesCount); if (t->isRunning()) { _hidl_cb(Result::OK, @@ -451,34 +453,34 @@ Return<void> StreamOut::prepareForWriting(uint32_t frameSize, mWriteThread = std::move(t); } else { - _hidl_cb(Result::INVALID_ARGUMENTS, {}, {}, {}, {}); + _hidl_cb(FAILURE(Result::INVALID_ARGUMENTS), {}, {}, {}, {}); } return Void(); } Return<void> StreamOut::getRenderPosition(getRenderPosition_cb _hidl_cb) { - _hidl_cb(Result::NOT_SUPPORTED, 0); + _hidl_cb(FAILURE(Result::NOT_SUPPORTED), 0); return Void(); } Return<void> StreamOut::getNextWriteTimestamp(getNextWriteTimestamp_cb _hidl_cb) { - _hidl_cb(Result::NOT_SUPPORTED, 0); + _hidl_cb(FAILURE(Result::NOT_SUPPORTED), 0); return Void(); } Return<Result> StreamOut::setCallback(const sp<IStreamOutCallback>& callback) { (void)callback; - return Result::NOT_SUPPORTED; + return FAILURE(Result::NOT_SUPPORTED); } Return<Result> StreamOut::clearCallback() { - return Result::NOT_SUPPORTED; + return FAILURE(Result::NOT_SUPPORTED); } Return<Result> StreamOut::setEventCallback(const sp<IStreamOutEventCallback>& callback) { (void)callback; - return Result::NOT_SUPPORTED; + return FAILURE(Result::NOT_SUPPORTED); } Return<void> StreamOut::supportsPauseAndResume(supportsPauseAndResume_cb _hidl_cb) { @@ -487,11 +489,11 @@ Return<void> StreamOut::supportsPauseAndResume(supportsPauseAndResume_cb _hidl_c } Return<Result> StreamOut::pause() { - return Result::NOT_SUPPORTED; + return FAILURE(Result::NOT_SUPPORTED); } Return<Result> StreamOut::resume() { - return Result::NOT_SUPPORTED; + return FAILURE(Result::NOT_SUPPORTED); } Return<bool> StreamOut::supportsDrain() { @@ -500,15 +502,15 @@ Return<bool> StreamOut::supportsDrain() { Return<Result> StreamOut::drain(AudioDrain type) { (void)type; - return Result::NOT_SUPPORTED; + return FAILURE(Result::NOT_SUPPORTED); } Return<Result> StreamOut::flush() { - return Result::NOT_SUPPORTED; + return FAILURE(Result::NOT_SUPPORTED); } Return<void> StreamOut::getPresentationPosition(getPresentationPosition_cb _hidl_cb) { - _hidl_cb(Result::NOT_SUPPORTED, {}, {}); // see WriteThread::doGetPresentationPosition + _hidl_cb(FAILURE(Result::NOT_SUPPORTED), {}, {}); // see WriteThread::doGetPresentationPosition return Void(); } @@ -516,37 +518,37 @@ Return<Result> StreamOut::selectPresentation(int32_t presentationId, int32_t programId) { (void)presentationId; (void)programId; - return Result::NOT_SUPPORTED; + return FAILURE(Result::NOT_SUPPORTED); } Return<void> StreamOut::getDualMonoMode(getDualMonoMode_cb _hidl_cb) { - _hidl_cb(Result::NOT_SUPPORTED, {}); + _hidl_cb(FAILURE(Result::NOT_SUPPORTED), {}); return Void(); } Return<Result> StreamOut::setDualMonoMode(DualMonoMode mode) { (void)mode; - return Result::NOT_SUPPORTED; + return FAILURE(Result::NOT_SUPPORTED); } Return<void> StreamOut::getAudioDescriptionMixLevel(getAudioDescriptionMixLevel_cb _hidl_cb) { - _hidl_cb(Result::NOT_SUPPORTED, 0); + _hidl_cb(FAILURE(Result::NOT_SUPPORTED), 0); return Void(); } Return<Result> StreamOut::setAudioDescriptionMixLevel(float leveldB) { (void)leveldB; - return Result::NOT_SUPPORTED; + return FAILURE(Result::NOT_SUPPORTED); } Return<void> StreamOut::getPlaybackRateParameters(getPlaybackRateParameters_cb _hidl_cb) { - _hidl_cb(Result::NOT_SUPPORTED, {}); + _hidl_cb(FAILURE(Result::NOT_SUPPORTED), {}); return Void(); } Return<Result> StreamOut::setPlaybackRateParameters(const PlaybackRate &playbackRate) { (void)playbackRate; - return Result::NOT_SUPPORTED; + return FAILURE(Result::NOT_SUPPORTED); } } // namespace implementation diff --git a/audio/stream_out.h b/audio/stream_out.h index c55ad8ce..79adef34 100644 --- a/audio/stream_out.h +++ b/audio/stream_out.h @@ -15,6 +15,7 @@ */ #pragma once +#include <atomic> #include <android/hardware/audio/6.0/IStreamOut.h> #include <android/hardware/audio/6.0/IDevice.h> #include "stream_common.h" @@ -44,6 +45,8 @@ struct StreamOut : public IStreamOut { const SourceMetadata& sourceMetadata); ~StreamOut(); + static constexpr int16_t kVolumeDenominator = 1 << 14; + // IStream Return<uint64_t> getFrameSize() override; Return<uint64_t> getFrameCount() override; @@ -101,12 +104,25 @@ struct StreamOut : public IStreamOut { Return<void> getPlaybackRateParameters(getPlaybackRateParameters_cb _hidl_cb) override; Return<Result> setPlaybackRateParameters(const PlaybackRate &playbackRate) override; + int16_t getVolumeNumerator() const { return mVolumeNumerator; }; + const DeviceAddress &getDeviceAddress() const { return mCommon.m_device; } + const AudioConfig &getAudioConfig() const { return mCommon.m_config; } + const hidl_bitfield<AudioOutputFlag> &getAudioOutputFlags() const { return mCommon.m_flags; } + + uint64_t &getFrameCounter() { return mFrames; } + private: + Result closeImpl(bool fromDctor); + sp<IDevice> mDev; void (* const mUnrefDevice)(IDevice*); const StreamCommon mCommon; const SourceMetadata mSourceMetadata; std::unique_ptr<IOThread> mWriteThread; + std::atomic<int16_t> mVolumeNumerator = kVolumeDenominator; + + // The count is not reset to zero when output enters standby. + uint64_t mFrames = 0; }; } // namespace implementation diff --git a/audio/talsa.cpp b/audio/talsa.cpp index 61ea1409..12c22b0a 100644 --- a/audio/talsa.cpp +++ b/audio/talsa.cpp @@ -14,8 +14,9 @@ * limitations under the License. */ -#include "talsa.h" #include <log/log.h> +#include "talsa.h" +#include "debug.h" namespace android { namespace hardware { @@ -60,7 +61,7 @@ std::unique_ptr<pcm_t, PcmDeleter> pcmOpen(const unsigned int dev, "frameCount=%zu isOut=%d with %s", __func__, __LINE__, nChannels, sampleRateHz, frameCount, isOut, pcm_get_error(pcm.get())); - return nullptr; + return FAILURE(nullptr); } } diff --git a/audio/util.cpp b/audio/util.cpp index 746e37de..dbe620ba 100644 --- a/audio/util.cpp +++ b/audio/util.cpp @@ -18,6 +18,7 @@ #include <cutils/bitops.h> #include <system/audio.h> #include "util.h" +#include "debug.h" namespace android { namespace hardware { @@ -59,11 +60,16 @@ bool checkSampleRateHz(uint32_t value, uint32_t &suggest) { } suggest = kSupportedRatesHz.back(); - return false; + return FAILURE(false); +} + +size_t align(size_t v, size_t a) { + return (v + a - 1) / a * a; } size_t getBufferSizeFrames(size_t duration_ms, uint32_t sample_rate) { - return sample_rate * duration_ms / 1000; + // AudioFlinger requires the buffer to be aligned by 16 frames + return align(sample_rate * duration_ms / 1000, 16); } } // namespace @@ -107,7 +113,7 @@ bool checkAudioConfig(bool isOut, kSupportedOutChannelMask.end(), cfg.channelMask) == kSupportedOutChannelMask.end()) { suggested.channelMask = AudioChannelMask::OUT_STEREO | 0; - valid = false; + valid = FAILURE(false); } else { suggested.channelMask = cfg.channelMask; } @@ -116,7 +122,7 @@ bool checkAudioConfig(bool isOut, kSupportedInChannelMask.end(), cfg.channelMask) == kSupportedInChannelMask.end()) { suggested.channelMask = AudioChannelMask::IN_STEREO | 0; - valid = false; + valid = FAILURE(false); } else { suggested.channelMask = cfg.channelMask; } @@ -126,7 +132,7 @@ bool checkAudioConfig(bool isOut, kSupportedAudioFormats.end(), cfg.format) == kSupportedAudioFormats.end()) { suggested.format = AudioFormat::PCM_16_BIT; - valid = false; + valid = FAILURE(false); } else { suggested.format = cfg.format; } @@ -140,25 +146,11 @@ bool checkAudioConfig(bool isOut, return valid; } -StreamPosition::StreamPosition() : mTimestamp(systemTime(SYSTEM_TIME_MONOTONIC)) {} - -void StreamPosition::addFrames(uint64_t n) { - mTimestamp = systemTime(SYSTEM_TIME_MONOTONIC); - mFrames += n; -} - -void StreamPosition::now(const size_t sampleRateHz, - uint64_t &frames, - nsecs_t ×tamp) const { - const nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - const uint64_t deltaUs = ns2us(now - mTimestamp); - - frames = mFrames + sampleRateHz * deltaUs / 1000000; - timestamp = now; -} - -void StreamPosition::reset() { - *this = StreamPosition(); +TimeSpec nsecs2TimeSpec(nsecs_t ns) { + TimeSpec ts; + ts.tvSec = ns2s(ns); + ts.tvNSec = ns - s2ns(ts.tvSec); + return ts; } } // namespace util diff --git a/audio/util.h b/audio/util.h index bfac69a5..aae8f535 100644 --- a/audio/util.h +++ b/audio/util.h @@ -43,15 +43,7 @@ bool checkAudioConfig(bool isOut, const AudioConfig &cfg, AudioConfig &suggested); -struct StreamPosition { - StreamPosition(); - void addFrames(uint64_t n); - void now(size_t sampleRateHz, uint64_t &frames, nsecs_t ×tamp) const; - void reset(); - - uint64_t mFrames = 0; - nsecs_t mTimestamp; -}; +TimeSpec nsecs2TimeSpec(nsecs_t); } // namespace util } // namespace implementation diff --git a/camera/EmulatedFakeCamera3.cpp b/camera/EmulatedFakeCamera3.cpp index 2009a33b..2da2c4da 100644 --- a/camera/EmulatedFakeCamera3.cpp +++ b/camera/EmulatedFakeCamera3.cpp @@ -1109,7 +1109,7 @@ status_t EmulatedFakeCamera3::getCameraCapabilities() { mCapabilities.add(FULL_LEVEL); // "RAW" causes several CTS failures: b/68723953, disable it so far. // TODO: add "RAW" back when all failures are resolved. - //mCapabilities.add(RAW); + mCapabilities.add(RAW); mCapabilities.add(MOTION_TRACKING); } @@ -1330,7 +1330,7 @@ status_t EmulatedFakeCamera3::constructStaticInfo() { // android.flash - static const uint8_t flashAvailable = 0; + static const uint8_t flashAvailable = 1; ADD_STATIC_ENTRY(ANDROID_FLASH_INFO_AVAILABLE, &flashAvailable, 1); // android.hotPixel diff --git a/camera/JpegCompressor.cpp b/camera/JpegCompressor.cpp index 3a5b15e1..168b98a0 100644 --- a/camera/JpegCompressor.cpp +++ b/camera/JpegCompressor.cpp @@ -46,7 +46,7 @@ typedef size_t (*GetCompressedSizeFunc)(JpegStub* stub); NV21JpegCompressor::NV21JpegCompressor() { - const char dlName[] = "/vendor/lib/hw/camera.goldfish.jpeg.so"; + const char dlName[] = "/vendor/lib/hw/camera.ranchu.jpeg.so"; if (mDl == NULL) { mDl = dlopen(dlName, RTLD_NOW); } diff --git a/camera/media_codecs.xml b/camera/media_codecs.xml index edead34f..81cffc93 100644 --- a/camera/media_codecs.xml +++ b/camera/media_codecs.xml @@ -82,6 +82,16 @@ Only the three quirks included above are recognized at this point: <Setting name="max-video-encoder-input-buffers" value="12" /> </Settings> + <MediaCodec name="OMX.android.goldfish.h264.decoder" type="video/avc" > + <Limit name="concurrent-instances" max="4" /> + </MediaCodec> + <MediaCodec name="OMX.android.goldfish.vp8.decoder" type="video/x-vnd.on2.vp8" > + <Limit name="concurrent-instances" max="4" /> + </MediaCodec> + <MediaCodec name="OMX.android.goldfish.vp9.decoder" type="video/x-vnd.on2.vp9" > + <Limit name="concurrent-instances" max="4" /> + </MediaCodec> + <Include href="media_codecs_google_audio.xml" /> <Include href="media_codecs_google_telephony.xml" /> <Include href="media_codecs_google_video.xml" /> diff --git a/camera/media_codecs_google_video_default.xml b/camera/media_codecs_google_video_default.xml index 3d955487..588ead52 100644 --- a/camera/media_codecs_google_video_default.xml +++ b/camera/media_codecs_google_video_default.xml @@ -36,37 +36,18 @@ <Feature name="adaptive-playback" /> </MediaCodec> <MediaCodec name="OMX.android.goldfish.h264.decoder" type="video/avc"> - <Limit name="size" min="96x96" max="2560x2560" /> + <Limit name="size" min="96x96" max="3840x2160" /> <Limit name="alignment" value="2x2" /> <Limit name="block-size" value="16x16" /> <Limit name="blocks-per-second" range="24-2073600" /> <Limit name="bitrate" range="1-120000000" /> <Limit name="frame-rate" range="1-480" /> - <Limit name="performance-point-2560x1440" value="80" /> - <Limit name="performance-point-1920x1080" value="160" /> - <Limit name="performance-point-1280x720" value="480" /> - <Limit name="measured-frame-rate-320x240" range="183-183" /> - <Limit name="measured-frame-rate-720x480" range="181-181" /> - <Limit name="measured-frame-rate-1280x720" range="182-184" /> - <Limit name="measured-frame-rate-1920x1080" range="30-50" /> - <Limit name="measured-frame-rate-2560x1440" range="30-40" /> - <Feature name="adaptive-playback" /> - </MediaCodec> - <MediaCodec name="OMX.google.goldfish.h264.decoder" type="video/avc"> - <Limit name="size" min="96x96" max="2560x2560" /> - <Limit name="alignment" value="2x2" /> - <Limit name="block-size" value="16x16" /> - <Limit name="blocks-per-second" range="24-2073600" /> - <Limit name="bitrate" range="1-120000000" /> - <Limit name="frame-rate" range="1-480" /> - <Limit name="performance-point-2560x1440" value="80" /> - <Limit name="performance-point-1920x1080" value="160" /> - <Limit name="performance-point-1280x720" value="480" /> - <Limit name="measured-frame-rate-320x240" range="183-183" /> - <Limit name="measured-frame-rate-720x480" range="181-181" /> - <Limit name="measured-frame-rate-1280x720" range="182-184" /> - <Limit name="measured-frame-rate-1920x1080" range="30-50" /> - <Limit name="measured-frame-rate-2560x1440" range="30-40" /> + <Limit name="performance-point-3840x2160" value="60" /> + <Limit name="measured-frame-rate-320x240" range="257-266" /> + <Limit name="measured-frame-rate-720x480" range="262-264" /> + <Limit name="measured-frame-rate-1280x720" range="227-251" /> + <Limit name="measured-frame-rate-1920x1080" range="235-247" /> + <Limit name="measured-frame-rate-3840x2160" range="235-247" /> <Feature name="adaptive-playback" /> </MediaCodec> <MediaCodec name="OMX.google.h264.decoder" type="video/avc"> @@ -77,9 +58,7 @@ <Limit name="bitrate" range="1-120000000" /> <Limit name="frame-rate" range="1-480" /> <Limit name="concurrent-instances" max="16" /> - <Limit name="performance-point-720x480" range="180" /> - <Limit name="performance-point-1280x720" value="480" /> - <Limit name="performance-point-1920x1080" value="30" /> + <Limit name="performance-point-1920x1088" value="30" /> <Limit name="measured-frame-rate-320x240" range="183-183" /> <Limit name="measured-frame-rate-720x480" range="181-181" /> <Limit name="measured-frame-rate-1280x720" range="182-184" /> @@ -98,71 +77,33 @@ <Feature name="adaptive-playback" /> </MediaCodec> <MediaCodec name="OMX.android.goldfish.vp9.decoder" type="video/x-vnd.on2.vp9"> - <Limit name="size" min="96x96" max="3840x2150" /> + <Limit name="size" min="96x96" max="3840x2160" /> <Limit name="alignment" value="2x2" /> <Limit name="block-size" value="16x16" /> <Limit name="blocks-per-second" min="24" max="2073600" /> <Limit name="bitrate" range="1-120000000" /> <Limit name="frame-rate" range="1-480" /> - <Limit name="performance-point-2560x1440" value="80" /> - <Limit name="performance-point-1920x1080" value="160" /> - <Limit name="performance-point-1280x720" value="480" /> - <Limit name="measured-frame-rate-320x240" range="183-183" /> - <Limit name="measured-frame-rate-720x480" range="181-181" /> - <Limit name="measured-frame-rate-1280x720" range="182-184" /> - <Limit name="measured-frame-rate-1920x1088" range="30-50" /> - <Limit name="measured-frame-rate-2560x1440" range="30-40" /> + <Limit name="performance-point-3840x2160" value="60" /> + <Limit name="measured-frame-rate-320x180" range="237-258" /> + <Limit name="measured-frame-rate-640x360" range="237-258" /> + <Limit name="measured-frame-rate-1280x720" range="237-258" /> + <Limit name="measured-frame-rate-1920x1080" range="293-302" /> + <Limit name="measured-frame-rate-3840x2160" range="150-150" /> <Feature name="adaptive-playback" /> </MediaCodec> <MediaCodec name="OMX.android.goldfish.vp8.decoder" type="video/x-vnd.on2.vp8"> - <Limit name="size" min="96x96" max="3840x2150" /> + <Limit name="size" min="96x96" max="3840x2160" /> <Limit name="alignment" value="2x2" /> <Limit name="block-size" value="16x16" /> <Limit name="blocks-per-second" min="24" max="2073600" /> <Limit name="bitrate" range="1-120000000" /> <Limit name="frame-rate" range="1-480" /> - <Limit name="performance-point-2560x1440" value="80" /> - <Limit name="performance-point-1920x1080" value="160" /> - <Limit name="performance-point-1280x720" value="480" /> - <Limit name="measured-frame-rate-320x240" range="183-183" /> - <Limit name="measured-frame-rate-720x480" range="181-181" /> - <Limit name="measured-frame-rate-1280x720" range="182-184" /> - <Limit name="measured-frame-rate-1920x1088" range="30-50" /> - <Limit name="measured-frame-rate-2560x1440" range="30-40" /> - <Feature name="adaptive-playback" /> - </MediaCodec> - <MediaCodec name="OMX.google.goldfish.vp8.decoder" type="video/x-vnd.on2.vp8"> - <Limit name="size" min="2x2" max="2560x2560" /> - <Limit name="alignment" value="2x2" /> - <Limit name="block-size" value="16x16" /> - <Limit name="blocks-per-second" min="24" max="2073600" /> - <Limit name="bitrate" range="1-120000000" /> - <Limit name="frame-rate" range="1-480" /> - <Limit name="performance-point-2560x1440" value="80" /> - <Limit name="performance-point-1920x1080" value="160" /> - <Limit name="performance-point-1280x720" value="480" /> - <Limit name="measured-frame-rate-320x240" range="183-183" /> - <Limit name="measured-frame-rate-720x480" range="181-181" /> - <Limit name="measured-frame-rate-1280x720" range="182-184" /> - <Limit name="measured-frame-rate-1920x1088" range="30-50" /> - <Limit name="measured-frame-rate-2560x1440" range="30-40" /> - <Feature name="adaptive-playback" /> - </MediaCodec> - <MediaCodec name="OMX.google.goldfish.vp9.decoder" type="video/x-vnd.on2.vp9"> - <Limit name="size" min="2x2" max="2560x2560" /> - <Limit name="alignment" value="2x2" /> - <Limit name="block-size" value="16x16" /> - <Limit name="blocks-per-second" min="24" max="2073600" /> - <Limit name="bitrate" range="1-120000000" /> - <Limit name="frame-rate" range="1-480" /> - <Limit name="performance-point-2560x1440" value="80" /> - <Limit name="performance-point-1920x1080" value="160" /> - <Limit name="performance-point-1280x720" value="480" /> - <Limit name="measured-frame-rate-320x240" range="183-183" /> - <Limit name="measured-frame-rate-720x480" range="181-181" /> - <Limit name="measured-frame-rate-1280x720" range="182-184" /> - <Limit name="measured-frame-rate-1920x1088" range="30-50" /> - <Limit name="measured-frame-rate-2560x1440" range="30-40" /> + <Limit name="performance-point-3840x2160" value="60" /> + <Limit name="measured-frame-rate-320x180" range="743-817" /> + <Limit name="measured-frame-rate-640x360" range="237-258" /> + <Limit name="measured-frame-rate-1280x720" range="237-258" /> + <Limit name="measured-frame-rate-1920x1080" range="30-160" /> + <Limit name="measured-frame-rate-3840x2160" range="30-90" /> <Feature name="adaptive-playback" /> </MediaCodec> <MediaCodec name="OMX.google.vp8.decoder" type="video/x-vnd.on2.vp8"> @@ -172,9 +113,7 @@ <Limit name="blocks-per-second" min="24" max="2073600" /> <Limit name="bitrate" range="1-120000000" /> <Limit name="frame-rate" range="1-480" /> - <Limit name="performance-point-2560x1440" value="80" /> - <Limit name="performance-point-1920x1080" value="160" /> - <Limit name="performance-point-1280x720" value="480" /> + <Limit name="performance-point-1920x1088" value="60" /> <Limit name="measured-frame-rate-320x240" range="183-183" /> <Limit name="measured-frame-rate-720x480" range="181-181" /> <Limit name="measured-frame-rate-1280x720" range="182-184" /> @@ -189,12 +128,10 @@ <Limit name="blocks-per-second" min="24" max="2073600" /> <Limit name="bitrate" range="1-120000000" /> <Limit name="frame-rate" range="1-480" /> - <Limit name="performance-point-2560x1440" value="80" /> - <Limit name="performance-point-1920x1080" value="160" /> - <Limit name="performance-point-1280x720" value="480" /> + <Limit name="performance-point-1920x1088" value="60" /> <Limit name="measured-frame-rate-320x240" range="183-183" /> <Limit name="measured-frame-rate-720x480" range="181-181" /> - <Limit name="measured-frame-rate-1280x720" range="182-184" /> + <Limit name="measured-frame-rate-1280x720" range="121-125" /> <Limit name="measured-frame-rate-1920x1088" range="30-50" /> <Limit name="measured-frame-rate-2560x1440" range="30-40" /> <Feature name="adaptive-playback" /> diff --git a/data/etc/advancedFeatures.ini b/data/etc/advancedFeatures.ini index 92c37748..73a8fc25 100644 --- a/data/etc/advancedFeatures.ini +++ b/data/etc/advancedFeatures.ini @@ -10,6 +10,7 @@ HostComposition = on RefCountPipe = on VirtioInput = on DynamicPartition = on +HardwareDecoder = on YUVCache = on GLDirectMem = on Vulkan = on diff --git a/data/etc/config.ini.xl b/data/etc/config.ini.xl index 40ec7cca..32d26659 100644 --- a/data/etc/config.ini.xl +++ b/data/etc/config.ini.xl @@ -16,5 +16,5 @@ hw.sensors.proximity=yes image.sysdir.1=x86/ skin.dynamic=no hw.lcd.density=560 -skin.name=1440x2560 -skin.path=1440x2560 +skin.name=1440x2960 +skin.path=1440x2960 diff --git a/data/etc/google/user/advancedFeatures.ini b/data/etc/google/user/advancedFeatures.ini index 4b7cb339..85b5c3ab 100644 --- a/data/etc/google/user/advancedFeatures.ini +++ b/data/etc/google/user/advancedFeatures.ini @@ -11,6 +11,7 @@ HostComposition = on RefCountPipe = on VirtioInput = on DynamicPartition = on +HardwareDecoder = on MultiDisplay = on YUVCache = on GLDirectMem = on diff --git a/data/etc/google/userdebug/advancedFeatures.ini b/data/etc/google/userdebug/advancedFeatures.ini index 4b7cb339..85b5c3ab 100644 --- a/data/etc/google/userdebug/advancedFeatures.ini +++ b/data/etc/google/userdebug/advancedFeatures.ini @@ -11,6 +11,7 @@ HostComposition = on RefCountPipe = on VirtioInput = on DynamicPartition = on +HardwareDecoder = on MultiDisplay = on YUVCache = on GLDirectMem = on diff --git a/emulator-info.txt b/emulator-info.txt index 1ae560d8..fb45a7e0 100644 --- a/emulator-info.txt +++ b/emulator-info.txt @@ -1,2 +1,2 @@ # Emulator (stable) version -require version-emulator=6278574 +require version-emulator=6629878 diff --git a/rro_overlays/TetheringOverlay/Android.bp b/rro_overlays/TetheringOverlay/Android.bp new file mode 100644 index 00000000..31b0c570 --- /dev/null +++ b/rro_overlays/TetheringOverlay/Android.bp @@ -0,0 +1,22 @@ +// +// Copyright (C) 2020 The Android Open-Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +runtime_resource_overlay { + name: "EmulatorTetheringConfigOverlay", + resource_dirs: ["res"], + product_specific: true, + sdk_version: "current", +} diff --git a/rro_overlays/TetheringOverlay/AndroidManifest.xml b/rro_overlays/TetheringOverlay/AndroidManifest.xml new file mode 100644 index 00000000..fc8c8bd0 --- /dev/null +++ b/rro_overlays/TetheringOverlay/AndroidManifest.xml @@ -0,0 +1,11 @@ +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.networkstack.tethering.emulator" + android:versionCode="1" + android:versionName="1.0"> + <application android:hasCode="false" /> + <overlay + android:targetPackage="com.android.networkstack.tethering" + android:targetName="TetheringConfig" + android:isStatic="true" + android:priority="0"/> +</manifest> diff --git a/rro_overlays/TetheringOverlay/res/values/config.xml b/rro_overlays/TetheringOverlay/res/values/config.xml new file mode 100644 index 00000000..8cb8b405 --- /dev/null +++ b/rro_overlays/TetheringOverlay/res/values/config.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- Allow testing SoftAP using the simulated interfaces on the emulator. --> + <string-array name="config_tether_wifi_regexs"> + <item>"wlan\\d"</item> + </string-array> + <string-array name="config_tether_wifi_p2p_regexs"> + <item>"p2p-wlan\\d-.*"</item> + </string-array> +</resources> diff --git a/sensors/multihal_sensors.cpp b/sensors/multihal_sensors.cpp index 3502add9..104ff7f6 100644 --- a/sensors/multihal_sensors.cpp +++ b/sensors/multihal_sensors.cpp @@ -26,7 +26,9 @@ using ahs21::SensorType; using ahs10::SensorFlagBits; using ahs10::MetaDataEventType; -MultihalSensors::MultihalSensors() : m_qemuSensorsFd(qemud_channel_open("sensors")) { +MultihalSensors::MultihalSensors() + : m_qemuSensorsFd(qemud_channel_open("sensors")) + , m_batchInfo(getSensorNumber()) { if (!m_qemuSensorsFd.ok()) { ALOGE("%s:%d: m_qemuSensorsFd is not opened", __func__, __LINE__); ::abort(); @@ -56,13 +58,16 @@ MultihalSensors::MultihalSensors() : m_qemuSensorsFd(qemud_channel_open("sensors ::abort(); } buffer[len] = 0; - uint32_t availableSensorsMask = 0; - if (sscanf(buffer, "%u", &availableSensorsMask) != 1) { + uint32_t hostSensorsMask = 0; + if (sscanf(buffer, "%u", &hostSensorsMask) != 1) { ALOGE("%s:%d: Can't parse qemud response", __func__, __LINE__); ::abort(); } m_availableSensorsMask = - availableSensorsMask & ((1u << getSensorNumber()) - 1); + hostSensorsMask & ((1u << getSensorNumber()) - 1); + + ALOGI("%s:%d: host sensors mask=%x, available sensors mask=%x", + __func__, __LINE__, hostSensorsMask, m_availableSensorsMask); if (!::android::base::Socketpair(AF_LOCAL, SOCK_STREAM, 0, &m_callersFd, &m_sensorThreadFd)) { @@ -70,11 +75,17 @@ MultihalSensors::MultihalSensors() : m_qemuSensorsFd(qemud_channel_open("sensors ::abort(); } - m_sensorThread = std::thread(qemuSensorListenerThreadStart, this); + m_sensorThread = std::thread(&MultihalSensors::qemuSensorListenerThread, this); + m_batchThread = std::thread(&MultihalSensors::batchThread, this); } MultihalSensors::~MultihalSensors() { - disableAllSensors(); + setAllQemuSensors(false); + + m_batchRunning = false; + m_batchUpdated.notify_one(); + m_batchThread.join(); + qemuSensorThreadSendCommand(kCMD_QUIT); m_sensorThread.join(); } @@ -104,7 +115,7 @@ Return<void> MultihalSensors::getSensorsList_2_1(getSensorsList_2_1_cb _hidl_cb) } Return<Result> MultihalSensors::setOperationMode(const OperationMode mode) { - std::unique_lock<std::mutex> lock(m_apiMtx); + std::unique_lock<std::mutex> lock(m_mtx); if (m_activeSensorsMask) { return Result::INVALID_OPERATION; @@ -120,25 +131,31 @@ Return<Result> MultihalSensors::activate(const int32_t sensorHandle, return Result::BAD_VALUE; } - std::unique_lock<std::mutex> lock(m_apiMtx); + std::unique_lock<std::mutex> lock(m_mtx); + BatchInfo& batchInfo = m_batchInfo[sensorHandle]; - uint32_t newActiveMask; if (enabled) { - newActiveMask = m_activeSensorsMask | (1u << sensorHandle); - } else { - newActiveMask = m_activeSensorsMask & ~(1u << sensorHandle); - } - if (m_activeSensorsMask == newActiveMask) { - return Result::OK; - } - - if (m_opMode == OperationMode::NORMAL) { - if (!activateQemuSensorImpl(m_qemuSensorsFd.get(), sensorHandle, enabled)) { - return Result::INVALID_OPERATION; + const SensorInfo* sensor = getSensorInfoByHandle(sensorHandle); + LOG_ALWAYS_FATAL_IF(!sensor); + if (!(sensor->flags & static_cast<uint32_t>(SensorFlagBits::ON_CHANGE_MODE))) { + if (batchInfo.samplingPeriodNs <= 0) { + return Result::BAD_VALUE; + } + + BatchEventRef batchEventRef; + batchEventRef.timestamp = + ::android::elapsedRealtimeNano() + batchInfo.samplingPeriodNs; + batchEventRef.sensorHandle = sensorHandle; + batchEventRef.generation = ++batchInfo.generation; + + m_batchQueue.push(batchEventRef); + m_batchUpdated.notify_one(); } - } - m_activeSensorsMask = newActiveMask; + m_activeSensorsMask = m_activeSensorsMask | (1u << sensorHandle); + } else { + m_activeSensorsMask = m_activeSensorsMask & ~(1u << sensorHandle); + } return Result::OK; } @@ -147,26 +164,35 @@ Return<Result> MultihalSensors::batch(const int32_t sensorHandle, const int64_t maxReportLatencyNs) { (void)maxReportLatencyNs; + if (!isSensorHandleValid(sensorHandle)) { + return Result::BAD_VALUE; + } + const SensorInfo* sensor = getSensorInfoByHandle(sensorHandle); - if (sensor) { - if (samplingPeriodNs >= sensor->minDelay) { - return Result::OK; - } else { - return Result::BAD_VALUE; - } - } else { + LOG_ALWAYS_FATAL_IF(!sensor); + + if (samplingPeriodNs < sensor->minDelay) { return Result::BAD_VALUE; } + + std::unique_lock<std::mutex> lock(m_mtx); + if (m_opMode == OperationMode::NORMAL) { + m_batchInfo[sensorHandle].samplingPeriodNs = samplingPeriodNs; + } + + return Result::OK; } Return<Result> MultihalSensors::flush(const int32_t sensorHandle) { - const SensorInfo* sensor = getSensorInfoByHandle(sensorHandle); - if (!sensor) { + if (!isSensorHandleValid(sensorHandle)) { return Result::BAD_VALUE; } - std::unique_lock<std::mutex> lock(m_apiMtx); - if (!(m_activeSensorsMask & (1u << sensorHandle))) { + const SensorInfo* sensor = getSensorInfoByHandle(sensorHandle); + LOG_ALWAYS_FATAL_IF(!sensor); + + std::unique_lock<std::mutex> lock(m_mtx); + if (!isSensorActive(sensorHandle)) { return Result::BAD_VALUE; } @@ -175,48 +201,58 @@ Return<Result> MultihalSensors::flush(const int32_t sensorHandle) { event.sensorType = SensorType::META_DATA; event.u.meta.what = MetaDataEventType::META_DATA_FLUSH_COMPLETE; - postSensorEventLocked(event); + doPostSensorEventLocked(*sensor, event); return Result::OK; } Return<Result> MultihalSensors::injectSensorData_2_1(const Event& event) { + if (!isSensorHandleValid(event.sensorHandle)) { + return Result::BAD_VALUE; + } if (event.sensorType == SensorType::ADDITIONAL_INFO) { return Result::OK; } - std::unique_lock<std::mutex> lock(m_apiMtx); + std::unique_lock<std::mutex> lock(m_mtx); if (m_opMode != OperationMode::DATA_INJECTION) { return Result::INVALID_OPERATION; } const SensorInfo* sensor = getSensorInfoByHandle(event.sensorHandle); - if (!sensor) { - return Result::BAD_VALUE; - } + LOG_ALWAYS_FATAL_IF(!sensor); if (sensor->type != event.sensorType) { return Result::BAD_VALUE; } - postSensorEventLocked(event); + doPostSensorEventLocked(*sensor, event); return Result::OK; } Return<Result> MultihalSensors::initialize(const sp<IHalProxyCallback>& halProxyCallback) { - std::unique_lock<std::mutex> lock(m_apiMtx); - disableAllSensors(); + std::unique_lock<std::mutex> lock(m_mtx); + setAllQemuSensors(true); // we need to start sampling sensors for batching m_opMode = OperationMode::NORMAL; m_halProxyCallback = halProxyCallback; return Result::OK; } void MultihalSensors::postSensorEvent(const Event& event) { - std::unique_lock<std::mutex> lock(m_apiMtx); - postSensorEventLocked(event); + const SensorInfo* sensor = getSensorInfoByHandle(event.sensorHandle); + LOG_ALWAYS_FATAL_IF(!sensor); + + std::unique_lock<std::mutex> lock(m_mtx); + if (sensor->flags & static_cast<uint32_t>(SensorFlagBits::ON_CHANGE_MODE)) { + if (isSensorActive(event.sensorHandle)) { + doPostSensorEventLocked(*sensor, event); + } + } else { // CONTINUOUS_MODE + m_batchInfo[event.sensorHandle].event = event; + } } -void MultihalSensors::postSensorEventLocked(const Event& event) { +void MultihalSensors::doPostSensorEventLocked(const SensorInfo& sensor, + const Event& event) { const bool isWakeupEvent = - getSensorInfoByHandle(event.sensorHandle)->flags & - static_cast<uint32_t>(SensorFlagBits::WAKE_UP); + sensor.flags & static_cast<uint32_t>(SensorFlagBits::WAKE_UP); m_halProxyCallback->postEvents( {event}, @@ -227,6 +263,65 @@ bool MultihalSensors::qemuSensorThreadSendCommand(const char cmd) const { return TEMP_FAILURE_RETRY(write(m_callersFd.get(), &cmd, 1)) == 1; } +bool MultihalSensors::isSensorHandleValid(int sensorHandle) const { + if (!goldfish::isSensorHandleValid(sensorHandle)) { + return false; + } + + if (!(m_availableSensorsMask & (1u << sensorHandle))) { + return false; + } + + return true; +} + +void MultihalSensors::batchThread() { + using high_resolution_clock = std::chrono::high_resolution_clock; + + while (m_batchRunning) { + std::unique_lock<std::mutex> lock(m_mtx); + if (m_batchQueue.empty()) { + m_batchUpdated.wait(lock); + } else { + const int64_t t = m_batchQueue.top().timestamp; + const auto d = std::chrono::nanoseconds(t); + high_resolution_clock::time_point waitUntil(d); + m_batchUpdated.wait_until(lock, waitUntil); + } + + const int64_t nowNs = ::android::elapsedRealtimeNano(); + while (!m_batchQueue.empty() && (nowNs >= m_batchQueue.top().timestamp)) { + BatchEventRef evRef = m_batchQueue.top(); + m_batchQueue.pop(); + + const int sensorHandle = evRef.sensorHandle; + LOG_ALWAYS_FATAL_IF(!goldfish::isSensorHandleValid(sensorHandle)); + if (!isSensorActive(sensorHandle)) { + continue; + } + + BatchInfo &batchInfo = m_batchInfo[sensorHandle]; + if (batchInfo.event.sensorType == SensorType::META_DATA) { + ALOGW("%s:%d the host has not provided value yet for sensorHandle=%d", + __func__, __LINE__, sensorHandle); + } else { + batchInfo.event.timestamp = evRef.timestamp; + const SensorInfo* sensor = getSensorInfoByHandle(sensorHandle); + LOG_ALWAYS_FATAL_IF(!sensor); + doPostSensorEventLocked(*sensor, batchInfo.event); + } + + if (evRef.generation == batchInfo.generation) { + const int64_t samplingPeriodNs = batchInfo.samplingPeriodNs; + LOG_ALWAYS_FATAL_IF(samplingPeriodNs <= 0); + + evRef.timestamp += samplingPeriodNs; + m_batchQueue.push(evRef); + } + } + } +} + /// not supported ////////////////////////////////////////////////////////////// Return<void> MultihalSensors::registerDirectChannel(const SharedMemInfo& mem, registerDirectChannel_cb _hidl_cb) { diff --git a/sensors/multihal_sensors.h b/sensors/multihal_sensors.h index 80ed6a3b..382af7f7 100644 --- a/sensors/multihal_sensors.h +++ b/sensors/multihal_sensors.h @@ -17,8 +17,12 @@ #pragma once #include <android-base/unique_fd.h> #include <V2_1/SubHal.h> +#include <atomic> +#include <condition_variable> #include <cstdint> +#include <queue> #include <thread> +#include <vector> namespace goldfish { namespace ahs = ::android::hardware::sensors; @@ -26,6 +30,7 @@ namespace ahs21 = ahs::V2_1; namespace ahs10 = ahs::V1_0; using ahs21::implementation::IHalProxyCallback; +using ahs21::SensorInfo; using ahs21::Event; using ahs10::OperationMode; using ahs10::RateLevel; @@ -81,14 +86,18 @@ private: float lastHingeAngle2Value = kSensorNoValue; }; + bool isSensorHandleValid(int sensorHandle) const; + bool isSensorActive(int sensorHandle) const { + return m_activeSensorsMask & (1u << sensorHandle); // m_mtx required + } static bool activateQemuSensorImpl(int pipe, int sensorHandle, bool enabled); - bool disableAllSensors(); + bool setAllQemuSensors(bool enabled); void parseQemuSensorEvent(const int pipe, QemuSensorsProtocolState* state); void postSensorEvent(const Event& event); - void postSensorEventLocked(const Event& event); + void doPostSensorEventLocked(const SensorInfo& sensor, const Event& event); void qemuSensorListenerThread(); - static void qemuSensorListenerThreadStart(MultihalSensors* that); + void batchThread(); static constexpr char kCMD_QUIT = 'q'; bool qemuSensorThreadSendCommand(char cmd) const; @@ -105,7 +114,32 @@ private: uint32_t m_activeSensorsMask = 0; OperationMode m_opMode = OperationMode::NORMAL; sp<IHalProxyCallback> m_halProxyCallback; - mutable std::mutex m_apiMtx; + + // batching + struct BatchEventRef { + int64_t timestamp = -1; + int sensorHandle = -1; + int generation = 0; + + bool operator<(const BatchEventRef &rhs) const { + // not a typo, we want m_batchQueue.top() to be the smallest timestamp + return timestamp > rhs.timestamp; + } + }; + + struct BatchInfo { + Event event; + int64_t samplingPeriodNs = 0; + int generation = 0; + }; + + std::priority_queue<BatchEventRef> m_batchQueue; + std::vector<BatchInfo> m_batchInfo; + std::condition_variable m_batchUpdated; + std::thread m_batchThread; + std::atomic<bool> m_batchRunning = true; + + mutable std::mutex m_mtx; }; } // namespace goldfish diff --git a/sensors/multihal_sensors_epoll.cpp b/sensors/multihal_sensors_epoll.cpp index 0be12245..cf2ae56b 100644 --- a/sensors/multihal_sensors_epoll.cpp +++ b/sensors/multihal_sensors_epoll.cpp @@ -38,10 +38,6 @@ int qemuSensortThreadRcvCommand(const int fd) { } } // namespace -void MultihalSensors::qemuSensorListenerThreadStart(MultihalSensors* that) { - that->qemuSensorListenerThread(); -} - void MultihalSensors::qemuSensorListenerThread() { const unique_fd epollFd(epoll_create1(0)); if (!epollFd.ok()) { diff --git a/sensors/multihal_sensors_qemu.cpp b/sensors/multihal_sensors_qemu.cpp index a07d569b..f5da3a15 100644 --- a/sensors/multihal_sensors_qemu.cpp +++ b/sensors/multihal_sensors_qemu.cpp @@ -69,19 +69,16 @@ bool MultihalSensors::activateQemuSensorImpl(const int pipe, } } -bool MultihalSensors::disableAllSensors() { - if (m_opMode == OperationMode::NORMAL) { - uint32_t mask = m_activeSensorsMask; - for (int i = 0; mask; ++i, mask >>= 1) { - if (mask & 1) { - if (!activateQemuSensorImpl(m_qemuSensorsFd.get(), i, false)) { - return false; - } +bool MultihalSensors::setAllQemuSensors(const bool enabled) { + uint32_t mask = m_availableSensorsMask; + for (int i = 0; mask; ++i, mask >>= 1) { + if (mask & 1) { + if (!activateQemuSensorImpl(m_qemuSensorsFd.get(), i, enabled)) { + return false; } } } - m_activeSensorsMask = 0; return true; } diff --git a/sensors/sensor_list.cpp b/sensors/sensor_list.cpp index 245379fa..d228ba62 100644 --- a/sensors/sensor_list.cpp +++ b/sensors/sensor_list.cpp @@ -122,11 +122,11 @@ const SensorInfo kAllSensors[] = { .maxRange = 80.0, .resolution = 1.0, .power = 0.0, - .minDelay = 10000, + .minDelay = 0, .fifoReservedEventCount = 0, .fifoMaxEventCount = 0, .requiredPermission = "", - .maxDelay = 500000, + .maxDelay = 0, .flags = SensorFlagBits::DATA_INJECTION | SensorFlagBits::ON_CHANGE_MODE }, @@ -140,11 +140,11 @@ const SensorInfo kAllSensors[] = { .maxRange = 1.0, .resolution = 1.0, .power = 20.0, - .minDelay = 10000, + .minDelay = 0, .fifoReservedEventCount = 0, .fifoMaxEventCount = 0, .requiredPermission = "", - .maxDelay = 500000, + .maxDelay = 0, .flags = SensorFlagBits::DATA_INJECTION | SensorFlagBits::ON_CHANGE_MODE | SensorFlagBits::WAKE_UP @@ -159,11 +159,11 @@ const SensorInfo kAllSensors[] = { .maxRange = 40000.0, .resolution = 1.0, .power = 20.0, - .minDelay = 10000, + .minDelay = 0, .fifoReservedEventCount = 0, .fifoMaxEventCount = 0, .requiredPermission = "", - .maxDelay = 500000, + .maxDelay = 0, .flags = SensorFlagBits::DATA_INJECTION | SensorFlagBits::ON_CHANGE_MODE }, @@ -195,11 +195,11 @@ const SensorInfo kAllSensors[] = { .maxRange = 100.0, .resolution = 1.0, .power = 20.0, - .minDelay = 10000, + .minDelay = 0, .fifoReservedEventCount = 0, .fifoMaxEventCount = 0, .requiredPermission = "", - .maxDelay = 500000, + .maxDelay = 0, .flags = SensorFlagBits::DATA_INJECTION | SensorFlagBits::ON_CHANGE_MODE }, @@ -248,11 +248,11 @@ const SensorInfo kAllSensors[] = { .maxRange = 360, .resolution = 1.0, .power = 3.0, - .minDelay = 10000, + .minDelay = 0, .fifoReservedEventCount = 0, .fifoMaxEventCount = 0, .requiredPermission = "", - .maxDelay = 500000, + .maxDelay = 0, .flags = SensorFlagBits::DATA_INJECTION | SensorFlagBits::ON_CHANGE_MODE | SensorFlagBits::WAKE_UP @@ -267,11 +267,11 @@ const SensorInfo kAllSensors[] = { .maxRange = 360, .resolution = 1.0, .power = 3.0, - .minDelay = 10000, + .minDelay = 0, .fifoReservedEventCount = 0, .fifoMaxEventCount = 0, .requiredPermission = "", - .maxDelay = 500000, + .maxDelay = 0, .flags = SensorFlagBits::DATA_INJECTION | SensorFlagBits::ON_CHANGE_MODE | SensorFlagBits::WAKE_UP @@ -286,11 +286,11 @@ const SensorInfo kAllSensors[] = { .maxRange = 360, .resolution = 1.0, .power = 3.0, - .minDelay = 10000, + .minDelay = 0, .fifoReservedEventCount = 0, .fifoMaxEventCount = 0, .requiredPermission = "", - .maxDelay = 500000, + .maxDelay = 0, .flags = SensorFlagBits::DATA_INJECTION | SensorFlagBits::ON_CHANGE_MODE | SensorFlagBits::WAKE_UP diff --git a/sepolicy/common/file_contexts b/sepolicy/common/file_contexts index 421952f4..f009b7cd 100644 --- a/sepolicy/common/file_contexts +++ b/sepolicy/common/file_contexts @@ -45,6 +45,7 @@ /vendor/bin/hw/android\.hardware\.power\.stats@1\.0-service\.mock u:object_r:hal_power_stats_default_exec:s0 /vendor/bin/hw/android\.hardware\.gnss@2\.0-service\.ranchu u:object_r:hal_gnss_default_exec:s0 /vendor/bin/hw/android\.hardware\.neuralnetworks@1\.3-service-sample-.* u:object_r:hal_neuralnetworks_sample_exec:s0 +/vendor/bin/hw/android\.hardware\.audio\.service.ranchu u:object_r:hal_audio_default_exec:s0 /vendor/lib(64)?/hw/vulkan\.ranchu\.so u:object_r:same_process_hal_file:s0 /vendor/lib(64)?/libEGL_emulation\.so u:object_r:same_process_hal_file:s0 @@ -18,6 +18,9 @@ # $(call inherit-product-if-exists, frameworks/native/build/phone-xhdpi-2048-dalvik-heap.mk) +# Enable Scoped Storage related +$(call inherit-product, $(SRC_TARGET_DIR)/product/emulated_storage.mk) + PRODUCT_SOONG_NAMESPACES += \ device/generic/goldfish \ device/generic/goldfish-opengl @@ -56,6 +59,7 @@ PRODUCT_PACKAGES += \ local_time.default \ SdkSetup \ EmulatorRadioConfig \ + EmulatorTetheringConfigOverlay \ libstagefrighthw \ libstagefright_goldfish_vpxdec \ libstagefright_goldfish_avcdec \ @@ -73,11 +77,6 @@ PRODUCT_PACKAGES += \ endif PRODUCT_PACKAGES += \ - audio.r_submix.default \ - android.hardware.audio.service \ - android.hardware.audio.effect@6.0-impl:32 - -PRODUCT_PACKAGES += \ android.hardware.bluetooth@1.1-service.sim \ android.hardware.bluetooth.audio@2.0-impl PRODUCT_PROPERTY_OVERRIDES += bt.rootcanal_test_console=off @@ -151,15 +150,20 @@ PRODUCT_PACKAGES += \ DEVICE_MANIFEST_FILE += device/generic/goldfish/manifest.camera.xml endif -ifneq ($(EMULATOR_VENDOR_NO_SOUND_TRIGGER),true) -PRODUCT_PACKAGES += android.hardware.soundtrigger@2.2-impl.ranchu -endif - ifneq ($(EMULATOR_VENDOR_NO_SOUND),true) -PRODUCT_PACKAGES += android.hardware.audio@6.0-impl.ranchu +PRODUCT_PACKAGES += \ + android.hardware.audio.service.ranchu \ + android.hardware.soundtrigger@2.2-impl.ranchu \ + android.hardware.audio.effect@6.0-impl \ + PRODUCT_COPY_FILES += \ device/generic/goldfish/audio/policy/audio_policy_configuration.xml:$(TARGET_COPY_OUT_VENDOR)/etc/audio_policy_configuration.xml \ - device/generic/goldfish/audio/policy/primary_audio_policy_configuration.xml:$(TARGET_COPY_OUT_VENDOR)/etc/primary_audio_policy_configuration.xml + device/generic/goldfish/audio/policy/primary_audio_policy_configuration.xml:$(TARGET_COPY_OUT_VENDOR)/etc/primary_audio_policy_configuration.xml \ + frameworks/av/services/audiopolicy/config/r_submix_audio_policy_configuration.xml:$(TARGET_COPY_OUT_VENDOR)/etc/r_submix_audio_policy_configuration.xml \ + frameworks/av/services/audiopolicy/config/audio_policy_volumes.xml:$(TARGET_COPY_OUT_VENDOR)/etc/audio_policy_volumes.xml \ + frameworks/av/services/audiopolicy/config/default_volume_tables.xml:$(TARGET_COPY_OUT_VENDOR)/etc/default_volume_tables.xml \ + frameworks/av/media/libeffects/data/audio_effects.xml:$(TARGET_COPY_OUT_VENDOR)/etc/audio_effects.xml \ + endif PRODUCT_PACKAGES += \ @@ -270,6 +274,7 @@ PRODUCT_COPY_FILES += \ frameworks/native/data/etc/android.hardware.bluetooth.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.bluetooth.xml \ system/bt/vendor_libs/test_vendor_lib/data/controller_properties.json:vendor/etc/bluetooth/controller_properties.json \ frameworks/native/data/etc/android.hardware.wifi.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.wifi.xml \ + frameworks/native/data/etc/android.hardware.wifi.passpoint.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.wifi.passpoint.xml \ frameworks/native/data/etc/android.hardware.wifi.direct.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.wifi.direct.xml \ device/generic/goldfish/data/etc/handheld_core_hardware.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/handheld_core_hardware.xml \ device/generic/goldfish/camera/media_profiles.xml:$(TARGET_COPY_OUT_VENDOR)/etc/media_profiles_V1_0.xml \ @@ -280,9 +285,11 @@ PRODUCT_COPY_FILES += \ device/generic/goldfish/camera/media_codecs_performance.xml:$(TARGET_COPY_OUT_VENDOR)/etc/media_codecs_performance.xml \ frameworks/native/data/etc/android.hardware.touchscreen.multitouch.jazzhand.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.touchscreen.multitouch.jazzhand.xml \ frameworks/native/data/etc/android.hardware.camera.ar.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.camera.ar.xml \ - frameworks/native/data/etc/android.hardware.camera.autofocus.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.camera.autofocus.xml \ + frameworks/native/data/etc/android.hardware.camera.flash-autofocus.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.camera.flash-autofocus.xml \ + frameworks/native/data/etc/android.hardware.camera.concurrent.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.camera.concurrent.xml \ frameworks/native/data/etc/android.hardware.camera.front.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.camera.front.xml \ frameworks/native/data/etc/android.hardware.camera.full.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.camera.full.xml \ + frameworks/native/data/etc/android.hardware.camera.raw.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.camera.raw.xml \ frameworks/native/data/etc/android.hardware.fingerprint.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.fingerprint.xml \ frameworks/native/data/etc/android.hardware.vulkan.level-1.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.vulkan.level.xml \ frameworks/native/data/etc/android.hardware.vulkan.compute-0.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.vulkan.compute.xml \ @@ -290,9 +297,6 @@ PRODUCT_COPY_FILES += \ device/generic/goldfish/data/etc/android.software.vulkan.deqp.level-2019-03-01.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.software.vulkan.deqp.level-2019-03-01.xml \ frameworks/native/data/etc/android.software.autofill.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.software.autofill.xml \ frameworks/native/data/etc/android.software.verified_boot.xml:${TARGET_COPY_OUT_PRODUCT}/etc/permissions/android.software.verified_boot.xml \ - frameworks/av/media/libeffects/data/audio_effects.xml:$(TARGET_COPY_OUT_VENDOR)/etc/audio_effects.xml \ - frameworks/av/services/audiopolicy/config/audio_policy_volumes.xml:$(TARGET_COPY_OUT_VENDOR)/etc/audio_policy_volumes.xml \ - frameworks/av/services/audiopolicy/config/default_volume_tables.xml:$(TARGET_COPY_OUT_VENDOR)/etc/default_volume_tables.xml \ device/generic/goldfish/data/etc/permissions/privapp-permissions-goldfish.xml:$(TARGET_COPY_OUT_PRODUCT)/etc/permissions/privapp-permissions-goldfish.xml \ hardware/google/camera/devices/EmulatedCamera/hwl/configs/emu_camera_back.json:$(TARGET_COPY_OUT_VENDOR)/etc/config/emu_camera_back.json \ hardware/google/camera/devices/EmulatedCamera/hwl/configs/emu_camera_front.json:$(TARGET_COPY_OUT_VENDOR)/etc/config/emu_camera_front.json \ diff --git a/wifi/wifi_hal/Android.bp b/wifi/wifi_hal/Android.bp index 88c1e30d..64310034 100644 --- a/wifi/wifi_hal/Android.bp +++ b/wifi/wifi_hal/Android.bp @@ -28,6 +28,7 @@ cc_library_static { "wifi_hal.cpp", ], shared_libs: [ + "libnl", "liblog", "libcutils", "libhardware_legacy", diff --git a/wifi/wifi_hal/interface.cpp b/wifi/wifi_hal/interface.cpp index 7c683e52..47d81543 100644 --- a/wifi/wifi_hal/interface.cpp +++ b/wifi/wifi_hal/interface.cpp @@ -86,6 +86,9 @@ wifi_error Interface::getName(char* name, size_t size) { return WIFI_SUCCESS; } +// Wifi legacy HAL implicitly assumes getLinkStats is blocking and +// handler will be set to nullptr immediately after invocation. +// Therefore, this function will wait until onLinkStatsReply is called. wifi_error Interface::getLinkStats(wifi_request_id requestId, wifi_stats_result_handler handler) { NetlinkMessage message(RTM_GETLINK, mNetlink.getSequenceNumber()); @@ -97,12 +100,21 @@ wifi_error Interface::getLinkStats(wifi_request_id requestId, info->ifi_flags = 0; info->ifi_change = 0xFFFFFFFF; - bool success = mNetlink.sendMessage(message, - std::bind(&Interface::onLinkStatsReply, - this, - requestId, - handler, - std::placeholders::_1)); + std::condition_variable condition; + std::mutex mutex; + std::unique_lock<std::mutex> lock(mutex); + bool stopped = false; + auto callback = [this, requestId, &handler, + &mutex, &condition, &stopped] (const NetlinkMessage& message) { + stopped = true; + std::unique_lock<std::mutex> lock(mutex); + onLinkStatsReply(requestId, handler, message); + condition.notify_all(); + }; + bool success = mNetlink.sendMessage(message, callback); + while (!stopped) { + condition.wait(lock); + } return success ? WIFI_SUCCESS : WIFI_ERROR_UNKNOWN; } diff --git a/wifi/wifi_hal/netlinkmessage.cpp b/wifi/wifi_hal/netlinkmessage.cpp index baf5800d..06bb7438 100644 --- a/wifi/wifi_hal/netlinkmessage.cpp +++ b/wifi/wifi_hal/netlinkmessage.cpp @@ -22,6 +22,7 @@ #include <linux/rtnetlink.h> #include <sys/types.h> #include <unistd.h> +#include <netlink/msg.h> size_t getSpaceForMessageType(uint16_t type) { switch (type) { @@ -51,13 +52,12 @@ NetlinkMessage::NetlinkMessage(const char* data, size_t size) bool NetlinkMessage::getAttribute(int attributeId, void* data, size_t size) const { const void* value = nullptr; - uint16_t attrSize = 0; - if (!findAttribute(attributeId, &value, &attrSize)) { - return false; - } - if (size > attrSize) { + const auto attr = nlmsg_find_attr((struct nlmsghdr*)mData.data(), sizeof(ifinfomsg), attributeId); + if (!attr) { return false; } + value = (const uint8_t*) attr + NLA_HDRLEN; + size = attr->nla_len; memcpy(data, value, size); return true; } @@ -71,30 +71,3 @@ uint32_t NetlinkMessage::sequence() const { auto header = reinterpret_cast<const nlmsghdr*>(mData.data()); return header->nlmsg_seq; } - -bool NetlinkMessage::findAttribute(int attributeId, - const void** value, - uint16_t* size) const { - const uint8_t* end = mData.data() + mData.size(); - size_t attrOffset = getSpaceForMessageType(type()); - if (attrOffset == 0) { - return false; - } - const uint8_t* attribute = mData.data() + attrOffset; - while (attribute < end) { - auto header = reinterpret_cast<const nlattr*>(attribute); - if (header->nla_len == 0) { - // The length should include the header so the length should always - // be greater than zero. If it doesn't we're going to end up looping - // forever so ignore this. - return false; - } - if (header->nla_type == attributeId) { - *value = attribute + NLA_HDRLEN; - *size = header->nla_len; - return true; - } - attribute += header->nla_len; - } - return false; -} diff --git a/wifi/wifi_hal/netlinkmessage.h b/wifi/wifi_hal/netlinkmessage.h index 45fd7cdb..5e1a3b80 100644 --- a/wifi/wifi_hal/netlinkmessage.h +++ b/wifi/wifi_hal/netlinkmessage.h @@ -60,9 +60,6 @@ private: NetlinkMessage& operator=(const NetlinkMessage&) = delete; bool getAttribute(int attributeId, void* data, size_t size) const; - bool findAttribute(int attributeId, - const void** value, - uint16_t* size) const; std::vector<uint8_t> mData; }; |