1 /*
2  * Copyright 2019 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 #ifndef OBOE_QUIRKS_MANAGER_H
18 #define OBOE_QUIRKS_MANAGER_H
19 
20 #include <memory>
21 #include <oboe/AudioStreamBuilder.h>
22 #include <aaudio/AudioStreamAAudio.h>
23 
24 #ifndef __ANDROID_API_R__
25 #define __ANDROID_API_R__ 30
26 #endif
27 
28 namespace oboe {
29 
30 /**
31  * INTERNAL USE ONLY.
32  *
33  * Based on manufacturer, model and Android version number
34  * decide whether data conversion needs to occur.
35  *
36  * This also manages device and version specific workarounds.
37  */
38 
39 class QuirksManager {
40 public:
41 
getInstance()42     static QuirksManager &getInstance() {
43         static QuirksManager instance; // singleton
44         return instance;
45     }
46 
47     QuirksManager();
48     virtual ~QuirksManager() = default;
49 
50     /**
51      * Do we need to do channel, format or rate conversion to provide a low latency
52      * stream for this builder? If so then provide a builder for the native child stream
53      * that will be used to get low latency.
54      *
55      * @param builder builder provided by application
56      * @param childBuilder modified builder appropriate for the underlying device
57      * @return true if conversion is needed
58      */
59     bool isConversionNeeded(const AudioStreamBuilder &builder, AudioStreamBuilder &childBuilder);
60 
isMMapUsed(AudioStream & stream)61     static bool isMMapUsed(AudioStream &stream) {
62         bool answer = false;
63         if (stream.getAudioApi() == AudioApi::AAudio) {
64             AudioStreamAAudio *streamAAudio =
65                     reinterpret_cast<AudioStreamAAudio *>(&stream);
66             answer = streamAAudio->isMMapUsed();
67         }
68         return answer;
69     }
70 
clipBufferSize(AudioStream & stream,int32_t bufferSize)71     virtual int32_t clipBufferSize(AudioStream &stream, int32_t bufferSize) {
72         return mDeviceQuirks->clipBufferSize(stream, bufferSize);
73     }
74 
75     class DeviceQuirks {
76     public:
77         virtual ~DeviceQuirks() = default;
78 
79         /**
80          * Restrict buffer size. This is mainly to avoid glitches caused by MMAP
81          * timestamp inaccuracies.
82          * @param stream
83          * @param requestedSize
84          * @return
85          */
86         int32_t clipBufferSize(AudioStream &stream, int32_t requestedSize);
87 
88         // Exclusive MMAP streams can have glitches because they are using a timing
89         // model of the DSP to control IO instead of direct synchronization.
getExclusiveBottomMarginInBursts()90         virtual int32_t getExclusiveBottomMarginInBursts() const {
91             return kDefaultBottomMarginInBursts;
92         }
93 
getExclusiveTopMarginInBursts()94         virtual int32_t getExclusiveTopMarginInBursts() const {
95             return kDefaultTopMarginInBursts;
96         }
97 
98         // On some devices, you can open a mono stream but it is actually running in stereo!
isMonoMMapActuallyStereo()99         virtual bool isMonoMMapActuallyStereo() const {
100             return false;
101         }
102 
103         virtual bool isAAudioMMapPossible(const AudioStreamBuilder &builder) const;
104 
isMMapSafe(const AudioStreamBuilder &)105         virtual bool isMMapSafe(const AudioStreamBuilder & /* builder */ ) {
106             return true;
107         }
108 
109         static constexpr int32_t kDefaultBottomMarginInBursts = 0;
110         static constexpr int32_t kDefaultTopMarginInBursts = 0;
111 
112         // For Legacy streams, do not let the buffer go below one burst.
113         // b/129545119 | AAudio Legacy allows setBufferSizeInFrames too low
114         // Fixed in Q
115         static constexpr int32_t kLegacyBottomMarginInBursts = 1;
116         static constexpr int32_t kCommonNativeRate = 48000; // very typical native sample rate
117     };
118 
119     bool isMMapSafe(AudioStreamBuilder &builder);
120 
121 private:
122 
123     static constexpr int32_t kChannelCountMono = 1;
124     static constexpr int32_t kChannelCountStereo = 2;
125 
126     std::unique_ptr<DeviceQuirks> mDeviceQuirks{};
127 
128 };
129 
130 }
131 #endif //OBOE_QUIRKS_MANAGER_H
132