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 24#include <aaudio/AAudio.h> 25#include <aaudio/AAudioTesting.h> 26 27#include "binding/AAudioBinderClient.h" 28#include "client/AudioStreamInternalCapture.h" 29#include "client/AudioStreamInternalPlay.h" 30#include "core/AudioStream.h" 31#include "core/AudioStreamBuilder.h" 32#include "legacy/AudioStreamRecord.h" 33#include "legacy/AudioStreamTrack.h" 34 35using namespace aaudio; 36 37#define AAUDIO_MMAP_POLICY_DEFAULT AAUDIO_POLICY_NEVER 38#define AAUDIO_MMAP_EXCLUSIVE_POLICY_DEFAULT AAUDIO_POLICY_NEVER 39 40// These values are for a pre-check before we ask the lower level service to open a stream. 41// So they are just outside the maximum conceivable range of value, 42// on the edge of being ridiculous. 43// TODO These defines should be moved to a central place in audio. 44#define SAMPLES_PER_FRAME_MIN 1 45// TODO Remove 8 channel limitation. 46#define SAMPLES_PER_FRAME_MAX FCC_8 47#define SAMPLE_RATE_HZ_MIN 8000 48// HDMI supports up to 32 channels at 1536000 Hz. 49#define SAMPLE_RATE_HZ_MAX 1600000 50#define FRAMES_PER_DATA_CALLBACK_MIN 1 51#define FRAMES_PER_DATA_CALLBACK_MAX (1024 * 1024) 52 53/* 54 * AudioStreamBuilder 55 */ 56AudioStreamBuilder::AudioStreamBuilder() { 57} 58 59AudioStreamBuilder::~AudioStreamBuilder() { 60} 61 62static aaudio_result_t builder_createStream(aaudio_direction_t direction, 63 aaudio_sharing_mode_t sharingMode, 64 bool tryMMap, 65 AudioStream **audioStreamPtr) { 66 *audioStreamPtr = nullptr; 67 aaudio_result_t result = AAUDIO_OK; 68 69 switch (direction) { 70 71 case AAUDIO_DIRECTION_INPUT: 72 if (tryMMap) { 73 *audioStreamPtr = new AudioStreamInternalCapture(AAudioBinderClient::getInstance(), 74 false); 75 } else { 76 *audioStreamPtr = new AudioStreamRecord(); 77 } 78 break; 79 80 case AAUDIO_DIRECTION_OUTPUT: 81 if (tryMMap) { 82 *audioStreamPtr = new AudioStreamInternalPlay(AAudioBinderClient::getInstance(), 83 false); 84 } else { 85 *audioStreamPtr = new AudioStreamTrack(); 86 } 87 break; 88 89 default: 90 ALOGE("%s() bad direction = %d", __func__, direction); 91 result = AAUDIO_ERROR_ILLEGAL_ARGUMENT; 92 } 93 return result; 94} 95 96// Try to open using MMAP path if that is allowed. 97// Fall back to Legacy path if MMAP not available. 98// Exact behavior is controlled by MMapPolicy. 99aaudio_result_t AudioStreamBuilder::build(AudioStream** streamPtr) { 100 AudioStream *audioStream = nullptr; 101 if (streamPtr == nullptr) { 102 ALOGE("%s() streamPtr is null", __func__); 103 return AAUDIO_ERROR_NULL; 104 } 105 *streamPtr = nullptr; 106 107 aaudio_result_t result = validate(); 108 if (result != AAUDIO_OK) { 109 return result; 110 } 111 112 // The API setting is the highest priority. 113 aaudio_policy_t mmapPolicy = AAudio_getMMapPolicy(); 114 // If not specified then get from a system property. 115 if (mmapPolicy == AAUDIO_UNSPECIFIED) { 116 mmapPolicy = AAudioProperty_getMMapPolicy(); 117 } 118 // If still not specified then use the default. 119 if (mmapPolicy == AAUDIO_UNSPECIFIED) { 120 mmapPolicy = AAUDIO_MMAP_POLICY_DEFAULT; 121 } 122 123 int32_t mapExclusivePolicy = AAudioProperty_getMMapExclusivePolicy(); 124 if (mapExclusivePolicy == AAUDIO_UNSPECIFIED) { 125 mapExclusivePolicy = AAUDIO_MMAP_EXCLUSIVE_POLICY_DEFAULT; 126 } 127 128 aaudio_sharing_mode_t sharingMode = getSharingMode(); 129 if ((sharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE) 130 && (mapExclusivePolicy == AAUDIO_POLICY_NEVER)) { 131 ALOGD("%s() EXCLUSIVE sharing mode not supported. Use SHARED.", __func__); 132 sharingMode = AAUDIO_SHARING_MODE_SHARED; 133 setSharingMode(sharingMode); 134 } 135 136 bool allowMMap = mmapPolicy != AAUDIO_POLICY_NEVER; 137 bool allowLegacy = mmapPolicy != AAUDIO_POLICY_ALWAYS; 138 139 // TODO Support other performance settings in MMAP mode. 140 // Disable MMAP if low latency not requested. 141 if (getPerformanceMode() != AAUDIO_PERFORMANCE_MODE_LOW_LATENCY) { 142 ALOGD("%s() MMAP not available because AAUDIO_PERFORMANCE_MODE_LOW_LATENCY not used.", 143 __func__); 144 allowMMap = false; 145 } 146 147 // SessionID and Effects are only supported in Legacy mode. 148 if (getSessionId() != AAUDIO_SESSION_ID_NONE) { 149 ALOGD("%s() MMAP not available because sessionId used.", __func__); 150 allowMMap = false; 151 } 152 153 result = builder_createStream(getDirection(), sharingMode, allowMMap, &audioStream); 154 if (result == AAUDIO_OK) { 155 // Open the stream using the parameters from the builder. 156 result = audioStream->open(*this); 157 if (result == AAUDIO_OK) { 158 *streamPtr = audioStream; 159 } else { 160 bool isMMap = audioStream->isMMap(); 161 delete audioStream; 162 audioStream = nullptr; 163 164 if (isMMap && allowLegacy) { 165 ALOGV("%s() MMAP stream did not open so try Legacy path", __func__); 166 // If MMAP stream failed to open then TRY using a legacy stream. 167 result = builder_createStream(getDirection(), sharingMode, 168 false, &audioStream); 169 if (result == AAUDIO_OK) { 170 result = audioStream->open(*this); 171 if (result == AAUDIO_OK) { 172 *streamPtr = audioStream; 173 } else { 174 delete audioStream; 175 } 176 } 177 } 178 } 179 } 180 181 return result; 182} 183 184aaudio_result_t AudioStreamBuilder::validate() const { 185 186 // Check for values that are ridiculously out of range to prevent math overflow exploits. 187 // The service will do a better check. 188 aaudio_result_t result = AAudioStreamParameters::validate(); 189 if (result != AAUDIO_OK) { 190 return result; 191 } 192 193 switch (mPerformanceMode) { 194 case AAUDIO_PERFORMANCE_MODE_NONE: 195 case AAUDIO_PERFORMANCE_MODE_POWER_SAVING: 196 case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY: 197 break; 198 default: 199 ALOGE("illegal performanceMode = %d", mPerformanceMode); 200 return AAUDIO_ERROR_ILLEGAL_ARGUMENT; 201 // break; 202 } 203 204 // Prevent ridiculous values from causing problems. 205 if (mFramesPerDataCallback != AAUDIO_UNSPECIFIED 206 && (mFramesPerDataCallback < FRAMES_PER_DATA_CALLBACK_MIN 207 || mFramesPerDataCallback > FRAMES_PER_DATA_CALLBACK_MAX)) { 208 ALOGE("framesPerDataCallback out of range = %d", 209 mFramesPerDataCallback); 210 return AAUDIO_ERROR_OUT_OF_RANGE; 211 } 212 213 return AAUDIO_OK; 214} 215