diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2020-07-21 23:18:36 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2020-07-21 23:18:36 +0000 |
commit | 023eecfd282996acf5e80d301e7f774099f4bd19 (patch) | |
tree | 83a24dbe99f2c56b0df8df7e5e33644782488edd | |
parent | 60b8eb03a8a3f1581e07469704406def013ea5ca (diff) | |
parent | dd91871ac120b17874af7a24b1e7e7d825c48175 (diff) | |
download | device_generic_goldfish-023eecfd282996acf5e80d301e7f774099f4bd19.tar.gz device_generic_goldfish-023eecfd282996acf5e80d301e7f774099f4bd19.tar.bz2 device_generic_goldfish-023eecfd282996acf5e80d301e7f774099f4bd19.zip |
Snap for 6698269 from dd91871ac120b17874af7a24b1e7e7d825c48175 to mainline-releaseandroid-mainline-11.0.0_r2
Change-Id: I56c0fa8d7deb11dc15eb3918a3df7f599b29cbe5
33 files changed, 1031 insertions, 363 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/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/init.ranchu.rc b/init.ranchu.rc index 9be9885b..d2e5bded 100644 --- a/init.ranchu.rc +++ b/init.ranchu.rc @@ -62,7 +62,8 @@ on boot setprop ro.opengles.version ${ro.kernel.qemu.opengles.version} setprop ro.zygote.disable_gl_preload 1 - setprop debug.stagefright.ccodec 0 + # 0: omx; 4: c2 default now + setprop debug.stagefright.ccodec 4 setprop debug.stagefright.ccodec ${ro.kernel.qemu.media.ccodec} setprop dalvik.vm.heapsize 192m 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 @@ -73,11 +76,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 +149,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 += \ @@ -290,9 +293,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 \ |