diff options
author | yucliu <yucliu@google.com> | 2022-02-15 21:06:30 -0800 |
---|---|---|
committer | Yuchen Liu <yucliu@google.com> | 2022-03-14 23:24:05 +0000 |
commit | e448052c6bde4dbacba0fe2df045ed56cf2a73fd (patch) | |
tree | 07efb1102de85af474a149e9a22af231a5444cd9 /audio_proxy | |
parent | 075557a388a9e246783232d8d6d9d77c4460e361 (diff) | |
download | atv-e448052c6bde4dbacba0fe2df045ed56cf2a73fd.tar.gz |
[AudioProxy] Different stream use different latency/buffer size
Change the command line argument so that different stream now can have
different latency and buffer sizes.
Bug: 177944032
Test: Unit test. On device test.
Change-Id: I006154420c5c607d85ac637fb0e741c665dda513
(cherry picked from commit 9ae96df5f5c64a8826d6bf3e5788f9c8d05b6014)
Diffstat (limited to 'audio_proxy')
-rw-r--r-- | audio_proxy/service/Android.bp | 8 | ||||
-rw-r--r-- | audio_proxy/service/DeviceImpl.cpp | 25 | ||||
-rw-r--r-- | audio_proxy/service/DeviceImpl.h | 7 | ||||
-rw-r--r-- | audio_proxy/service/DevicesFactoryImpl.cpp | 8 | ||||
-rw-r--r-- | audio_proxy/service/DevicesFactoryImpl.h | 2 | ||||
-rw-r--r-- | audio_proxy/service/ServiceConfig.cpp | 94 | ||||
-rw-r--r-- | audio_proxy/service/ServiceConfig.h | 21 | ||||
-rw-r--r-- | audio_proxy/service/ServiceConfigTest.cpp | 61 | ||||
-rw-r--r-- | audio_proxy/service/device.google.atv.audio_proxy@5.1-service.rc | 5 | ||||
-rw-r--r-- | audio_proxy/service/device.google.atv.audio_proxy@6.0-service.rc | 5 | ||||
-rw-r--r-- | audio_proxy/service/device.google.atv.audio_proxy@7.0-service.rc | 5 | ||||
-rw-r--r-- | audio_proxy/service/device.google.atv.audio_proxy@7.1-service.rc | 5 | ||||
-rw-r--r-- | audio_proxy/service/main.cpp | 47 |
13 files changed, 221 insertions, 72 deletions
diff --git a/audio_proxy/service/Android.bp b/audio_proxy/service/Android.bp index 2c219c6..711add8 100644 --- a/audio_proxy/service/Android.bp +++ b/audio_proxy/service/Android.bp @@ -27,6 +27,7 @@ cc_library_static { host_supported: true, srcs: [ "RingBufferUtil.cpp", + "ServiceConfig.cpp", ], shared_libs: [ "libbase", @@ -180,9 +181,16 @@ cc_test { srcs: [ "RingBufferUtilTest.cpp", + "ServiceConfigTest.cpp", ], static_libs: [ "audio_proxy_service_util", + "libbase", "libgtest", ], + + cflags: [ + // Suppress the warning to make ServiceConfigTest easier. + "-Wno-writable-strings", + ], } diff --git a/audio_proxy/service/DeviceImpl.cpp b/audio_proxy/service/DeviceImpl.cpp index 4684dec..75d411a 100644 --- a/audio_proxy/service/DeviceImpl.cpp +++ b/audio_proxy/service/DeviceImpl.cpp @@ -23,6 +23,7 @@ #include "AidlTypes.h" #include "BusOutputStream.h" #include "BusStreamProvider.h" +#include "ServiceConfig.h" #include "StreamOutImpl.h" using namespace ::android::hardware::audio::common::CPP_VERSION; @@ -70,10 +71,8 @@ AidlAudioConfig toAidlAudioConfig(const AudioConfig& hidl_config) { } // namespace DeviceImpl::DeviceImpl(BusStreamProvider& busStreamProvider, - uint32_t bufferSizeMs, uint32_t latencyMs) - : mBusStreamProvider(busStreamProvider), - mBufferSizeMs(bufferSizeMs), - mLatencyMs(latencyMs) {} + const ServiceConfig& serviceConfig) + : mBusStreamProvider(busStreamProvider), mServiceConfig(serviceConfig) {} // Methods from ::android::hardware::audio::V5_0::IDevice follow. Return<Result> DeviceImpl::initCheck() { return Result::OK; } @@ -124,6 +123,12 @@ Return<void> DeviceImpl::openOutputStreamImpl( return Void(); } + const auto configIt = mServiceConfig.streams.find(device.address.id()); + if (configIt == mServiceConfig.streams.end()) { + _hidl_cb(Result::INVALID_ARGUMENTS, nullptr, {}); + return Void(); + } + std::optional<AidlAudioConfig> aidlConfig = toAidlAudioConfig(config.base); if (!aidlConfig) { DCHECK(false); @@ -148,7 +153,8 @@ Return<void> DeviceImpl::openOutputStreamImpl( static_cast<int32_t>(outputFlags)); DCHECK(busOutputStream); auto streamOut = sp<StreamOutImpl>::make(std::move(busOutputStream), - mBufferSizeMs, mLatencyMs); + configIt->second.bufferSizeMs, + configIt->second.latencyMs); mBusStreamProvider.onStreamOutCreated(streamOut); _hidl_cb(Result::OK, streamOut, config); return Void(); @@ -180,13 +186,20 @@ Return<void> DeviceImpl::openOutputStream(int32_t ioHandle, hidl_bitfield<AudioOutputFlag> flags, const SourceMetadata& sourceMetadata, openOutputStream_cb _hidl_cb) { + const auto configIt = mServiceConfig.streams.find(device.busAddress); + if (configIt == mServiceConfig.streams.end()) { + _hidl_cb(Result::INVALID_ARGUMENTS, nullptr, {}); + return Void(); + } + std::shared_ptr<BusOutputStream> busOutputStream = mBusStreamProvider.openOutputStream(device.busAddress, toAidlAudioConfig(config), static_cast<int32_t>(flags)); DCHECK(busOutputStream); auto streamOut = sp<StreamOutImpl>::make(std::move(busOutputStream), - mBufferSizeMs, mLatencyMs); + configIt->second.bufferSizeMs, + configIt->second.latencyMs); mBusStreamProvider.onStreamOutCreated(streamOut); _hidl_cb(Result::OK, streamOut, config); return Void(); diff --git a/audio_proxy/service/DeviceImpl.h b/audio_proxy/service/DeviceImpl.h index 44ad3b0..ffe3f88 100644 --- a/audio_proxy/service/DeviceImpl.h +++ b/audio_proxy/service/DeviceImpl.h @@ -54,6 +54,7 @@ using ::android::hardware::audio::common::CPP_VERSION::AudioOutputFlag; #endif class BusStreamProvider; +struct ServiceConfig; #if MAJOR_VERSION == 7 && MINOR_VERSION == 1 class DeviceImpl : public android::hardware::audio::V7_1::IDevice { @@ -61,8 +62,7 @@ class DeviceImpl : public android::hardware::audio::V7_1::IDevice { class DeviceImpl : public IDevice { #endif public: - DeviceImpl(BusStreamProvider& busStreamProvider, uint32_t bufferSizeMs, - uint32_t latencyMs); + DeviceImpl(BusStreamProvider& busStreamProvider, const ServiceConfig& config); // Methods from ::android::hardware::audio::V5_0::IDevice follow. Return<Result> initCheck() override; @@ -154,8 +154,7 @@ class DeviceImpl : public IDevice { #endif BusStreamProvider& mBusStreamProvider; - const uint32_t mBufferSizeMs; - const uint32_t mLatencyMs; + const ServiceConfig& mServiceConfig; std::set<AudioPatchHandle> mAudioPatchHandles; }; diff --git a/audio_proxy/service/DevicesFactoryImpl.cpp b/audio_proxy/service/DevicesFactoryImpl.cpp index a93ad4c..c5575a5 100644 --- a/audio_proxy/service/DevicesFactoryImpl.cpp +++ b/audio_proxy/service/DevicesFactoryImpl.cpp @@ -31,9 +31,7 @@ Return<void> DevicesFactoryImpl::openDevice(const hidl_string& device, openDevice_cb _hidl_cb) { if (device == mConfig.name) { LOG(INFO) << "Audio Device was opened: " << device; - _hidl_cb(Result::OK, - new DeviceImpl(mBusStreamProvider, mConfig.bufferSizeMs, - mConfig.latencyMs)); + _hidl_cb(Result::OK, new DeviceImpl(mBusStreamProvider, mConfig)); } else { _hidl_cb(Result::INVALID_ARGUMENTS, nullptr); } @@ -53,9 +51,7 @@ Return<void> DevicesFactoryImpl::openDevice_7_1(const hidl_string& device, openDevice_7_1_cb _hidl_cb) { if (device == mConfig.name) { LOG(INFO) << "Audio Device was opened: " << device; - _hidl_cb(Result::OK, - new DeviceImpl(mBusStreamProvider, mConfig.bufferSizeMs, - mConfig.latencyMs)); + _hidl_cb(Result::OK, new DeviceImpl(mBusStreamProvider, mConfig)); } else { _hidl_cb(Result::INVALID_ARGUMENTS, nullptr); } diff --git a/audio_proxy/service/DevicesFactoryImpl.h b/audio_proxy/service/DevicesFactoryImpl.h index 560692e..d9326eb 100644 --- a/audio_proxy/service/DevicesFactoryImpl.h +++ b/audio_proxy/service/DevicesFactoryImpl.h @@ -53,7 +53,7 @@ class DevicesFactoryImpl : public IDevicesFactory { private: BusStreamProvider& mBusStreamProvider; - const ServiceConfig mConfig; + const ServiceConfig& mConfig; }; } // namespace service diff --git a/audio_proxy/service/ServiceConfig.cpp b/audio_proxy/service/ServiceConfig.cpp new file mode 100644 index 0000000..61f40aa --- /dev/null +++ b/audio_proxy/service/ServiceConfig.cpp @@ -0,0 +1,94 @@ +// Copyright (C) 2022 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 "ServiceConfig.h" + +#include <android-base/parseint.h> +#include <android-base/strings.h> +#include <getopt.h> + +#include <utility> +#include <vector> + +namespace audio_proxy::service { +namespace { +std::pair<std::string, StreamConfig> parseStreamConfig(const char* optarg) { + std::vector<std::string> tokens = android::base::Split(optarg, ":"); + if (tokens.size() != 3) { + return {}; + } + + StreamConfig config; + if (!android::base::ParseUint(tokens[1].c_str(), &config.bufferSizeMs)) { + return {}; + } + + if (!android::base::ParseUint(tokens[2].c_str(), &config.latencyMs)) { + return {}; + } + + return {tokens[0], config}; +} +} // namespace + +std::optional<ServiceConfig> parseServiceConfigFromCommandLine(int argc, + char** argv) { + // $command --name service_name + // --stream address1:buffer_size:latency + // --stream address2:buffer_size:latency + static option options[] = { + {"name", required_argument, nullptr, 'n'}, + {"stream", required_argument, nullptr, 's'}, + {nullptr, 0, nullptr, 0}, + }; + + // Reset, this is useful in unittest. + optind = 0; + + ServiceConfig config; + int val = 0; + while ((val = getopt_long(argc, argv, "n:s:", options, nullptr)) != -1) { + switch (val) { + case 'n': + config.name = optarg; + break; + + case 's': { + std::pair<std::string, StreamConfig> streamConfig = + parseStreamConfig(optarg); + if (streamConfig.first.empty()) { + return std::nullopt; + } + + auto it = config.streams.emplace(std::move(streamConfig)); + if (!it.second) { + return std::nullopt; + } + + break; + } + + default: + break; + } + } + + if (config.name.empty() || config.streams.empty()) { + return std::nullopt; + } + + return config; +} + +} // namespace audio_proxy::service
\ No newline at end of file diff --git a/audio_proxy/service/ServiceConfig.h b/audio_proxy/service/ServiceConfig.h index 837b47c..f3de742 100644 --- a/audio_proxy/service/ServiceConfig.h +++ b/audio_proxy/service/ServiceConfig.h @@ -16,21 +16,32 @@ #include <stdint.h> +#include <map> +#include <optional> #include <string> namespace audio_proxy::service { +struct StreamConfig { + // Buffer size in milliseconds, as defined by IStream::getBufferSize. + uint32_t bufferSizeMs; + + // Latency in milliseconds, as defined by IStreamOut::getLatency. + uint32_t latencyMs; +}; + // Global configurations for the audio HAL service and AudioProxy service. struct ServiceConfig { // Name of the service. It will be used to identify the audio HAL service and // AudioProxy service. std::string name; - // Buffer size in milliseconds, as defined by IStream::getBufferSize. - uint32_t bufferSizeMs = 0; - - // Latency in milliseconds, as defined by IStreamOut::getLatency. - uint32_t latencyMs = 0; + // Supported stream configs. Key is the address of the stream. Value is the + // config. + std::map<std::string, StreamConfig> streams; }; +std::optional<ServiceConfig> parseServiceConfigFromCommandLine(int argc, + char** argv); + } // namespace audio_proxy::service
\ No newline at end of file diff --git a/audio_proxy/service/ServiceConfigTest.cpp b/audio_proxy/service/ServiceConfigTest.cpp new file mode 100644 index 0000000..e796464 --- /dev/null +++ b/audio_proxy/service/ServiceConfigTest.cpp @@ -0,0 +1,61 @@ +// Copyright (C) 2022 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 <gtest/gtest.h> + +#include "ServiceConfig.h" + +using namespace audio_proxy::service; + +TEST(ServiceConfigTest, GoodConfig) { + char* argv[] = {"command", "--name", "service", "--stream", "A:1:2"}; + auto config = + parseServiceConfigFromCommandLine(sizeof(argv) / sizeof(argv[0]), argv); + + ASSERT_TRUE(config); + EXPECT_EQ(config->name, "service"); + EXPECT_EQ(config->streams.size(), 1); + EXPECT_EQ(config->streams.begin()->first, "A"); + EXPECT_EQ(config->streams.begin()->second.bufferSizeMs, 1u); + EXPECT_EQ(config->streams.begin()->second.latencyMs, 2u); +} + +TEST(ServiceConfigTest, MultipleStreams) { + char* argv[] = {"command", "--name", "service", "--stream", + "A:1:2", "--stream", "B:3:4"}; + auto config = + parseServiceConfigFromCommandLine(sizeof(argv) / sizeof(argv[0]), argv); + + ASSERT_TRUE(config); + EXPECT_EQ(config->name, "service"); + EXPECT_EQ(config->streams.size(), 2); + + ASSERT_TRUE(config->streams.count("A")); + const auto& streamA = config->streams["A"]; + EXPECT_EQ(streamA.bufferSizeMs, 1u); + EXPECT_EQ(streamA.latencyMs, 2u); + + ASSERT_TRUE(config->streams.count("B")); + const auto& streamB = config->streams["B"]; + EXPECT_EQ(streamB.bufferSizeMs, 3u); + EXPECT_EQ(streamB.latencyMs, 4u); +} + +TEST(ServiceConfigTest, NoStreamConfig) { + char* argv[] = {"command", "--name", "service"}; + auto config = + parseServiceConfigFromCommandLine(sizeof(argv) / sizeof(argv[0]), argv); + + EXPECT_FALSE(config); +} diff --git a/audio_proxy/service/device.google.atv.audio_proxy@5.1-service.rc b/audio_proxy/service/device.google.atv.audio_proxy@5.1-service.rc index f639d21..5ce6140 100644 --- a/audio_proxy/service/device.google.atv.audio_proxy@5.1-service.rc +++ b/audio_proxy/service/device.google.atv.audio_proxy@5.1-service.rc @@ -1,4 +1,7 @@ -service audio_proxy_service /vendor/bin/hw/device.google.atv.audio_proxy@5.1-service --service_name mediashell --buffer_size_ms 40 --latency_ms 40 +service audio_proxy_service /vendor/bin/hw/device.google.atv.audio_proxy@5.1-service \ + --name mediashell \ + --stream MEDIASHELL_AUDIO_DEVICE_ADDR:40:200 \ + --stream MEDIASHELL_MIXER_DEVICE_ADDR:40:40 class hal user system group system diff --git a/audio_proxy/service/device.google.atv.audio_proxy@6.0-service.rc b/audio_proxy/service/device.google.atv.audio_proxy@6.0-service.rc index fc39baf..e0a9371 100644 --- a/audio_proxy/service/device.google.atv.audio_proxy@6.0-service.rc +++ b/audio_proxy/service/device.google.atv.audio_proxy@6.0-service.rc @@ -1,4 +1,7 @@ -service audio_proxy_service /vendor/bin/hw/device.google.atv.audio_proxy@6.0-service --service_name mediashell --buffer_size_ms 40 --latency_ms 40 +service audio_proxy_service /vendor/bin/hw/device.google.atv.audio_proxy@6.0-service \ + --name mediashell \ + --stream MEDIASHELL_AUDIO_DEVICE_ADDR:40:200 \ + --stream MEDIASHELL_MIXER_DEVICE_ADDR:40:40 class hal user system group system diff --git a/audio_proxy/service/device.google.atv.audio_proxy@7.0-service.rc b/audio_proxy/service/device.google.atv.audio_proxy@7.0-service.rc index 0335031..d8d2298 100644 --- a/audio_proxy/service/device.google.atv.audio_proxy@7.0-service.rc +++ b/audio_proxy/service/device.google.atv.audio_proxy@7.0-service.rc @@ -1,4 +1,7 @@ -service audio_proxy_service /vendor/bin/hw/device.google.atv.audio_proxy@7.0-service --service_name mediashell --buffer_size_ms 40 --latency_ms 40 +service audio_proxy_service /vendor/bin/hw/device.google.atv.audio_proxy@7.0-service \ + --name mediashell \ + --stream MEDIASHELL_AUDIO_DEVICE_ADDR:40:200 \ + --stream MEDIASHELL_MIXER_DEVICE_ADDR:40:40 class hal user system group system diff --git a/audio_proxy/service/device.google.atv.audio_proxy@7.1-service.rc b/audio_proxy/service/device.google.atv.audio_proxy@7.1-service.rc index 77051e6..6490f71 100644 --- a/audio_proxy/service/device.google.atv.audio_proxy@7.1-service.rc +++ b/audio_proxy/service/device.google.atv.audio_proxy@7.1-service.rc @@ -1,4 +1,7 @@ -service audio_proxy_service /vendor/bin/hw/device.google.atv.audio_proxy@7.1-service --service_name mediashell --buffer_size_ms 40 --latency_ms 40 +service audio_proxy_service /vendor/bin/hw/device.google.atv.audio_proxy@7.1-service \ + --name mediashell \ + --stream MEDIASHELL_AUDIO_DEVICE_ADDR:40:200 \ + --stream MEDIASHELL_MIXER_DEVICE_ADDR:40:40 class hal user system group system diff --git a/audio_proxy/service/main.cpp b/audio_proxy/service/main.cpp index 4e4eced..9c16a90 100644 --- a/audio_proxy/service/main.cpp +++ b/audio_proxy/service/main.cpp @@ -13,10 +13,8 @@ // limitations under the License. #include <android-base/logging.h> -#include <android-base/parseint.h> #include <android/binder_manager.h> #include <android/binder_process.h> -#include <getopt.h> #include <hidl/HidlTransportSupport.h> #include <optional> @@ -24,56 +22,13 @@ #include "AudioProxyError.h" #include "AudioProxyImpl.h" #include "DevicesFactoryImpl.h" +#include "ServiceConfig.h" using android::sp; using android::status_t; using namespace audio_proxy::service; -namespace { - -std::optional<ServiceConfig> parseServiceConfigFromCommandLine(int argc, - char** argv) { - ServiceConfig config; - static option options[] = { - {"service_name", required_argument, nullptr, 's'}, - {"buffer_size_ms", required_argument, nullptr, 'b'}, - {"latency_ms", required_argument, nullptr, 'l'}, - {nullptr, 0, nullptr, 0}, - }; - - int val = 0; - while ((val = getopt_long(argc, argv, "s:b:l:", options, nullptr)) != -1) { - switch (val) { - case 's': - config.name = optarg; - break; - case 'b': - if (!android::base::ParseUint(optarg, &config.bufferSizeMs)) { - return std::nullopt; - } - break; - case 'l': - if (!android::base::ParseUint(optarg, &config.latencyMs)) { - return std::nullopt; - } - break; - - default: - break; - } - } - - if (config.name.empty() || config.bufferSizeMs == 0 || - config.latencyMs == 0) { - return std::nullopt; - } - - return config; -} - -} // namespace - int main(int argc, char** argv) { auto config = parseServiceConfigFromCommandLine(argc, argv); if (!config) { |