• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2015 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 #define LOG_TAG "AudioStreamBuilder"
18 //#define LOG_NDEBUG 0
19 #include <utils/Log.h>
20 
21 #include <new>
22 #include <stdint.h>
23 #include <vector>
24 
25 #include <aaudio/AAudio.h>
26 #include <aaudio/AAudioTesting.h>
27 #include <android/media/audio/common/AudioMMapPolicy.h>
28 #include <android/media/audio/common/AudioMMapPolicyInfo.h>
29 #include <android/media/audio/common/AudioMMapPolicyType.h>
30 #include <media/AudioSystem.h>
31 
32 #include "binding/AAudioBinderClient.h"
33 #include "client/AudioStreamInternalCapture.h"
34 #include "client/AudioStreamInternalPlay.h"
35 #include "core/AudioGlobal.h"
36 #include "core/AudioStream.h"
37 #include "core/AudioStreamBuilder.h"
38 #include "legacy/AudioStreamRecord.h"
39 #include "legacy/AudioStreamTrack.h"
40 
41 using namespace aaudio;
42 
43 using android::media::audio::common::AudioMMapPolicy;
44 using android::media::audio::common::AudioMMapPolicyInfo;
45 using android::media::audio::common::AudioMMapPolicyType;
46 
47 #define AAUDIO_MMAP_POLICY_DEFAULT             AAUDIO_POLICY_NEVER
48 #define AAUDIO_MMAP_EXCLUSIVE_POLICY_DEFAULT   AAUDIO_POLICY_NEVER
49 
50 // These values are for a pre-check before we ask the lower level service to open a stream.
51 // So they are just outside the maximum conceivable range of value,
52 // on the edge of being ridiculous.
53 // TODO These defines should be moved to a central place in audio.
54 #define SAMPLES_PER_FRAME_MIN        1
55 #define SAMPLES_PER_FRAME_MAX        FCC_LIMIT
56 #define SAMPLE_RATE_HZ_MIN           8000
57 // HDMI supports up to 32 channels at 1536000 Hz.
58 #define SAMPLE_RATE_HZ_MAX           1600000
59 #define FRAMES_PER_DATA_CALLBACK_MIN 1
60 #define FRAMES_PER_DATA_CALLBACK_MAX (1024 * 1024)
61 
62 /*
63  * AudioStreamBuilder
64  */
builder_createStream(aaudio_direction_t direction,aaudio_sharing_mode_t,bool tryMMap,android::sp<AudioStream> & stream)65 static aaudio_result_t builder_createStream(aaudio_direction_t direction,
66                                             aaudio_sharing_mode_t /*sharingMode*/,
67                                             bool tryMMap,
68                                             android::sp<AudioStream> &stream) {
69     aaudio_result_t result = AAUDIO_OK;
70 
71     switch (direction) {
72 
73         case AAUDIO_DIRECTION_INPUT:
74             if (tryMMap) {
75                 stream = new AudioStreamInternalCapture(AAudioBinderClient::getInstance(),
76                                                                  false);
77             } else {
78                 stream = new AudioStreamRecord();
79             }
80             break;
81 
82         case AAUDIO_DIRECTION_OUTPUT:
83             if (tryMMap) {
84                 stream = new AudioStreamInternalPlay(AAudioBinderClient::getInstance(),
85                                                               false);
86             } else {
87                 stream = new AudioStreamTrack();
88             }
89             break;
90 
91         default:
92             ALOGE("%s() bad direction = %d", __func__, direction);
93             result = AAUDIO_ERROR_ILLEGAL_ARGUMENT;
94     }
95     return result;
96 }
97 
98 namespace {
99 
aidl2legacy_aaudio_policy(AudioMMapPolicy aidl)100 aaudio_policy_t aidl2legacy_aaudio_policy(AudioMMapPolicy aidl) {
101     switch (aidl) {
102         case AudioMMapPolicy::NEVER:
103             return AAUDIO_POLICY_NEVER;
104         case AudioMMapPolicy::AUTO:
105             return AAUDIO_POLICY_AUTO;
106         case AudioMMapPolicy::ALWAYS:
107             return AAUDIO_POLICY_ALWAYS;
108         case AudioMMapPolicy::UNSPECIFIED:
109         default:
110             return AAUDIO_UNSPECIFIED;
111     }
112 }
113 
114 // The aaudio policy will be ALWAYS, NEVER, UNSPECIFIED only when all policy info are
115 // ALWAYS, NEVER or UNSPECIFIED. Otherwise, the aaudio policy will be AUTO.
getAAudioPolicy(const std::vector<AudioMMapPolicyInfo> & policyInfos)116 aaudio_policy_t getAAudioPolicy(
117         const std::vector<AudioMMapPolicyInfo>& policyInfos) {
118     if (policyInfos.empty()) return AAUDIO_POLICY_AUTO;
119     for (size_t i = 1; i < policyInfos.size(); ++i) {
120         if (policyInfos.at(i).mmapPolicy != policyInfos.at(0).mmapPolicy) {
121             return AAUDIO_POLICY_AUTO;
122         }
123     }
124     return aidl2legacy_aaudio_policy(policyInfos.at(0).mmapPolicy);
125 }
126 
127 } // namespace
128 
129 // Try to open using MMAP path if that is allowed.
130 // Fall back to Legacy path if MMAP not available.
131 // Exact behavior is controlled by MMapPolicy.
build(AudioStream ** streamPtr)132 aaudio_result_t AudioStreamBuilder::build(AudioStream** streamPtr) {
133 
134     if (streamPtr == nullptr) {
135         ALOGE("%s() streamPtr is null", __func__);
136         return AAUDIO_ERROR_NULL;
137     }
138     *streamPtr = nullptr;
139 
140     logParameters();
141 
142     aaudio_result_t result = validate();
143     if (result != AAUDIO_OK) {
144         return result;
145     }
146 
147     std::vector<AudioMMapPolicyInfo> policyInfos;
148     // The API setting is the highest priority.
149     aaudio_policy_t mmapPolicy = AudioGlobal_getMMapPolicy();
150     // If not specified then get from a system property.
151     if (mmapPolicy == AAUDIO_UNSPECIFIED && android::AudioSystem::getMmapPolicyInfo(
152                 AudioMMapPolicyType::DEFAULT, &policyInfos) == NO_ERROR) {
153         mmapPolicy = getAAudioPolicy(policyInfos);
154     }
155     // If still not specified then use the default.
156     if (mmapPolicy == AAUDIO_UNSPECIFIED) {
157         mmapPolicy = AAUDIO_MMAP_POLICY_DEFAULT;
158     }
159 
160     policyInfos.clear();
161     aaudio_policy_t mmapExclusivePolicy = AAUDIO_UNSPECIFIED;
162     if (android::AudioSystem::getMmapPolicyInfo(
163             AudioMMapPolicyType::EXCLUSIVE, &policyInfos) == NO_ERROR) {
164         mmapExclusivePolicy = getAAudioPolicy(policyInfos);
165     }
166     if (mmapExclusivePolicy == AAUDIO_UNSPECIFIED) {
167         mmapExclusivePolicy = AAUDIO_MMAP_EXCLUSIVE_POLICY_DEFAULT;
168     }
169 
170     aaudio_sharing_mode_t sharingMode = getSharingMode();
171     if ((sharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE)
172         && (mmapExclusivePolicy == AAUDIO_POLICY_NEVER)) {
173         ALOGD("%s() EXCLUSIVE sharing mode not supported. Use SHARED.", __func__);
174         sharingMode = AAUDIO_SHARING_MODE_SHARED;
175         setSharingMode(sharingMode);
176     }
177 
178     bool allowMMap = mmapPolicy != AAUDIO_POLICY_NEVER;
179     bool allowLegacy = mmapPolicy != AAUDIO_POLICY_ALWAYS;
180 
181     // TODO Support other performance settings in MMAP mode.
182     // Disable MMAP if low latency not requested.
183     if (getPerformanceMode() != AAUDIO_PERFORMANCE_MODE_LOW_LATENCY) {
184         ALOGD("%s() MMAP not used because AAUDIO_PERFORMANCE_MODE_LOW_LATENCY not requested.",
185               __func__);
186         allowMMap = false;
187     }
188 
189     // SessionID and Effects are only supported in Legacy mode.
190     if (getSessionId() != AAUDIO_SESSION_ID_NONE) {
191         ALOGD("%s() MMAP not used because sessionId specified.", __func__);
192         allowMMap = false;
193     }
194 
195     if (!allowMMap && !allowLegacy) {
196         ALOGE("%s() no backend available: neither MMAP nor legacy path are allowed", __func__);
197         return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
198     }
199 
200     setPrivacySensitive(false);
201     if (mPrivacySensitiveReq == PRIVACY_SENSITIVE_DEFAULT) {
202         // When not explicitly requested, set privacy sensitive mode according to input preset:
203         // communication and camcorder captures are considered privacy sensitive by default.
204         aaudio_input_preset_t preset = getInputPreset();
205         if (preset == AAUDIO_INPUT_PRESET_CAMCORDER
206                 || preset == AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION) {
207             setPrivacySensitive(true);
208         }
209     } else if (mPrivacySensitiveReq == PRIVACY_SENSITIVE_ENABLED) {
210         setPrivacySensitive(true);
211     }
212 
213     android::sp<AudioStream> audioStream;
214     result = builder_createStream(getDirection(), sharingMode, allowMMap, audioStream);
215     if (result == AAUDIO_OK) {
216         // Open the stream using the parameters from the builder.
217         result = audioStream->open(*this);
218         if (result != AAUDIO_OK) {
219             bool isMMap = audioStream->isMMap();
220             if (isMMap && allowLegacy) {
221                 ALOGV("%s() MMAP stream did not open so try Legacy path", __func__);
222                 // If MMAP stream failed to open then TRY using a legacy stream.
223                 result = builder_createStream(getDirection(), sharingMode,
224                                               false, audioStream);
225                 if (result == AAUDIO_OK) {
226                     result = audioStream->open(*this);
227                 }
228             }
229         }
230         if (result == AAUDIO_OK) {
231             audioStream->registerPlayerBase();
232             audioStream->logOpenActual();
233             *streamPtr = startUsingStream(audioStream);
234         } // else audioStream will go out of scope and be deleted
235     }
236 
237     return result;
238 }
239 
startUsingStream(android::sp<AudioStream> & audioStream)240 AudioStream *AudioStreamBuilder::startUsingStream(android::sp<AudioStream> &audioStream) {
241     // Increment the smart pointer so it will not get deleted when
242     // we pass it to the C caller and it goes out of scope.
243     // The C code cannot hold a smart pointer so we increment the reference
244     // count to indicate that the C app owns a reference.
245     audioStream->incStrong(nullptr);
246     return audioStream.get();
247 }
248 
stopUsingStream(AudioStream * stream)249 void AudioStreamBuilder::stopUsingStream(AudioStream *stream) {
250     // Undo the effect of startUsingStream()
251     android::sp<AudioStream> spAudioStream(stream);
252     ALOGV("%s() strongCount = %d", __func__, spAudioStream->getStrongCount());
253     spAudioStream->decStrong(nullptr);
254 }
255 
validate() const256 aaudio_result_t AudioStreamBuilder::validate() const {
257 
258     // Check for values that are ridiculously out of range to prevent math overflow exploits.
259     // The service will do a better check.
260     aaudio_result_t result = AAudioStreamParameters::validate();
261     if (result != AAUDIO_OK) {
262         return result;
263     }
264 
265     switch (mPerformanceMode) {
266         case AAUDIO_PERFORMANCE_MODE_NONE:
267         case AAUDIO_PERFORMANCE_MODE_POWER_SAVING:
268         case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY:
269             break;
270         default:
271             ALOGE("illegal performanceMode = %d", mPerformanceMode);
272             return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
273             // break;
274     }
275 
276     // Prevent ridiculous values from causing problems.
277     if (mFramesPerDataCallback != AAUDIO_UNSPECIFIED
278         && (mFramesPerDataCallback < FRAMES_PER_DATA_CALLBACK_MIN
279             || mFramesPerDataCallback > FRAMES_PER_DATA_CALLBACK_MAX)) {
280         ALOGE("framesPerDataCallback out of range = %d",
281               mFramesPerDataCallback);
282         return AAUDIO_ERROR_OUT_OF_RANGE;
283     }
284 
285     return AAUDIO_OK;
286 }
287 
AAudio_convertSharingModeToShortText(aaudio_sharing_mode_t sharingMode)288 static const char *AAudio_convertSharingModeToShortText(aaudio_sharing_mode_t sharingMode) {
289     switch (sharingMode) {
290         case AAUDIO_SHARING_MODE_EXCLUSIVE:
291             return "EX";
292         case AAUDIO_SHARING_MODE_SHARED:
293             return "SH";
294         default:
295             return "?!";
296     }
297 }
298 
AAudio_convertDirectionToText(aaudio_direction_t direction)299 static const char *AAudio_convertDirectionToText(aaudio_direction_t direction) {
300     switch (direction) {
301         case AAUDIO_DIRECTION_OUTPUT:
302             return "OUTPUT";
303         case AAUDIO_DIRECTION_INPUT:
304             return "INPUT";
305         default:
306             return "?!";
307     }
308 }
309 
logParameters() const310 void AudioStreamBuilder::logParameters() const {
311     // This is very helpful for debugging in the future. Please leave it in.
312     ALOGI("rate   = %6d, channels  = %d, channelMask = %#x, format   = %d, sharing = %s, dir = %s",
313           getSampleRate(), getSamplesPerFrame(), getChannelMask(), getFormat(),
314           AAudio_convertSharingModeToShortText(getSharingMode()),
315           AAudio_convertDirectionToText(getDirection()));
316     ALOGI("device = %6d, sessionId = %d, perfMode = %d, callback: %s with frames = %d",
317           getDeviceId(),
318           getSessionId(),
319           getPerformanceMode(),
320           ((getDataCallbackProc() != nullptr) ? "ON" : "OFF"),
321           mFramesPerDataCallback);
322     ALOGI("usage  = %6d, contentType = %d, inputPreset = %d, allowedCapturePolicy = %d",
323           getUsage(), getContentType(), getInputPreset(), getAllowedCapturePolicy());
324     ALOGI("privacy sensitive = %s, opPackageName = %s, attributionTag = %s",
325           isPrivacySensitive() ? "true" : "false",
326           !getOpPackageName().has_value() ? "(null)" : getOpPackageName().value().c_str(),
327           !getAttributionTag().has_value() ? "(null)" : getAttributionTag().value().c_str());
328 }
329