Loading audio/aidl/default/Android.bp +5 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ cc_defaults { "libbinder_ndk", "libcutils", "libfmq", "libnbaio_mono", "libstagefright_foundation", "libtinyalsav2", "libutils", Loading Loading @@ -76,6 +77,10 @@ cc_library { "Stream.cpp", "StreamStub.cpp", "Telephony.cpp", "r_submix/ModuleRemoteSubmix.cpp", "r_submix/RemoteSubmixUtils.cpp", "r_submix/SubmixRoute.cpp", "r_submix/StreamRemoteSubmix.cpp", "usb/ModuleUsb.cpp", "usb/StreamUsb.cpp", "usb/UsbAlsaMixerControl.cpp", Loading audio/aidl/default/Module.cpp +16 −3 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ #include "core-impl/Bluetooth.h" #include "core-impl/Module.h" #include "core-impl/ModuleRemoteSubmix.h" #include "core-impl/ModuleUsb.h" #include "core-impl/SoundDose.h" #include "core-impl/StreamStub.h" Loading Loading @@ -111,8 +112,9 @@ std::shared_ptr<Module> Module::createInstance(Type type) { switch (type) { case Module::Type::USB: return ndk::SharedRefBase::make<ModuleUsb>(type); case Type::DEFAULT: case Type::R_SUBMIX: return ndk::SharedRefBase::make<ModuleRemoteSubmix>(type); case Type::DEFAULT: default: return ndk::SharedRefBase::make<Module>(type); } Loading Loading @@ -181,8 +183,8 @@ ndk::ScopedAStatus Module::createStreamContext( StreamContext temp( std::make_unique<StreamContext::CommandMQ>(1, true /*configureEventFlagWord*/), std::make_unique<StreamContext::ReplyMQ>(1, true /*configureEventFlagWord*/), portConfigIt->format.value(), portConfigIt->channelMask.value(), portConfigIt->sampleRate.value().value, flags, portConfigIt->portId, portConfigIt->format.value(), portConfigIt->channelMask.value(), portConfigIt->sampleRate.value().value, flags, portConfigIt->ext.get<AudioPortExt::mix>().handle, std::make_unique<StreamContext::DataMQ>(frameSize * in_bufferSizeFrames), asyncCallback, outEventCallback, params); Loading Loading @@ -490,6 +492,17 @@ ndk::ScopedAStatus Module::connectExternalDevice(const AudioPort& in_templateIdA return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); } for (auto profile : connectedPort.profiles) { if (profile.channelMasks.empty()) { LOG(ERROR) << __func__ << ": the profile " << profile.name << " has no channel masks"; return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); } if (profile.sampleRates.empty()) { LOG(ERROR) << __func__ << ": the profile " << profile.name << " has no sample rates"; return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); } } connectedPort.id = ++getConfig().nextPortId; auto [connectedPortsIt, _] = mConnectedDevicePorts.insert(std::pair(connectedPort.id, std::vector<int32_t>())); Loading audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h 0 → 100644 +59 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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 "core-impl/Module.h" namespace aidl::android::hardware::audio::core { class ModuleRemoteSubmix : public Module { public: explicit ModuleRemoteSubmix(Module::Type type) : Module(type) {} private: // IModule interfaces ndk::ScopedAStatus getTelephony(std::shared_ptr<ITelephony>* _aidl_return) override; ndk::ScopedAStatus getBluetooth(std::shared_ptr<IBluetooth>* _aidl_return) override; ndk::ScopedAStatus getMicMute(bool* _aidl_return) override; ndk::ScopedAStatus setMicMute(bool in_mute) override; // Module interfaces ndk::ScopedAStatus createInputStream( const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, StreamContext&& context, const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones, std::shared_ptr<StreamIn>* result) override; ndk::ScopedAStatus createOutputStream( const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, StreamContext&& context, const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>& offloadInfo, std::shared_ptr<StreamOut>* result) override; ndk::ScopedAStatus populateConnectedDevicePort( ::aidl::android::media::audio::common::AudioPort* audioPort) override; ndk::ScopedAStatus checkAudioPatchEndpointsMatch( const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sources, const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sinks) override; void onExternalDeviceConnectionChanged( const ::aidl::android::media::audio::common::AudioPort& audioPort, bool connected) override; ndk::ScopedAStatus onMasterMuteChanged(bool mute) override; ndk::ScopedAStatus onMasterVolumeChanged(float volume) override; }; } // namespace aidl::android::hardware::audio::core audio/aidl/default/include/core-impl/Stream.h +6 −0 Original line number Diff line number Diff line Loading @@ -78,6 +78,7 @@ class StreamContext { StreamContext() = default; StreamContext(std::unique_ptr<CommandMQ> commandMQ, std::unique_ptr<ReplyMQ> replyMQ, int portId, const ::aidl::android::media::audio::common::AudioFormatDescription& format, const ::aidl::android::media::audio::common::AudioChannelLayout& channelLayout, int sampleRate, const ::aidl::android::media::audio::common::AudioIoFlags& flags, Loading @@ -88,6 +89,7 @@ class StreamContext { : mCommandMQ(std::move(commandMQ)), mInternalCommandCookie(std::rand()), mReplyMQ(std::move(replyMQ)), mPortId(portId), mFormat(format), mChannelLayout(channelLayout), mSampleRate(sampleRate), Loading @@ -101,6 +103,7 @@ class StreamContext { : mCommandMQ(std::move(other.mCommandMQ)), mInternalCommandCookie(other.mInternalCommandCookie), mReplyMQ(std::move(other.mReplyMQ)), mPortId(other.mPortId), mFormat(other.mFormat), mChannelLayout(other.mChannelLayout), mSampleRate(other.mSampleRate), Loading @@ -114,6 +117,7 @@ class StreamContext { mCommandMQ = std::move(other.mCommandMQ); mInternalCommandCookie = other.mInternalCommandCookie; mReplyMQ = std::move(other.mReplyMQ); mPortId = std::move(other.mPortId); mFormat = std::move(other.mFormat); mChannelLayout = std::move(other.mChannelLayout); mSampleRate = other.mSampleRate; Loading Loading @@ -145,6 +149,7 @@ class StreamContext { std::shared_ptr<IStreamOutEventCallback> getOutEventCallback() const { return mOutEventCallback; } int getPortId() const { return mPortId; } ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); } int getTransientStateDelayMs() const { return mDebugParameters.transientStateDelayMs; } int getSampleRate() const { return mSampleRate; } Loading @@ -155,6 +160,7 @@ class StreamContext { std::unique_ptr<CommandMQ> mCommandMQ; int mInternalCommandCookie; // The value used to confirm that the command was posted internally std::unique_ptr<ReplyMQ> mReplyMQ; int mPortId; ::aidl::android::media::audio::common::AudioFormatDescription mFormat; ::aidl::android::media::audio::common::AudioChannelLayout mChannelLayout; int mSampleRate; Loading audio/aidl/default/include/core-impl/StreamRemoteSubmix.h 0 → 100644 +98 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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 <mutex> #include <vector> #include "core-impl/Stream.h" #include "r_submix/SubmixRoute.h" namespace aidl::android::hardware::audio::core { using aidl::android::hardware::audio::core::r_submix::AudioConfig; using aidl::android::hardware::audio::core::r_submix::SubmixRoute; class StreamRemoteSubmix : public StreamCommonImpl { public: StreamRemoteSubmix(const Metadata& metadata, StreamContext&& context); ::android::status_t init() override; ::android::status_t drain(StreamDescriptor::DrainMode) override; ::android::status_t flush() override; ::android::status_t pause() override; ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, int32_t* latencyMs) override; ::android::status_t standby() override; void shutdown() override; // Overridden methods of 'StreamCommonImpl', called on a Binder thread. ndk::ScopedAStatus prepareToClose() override; private: size_t getPipeSizeInFrames(); size_t getStreamPipeSizeInFrames(); ::android::status_t outWrite(void* buffer, size_t frameCount, size_t* actualFrameCount); ::android::status_t inRead(void* buffer, size_t frameCount, size_t* actualFrameCount); const int mPortId; const bool mIsInput; AudioConfig mStreamConfig; std::shared_ptr<SubmixRoute> mCurrentRoute = nullptr; ::android::status_t mStatus = ::android::NO_INIT; // Mutex lock to protect vector of submix routes, each of these submix routes have their mutex // locks and none of the mutex locks should be taken together. static std::mutex sSubmixRoutesLock; static std::map<int32_t, std::shared_ptr<SubmixRoute>> sSubmixRoutes GUARDED_BY(sSubmixRoutesLock); // limit for number of read error log entries to avoid spamming the logs static constexpr int kMaxReadErrorLogs = 5; // The duration of kMaxReadFailureAttempts * READ_ATTEMPT_SLEEP_MS must be strictly inferior // to the duration of a record buffer at the current record sample rate (of the device, not of // the recording itself). Here we have: 3 * 5ms = 15ms < 1024 frames * 1000 / 48000 = 21.333ms static constexpr int kMaxReadFailureAttempts = 3; // 5ms between two read attempts when pipe is empty static constexpr int kReadAttemptSleepUs = 5000; }; class StreamInRemoteSubmix final : public StreamRemoteSubmix, public StreamIn { public: friend class ndk::SharedRefBase; StreamInRemoteSubmix( const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, StreamContext&& context, const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones); private: ndk::ScopedAStatus getActiveMicrophones( std::vector<::aidl::android::media::audio::common::MicrophoneDynamicInfo>* _aidl_return) override; }; class StreamOutRemoteSubmix final : public StreamRemoteSubmix, public StreamOut { public: friend class ndk::SharedRefBase; StreamOutRemoteSubmix( const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, StreamContext&& context, const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>& offloadInfo); }; } // namespace aidl::android::hardware::audio::core Loading
audio/aidl/default/Android.bp +5 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ cc_defaults { "libbinder_ndk", "libcutils", "libfmq", "libnbaio_mono", "libstagefright_foundation", "libtinyalsav2", "libutils", Loading Loading @@ -76,6 +77,10 @@ cc_library { "Stream.cpp", "StreamStub.cpp", "Telephony.cpp", "r_submix/ModuleRemoteSubmix.cpp", "r_submix/RemoteSubmixUtils.cpp", "r_submix/SubmixRoute.cpp", "r_submix/StreamRemoteSubmix.cpp", "usb/ModuleUsb.cpp", "usb/StreamUsb.cpp", "usb/UsbAlsaMixerControl.cpp", Loading
audio/aidl/default/Module.cpp +16 −3 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ #include "core-impl/Bluetooth.h" #include "core-impl/Module.h" #include "core-impl/ModuleRemoteSubmix.h" #include "core-impl/ModuleUsb.h" #include "core-impl/SoundDose.h" #include "core-impl/StreamStub.h" Loading Loading @@ -111,8 +112,9 @@ std::shared_ptr<Module> Module::createInstance(Type type) { switch (type) { case Module::Type::USB: return ndk::SharedRefBase::make<ModuleUsb>(type); case Type::DEFAULT: case Type::R_SUBMIX: return ndk::SharedRefBase::make<ModuleRemoteSubmix>(type); case Type::DEFAULT: default: return ndk::SharedRefBase::make<Module>(type); } Loading Loading @@ -181,8 +183,8 @@ ndk::ScopedAStatus Module::createStreamContext( StreamContext temp( std::make_unique<StreamContext::CommandMQ>(1, true /*configureEventFlagWord*/), std::make_unique<StreamContext::ReplyMQ>(1, true /*configureEventFlagWord*/), portConfigIt->format.value(), portConfigIt->channelMask.value(), portConfigIt->sampleRate.value().value, flags, portConfigIt->portId, portConfigIt->format.value(), portConfigIt->channelMask.value(), portConfigIt->sampleRate.value().value, flags, portConfigIt->ext.get<AudioPortExt::mix>().handle, std::make_unique<StreamContext::DataMQ>(frameSize * in_bufferSizeFrames), asyncCallback, outEventCallback, params); Loading Loading @@ -490,6 +492,17 @@ ndk::ScopedAStatus Module::connectExternalDevice(const AudioPort& in_templateIdA return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); } for (auto profile : connectedPort.profiles) { if (profile.channelMasks.empty()) { LOG(ERROR) << __func__ << ": the profile " << profile.name << " has no channel masks"; return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); } if (profile.sampleRates.empty()) { LOG(ERROR) << __func__ << ": the profile " << profile.name << " has no sample rates"; return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); } } connectedPort.id = ++getConfig().nextPortId; auto [connectedPortsIt, _] = mConnectedDevicePorts.insert(std::pair(connectedPort.id, std::vector<int32_t>())); Loading
audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h 0 → 100644 +59 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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 "core-impl/Module.h" namespace aidl::android::hardware::audio::core { class ModuleRemoteSubmix : public Module { public: explicit ModuleRemoteSubmix(Module::Type type) : Module(type) {} private: // IModule interfaces ndk::ScopedAStatus getTelephony(std::shared_ptr<ITelephony>* _aidl_return) override; ndk::ScopedAStatus getBluetooth(std::shared_ptr<IBluetooth>* _aidl_return) override; ndk::ScopedAStatus getMicMute(bool* _aidl_return) override; ndk::ScopedAStatus setMicMute(bool in_mute) override; // Module interfaces ndk::ScopedAStatus createInputStream( const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, StreamContext&& context, const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones, std::shared_ptr<StreamIn>* result) override; ndk::ScopedAStatus createOutputStream( const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, StreamContext&& context, const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>& offloadInfo, std::shared_ptr<StreamOut>* result) override; ndk::ScopedAStatus populateConnectedDevicePort( ::aidl::android::media::audio::common::AudioPort* audioPort) override; ndk::ScopedAStatus checkAudioPatchEndpointsMatch( const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sources, const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sinks) override; void onExternalDeviceConnectionChanged( const ::aidl::android::media::audio::common::AudioPort& audioPort, bool connected) override; ndk::ScopedAStatus onMasterMuteChanged(bool mute) override; ndk::ScopedAStatus onMasterVolumeChanged(float volume) override; }; } // namespace aidl::android::hardware::audio::core
audio/aidl/default/include/core-impl/Stream.h +6 −0 Original line number Diff line number Diff line Loading @@ -78,6 +78,7 @@ class StreamContext { StreamContext() = default; StreamContext(std::unique_ptr<CommandMQ> commandMQ, std::unique_ptr<ReplyMQ> replyMQ, int portId, const ::aidl::android::media::audio::common::AudioFormatDescription& format, const ::aidl::android::media::audio::common::AudioChannelLayout& channelLayout, int sampleRate, const ::aidl::android::media::audio::common::AudioIoFlags& flags, Loading @@ -88,6 +89,7 @@ class StreamContext { : mCommandMQ(std::move(commandMQ)), mInternalCommandCookie(std::rand()), mReplyMQ(std::move(replyMQ)), mPortId(portId), mFormat(format), mChannelLayout(channelLayout), mSampleRate(sampleRate), Loading @@ -101,6 +103,7 @@ class StreamContext { : mCommandMQ(std::move(other.mCommandMQ)), mInternalCommandCookie(other.mInternalCommandCookie), mReplyMQ(std::move(other.mReplyMQ)), mPortId(other.mPortId), mFormat(other.mFormat), mChannelLayout(other.mChannelLayout), mSampleRate(other.mSampleRate), Loading @@ -114,6 +117,7 @@ class StreamContext { mCommandMQ = std::move(other.mCommandMQ); mInternalCommandCookie = other.mInternalCommandCookie; mReplyMQ = std::move(other.mReplyMQ); mPortId = std::move(other.mPortId); mFormat = std::move(other.mFormat); mChannelLayout = std::move(other.mChannelLayout); mSampleRate = other.mSampleRate; Loading Loading @@ -145,6 +149,7 @@ class StreamContext { std::shared_ptr<IStreamOutEventCallback> getOutEventCallback() const { return mOutEventCallback; } int getPortId() const { return mPortId; } ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); } int getTransientStateDelayMs() const { return mDebugParameters.transientStateDelayMs; } int getSampleRate() const { return mSampleRate; } Loading @@ -155,6 +160,7 @@ class StreamContext { std::unique_ptr<CommandMQ> mCommandMQ; int mInternalCommandCookie; // The value used to confirm that the command was posted internally std::unique_ptr<ReplyMQ> mReplyMQ; int mPortId; ::aidl::android::media::audio::common::AudioFormatDescription mFormat; ::aidl::android::media::audio::common::AudioChannelLayout mChannelLayout; int mSampleRate; Loading
audio/aidl/default/include/core-impl/StreamRemoteSubmix.h 0 → 100644 +98 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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 <mutex> #include <vector> #include "core-impl/Stream.h" #include "r_submix/SubmixRoute.h" namespace aidl::android::hardware::audio::core { using aidl::android::hardware::audio::core::r_submix::AudioConfig; using aidl::android::hardware::audio::core::r_submix::SubmixRoute; class StreamRemoteSubmix : public StreamCommonImpl { public: StreamRemoteSubmix(const Metadata& metadata, StreamContext&& context); ::android::status_t init() override; ::android::status_t drain(StreamDescriptor::DrainMode) override; ::android::status_t flush() override; ::android::status_t pause() override; ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, int32_t* latencyMs) override; ::android::status_t standby() override; void shutdown() override; // Overridden methods of 'StreamCommonImpl', called on a Binder thread. ndk::ScopedAStatus prepareToClose() override; private: size_t getPipeSizeInFrames(); size_t getStreamPipeSizeInFrames(); ::android::status_t outWrite(void* buffer, size_t frameCount, size_t* actualFrameCount); ::android::status_t inRead(void* buffer, size_t frameCount, size_t* actualFrameCount); const int mPortId; const bool mIsInput; AudioConfig mStreamConfig; std::shared_ptr<SubmixRoute> mCurrentRoute = nullptr; ::android::status_t mStatus = ::android::NO_INIT; // Mutex lock to protect vector of submix routes, each of these submix routes have their mutex // locks and none of the mutex locks should be taken together. static std::mutex sSubmixRoutesLock; static std::map<int32_t, std::shared_ptr<SubmixRoute>> sSubmixRoutes GUARDED_BY(sSubmixRoutesLock); // limit for number of read error log entries to avoid spamming the logs static constexpr int kMaxReadErrorLogs = 5; // The duration of kMaxReadFailureAttempts * READ_ATTEMPT_SLEEP_MS must be strictly inferior // to the duration of a record buffer at the current record sample rate (of the device, not of // the recording itself). Here we have: 3 * 5ms = 15ms < 1024 frames * 1000 / 48000 = 21.333ms static constexpr int kMaxReadFailureAttempts = 3; // 5ms between two read attempts when pipe is empty static constexpr int kReadAttemptSleepUs = 5000; }; class StreamInRemoteSubmix final : public StreamRemoteSubmix, public StreamIn { public: friend class ndk::SharedRefBase; StreamInRemoteSubmix( const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, StreamContext&& context, const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones); private: ndk::ScopedAStatus getActiveMicrophones( std::vector<::aidl::android::media::audio::common::MicrophoneDynamicInfo>* _aidl_return) override; }; class StreamOutRemoteSubmix final : public StreamRemoteSubmix, public StreamOut { public: friend class ndk::SharedRefBase; StreamOutRemoteSubmix( const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, StreamContext&& context, const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>& offloadInfo); }; } // namespace aidl::android::hardware::audio::core