• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <mutex>
20 #include <string>
21 
22 #include <android-base/thread_annotations.h>
23 #include <audio_utils/clock.h>
24 
25 #include <media/nbaio/MonoPipe.h>
26 #include <media/nbaio/MonoPipeReader.h>
27 
28 #include <aidl/android/media/audio/common/AudioChannelLayout.h>
29 #include <aidl/android/media/audio/common/AudioDeviceAddress.h>
30 #include <aidl/android/media/audio/common/AudioFormatDescription.h>
31 
32 using aidl::android::media::audio::common::AudioChannelLayout;
33 using aidl::android::media::audio::common::AudioFormatDescription;
34 using aidl::android::media::audio::common::AudioFormatType;
35 using aidl::android::media::audio::common::PcmType;
36 using ::android::MonoPipe;
37 using ::android::MonoPipeReader;
38 using ::android::sp;
39 
40 namespace aidl::android::hardware::audio::core::r_submix {
41 
42 static constexpr int kDefaultSampleRateHz = 48000;
43 // Value used to divide the MonoPipe buffer into segments that are written to the source and
44 // read from the sink. The maximum latency of the device is the size of the MonoPipe's buffer
45 // the minimum latency is the MonoPipe buffer size divided by this value.
46 static constexpr int kDefaultPipePeriodCount = 4;
47 // Size at the default sample rate
48 // NOTE: This value will be rounded up to the nearest power of 2 by MonoPipe.
49 static constexpr int kDefaultPipeSizeInFrames = 1024 * kDefaultPipePeriodCount;
50 
51 // Configuration of the audio stream.
52 struct AudioConfig {
53     int sampleRate = kDefaultSampleRateHz;
54     AudioFormatDescription format =
55             AudioFormatDescription{.type = AudioFormatType::PCM, .pcm = PcmType::INT_16_BIT};
56     AudioChannelLayout channelLayout =
57             AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
58                     AudioChannelLayout::LAYOUT_STEREO);
59     size_t frameSize;
60     size_t frameCount;
61 };
62 
63 class SubmixRoute {
64   public:
65     static std::shared_ptr<SubmixRoute> findOrCreateRoute(
66             const ::aidl::android::media::audio::common::AudioDeviceAddress& deviceAddress,
67             const AudioConfig& pipeConfig);
68     static std::shared_ptr<SubmixRoute> findRoute(
69             const ::aidl::android::media::audio::common::AudioDeviceAddress& deviceAddress);
70     static void removeRoute(
71             const ::aidl::android::media::audio::common::AudioDeviceAddress& deviceAddress);
72     static std::string dumpRoutes();
73 
isStreamInOpen()74     bool isStreamInOpen() {
75         std::lock_guard guard(mLock);
76         return mStreamInOpen;
77     }
getStreamInStandby()78     bool getStreamInStandby() {
79         std::lock_guard guard(mLock);
80         return mStreamInStandby;
81     }
isStreamOutOpen()82     bool isStreamOutOpen() {
83         std::lock_guard guard(mLock);
84         return mStreamOutOpen;
85     }
getStreamOutStandby()86     bool getStreamOutStandby() {
87         std::lock_guard guard(mLock);
88         return mStreamOutStandby;
89     }
getReadCounterFrames()90     long getReadCounterFrames() {
91         std::lock_guard guard(mLock);
92         return mReadCounterFrames;
93     }
getSink()94     sp<MonoPipe> getSink() {
95         std::lock_guard guard(mLock);
96         return mSink;
97     }
getSource()98     sp<MonoPipeReader> getSource() {
99         std::lock_guard guard(mLock);
100         return mSource;
101     }
getPipeConfig()102     AudioConfig getPipeConfig() {
103         std::lock_guard guard(mLock);
104         return mPipeConfig;
105     }
106 
107     bool isStreamConfigValid(bool isInput, const AudioConfig& streamConfig);
108     void closeStream(bool isInput);
109     ::android::status_t createPipe(const AudioConfig& streamConfig);
110     void exitStandby(bool isInput);
111     bool hasAtleastOneStreamOpen();
112     int notifyReadError();
113     void openStream(bool isInput);
114     AudioConfig releasePipe();
115     ::android::status_t resetPipe();
116     bool shouldBlockWrite();
117     void standby(bool isInput);
118     long updateReadCounterFrames(size_t frameCount);
119 
120     std::string dump();
121 
122   private:
123     using RoutesMap = std::map<::aidl::android::media::audio::common::AudioDeviceAddress,
124                                std::shared_ptr<r_submix::SubmixRoute>>;
125     class RoutesMonitor {
126       public:
RoutesMonitor(std::mutex & mutex,RoutesMap & routes)127         RoutesMonitor(std::mutex& mutex, RoutesMap& routes) : mLock(mutex), mRoutes(routes) {}
RoutesMonitor(std::mutex & mutex,RoutesMap & routes,bool)128         RoutesMonitor(std::mutex& mutex, RoutesMap& routes, bool /*tryLock*/)
129             : mLock(mutex, std::try_to_lock), mRoutes(routes) {}
130         RoutesMap* operator->() { return &mRoutes; }
131 
132       private:
133         std::unique_lock<std::mutex> mLock;
134         RoutesMap& mRoutes;
135     };
136 
137     static RoutesMonitor getRoutes(bool tryLock = false);
138 
139     bool isStreamConfigCompatible(const AudioConfig& streamConfig);
140 
141     std::mutex mLock;
142     AudioConfig mPipeConfig GUARDED_BY(mLock);
143     bool mStreamInOpen GUARDED_BY(mLock) = false;
144     int mInputRefCount GUARDED_BY(mLock) = 0;
145     bool mStreamInStandby GUARDED_BY(mLock) = true;
146     bool mStreamOutStandbyTransition GUARDED_BY(mLock) = false;
147     bool mStreamOutOpen GUARDED_BY(mLock) = false;
148     bool mStreamOutStandby GUARDED_BY(mLock) = true;
149     // how many frames have been requested to be read since standby
150     long mReadCounterFrames GUARDED_BY(mLock) = 0;
151 
152     // Pipe variables: they handle the ring buffer that "pipes" audio:
153     //  - from the submix virtual audio output == what needs to be played
154     //    remotely, seen as an output for the client
155     //  - to the virtual audio source == what is captured by the component
156     //    which "records" the submix / virtual audio source, and handles it as needed.
157     // A usecase example is one where the component capturing the audio is then sending it over
158     // Wifi for presentation on a remote Wifi Display device (e.g. a dongle attached to a TV, or a
159     // TV with Wifi Display capabilities), or to a wireless audio player.
160     sp<MonoPipe> mSink GUARDED_BY(mLock);
161     sp<MonoPipeReader> mSource GUARDED_BY(mLock);
162 };
163 
164 }  // namespace aidl::android::hardware::audio::core::r_submix
165