| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright (C) 2017 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 |  | 
| Eric Laurent | cb4dae2 | 2017-07-01 19:39:32 -0700 | [diff] [blame] | 17 | #define LOG_TAG "AAudioServiceStreamShared" | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 18 | //#define LOG_NDEBUG 0 | 
 | 19 | #include <utils/Log.h> | 
 | 20 |  | 
| Phil Burk | a5222e2 | 2017-07-28 13:31:14 -0700 | [diff] [blame] | 21 | #include <iomanip> | 
 | 22 | #include <iostream> | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 23 | #include <mutex> | 
 | 24 |  | 
 | 25 | #include <aaudio/AAudio.h> | 
 | 26 |  | 
 | 27 | #include "binding/IAAudioService.h" | 
 | 28 |  | 
 | 29 | #include "binding/AAudioServiceMessage.h" | 
 | 30 | #include "AAudioServiceStreamBase.h" | 
 | 31 | #include "AAudioServiceStreamShared.h" | 
 | 32 | #include "AAudioEndpointManager.h" | 
 | 33 | #include "AAudioService.h" | 
 | 34 | #include "AAudioServiceEndpoint.h" | 
 | 35 |  | 
 | 36 | using namespace android; | 
 | 37 | using namespace aaudio; | 
 | 38 |  | 
| Phil Burk | ec89b2e | 2017-06-20 15:05:06 -0700 | [diff] [blame] | 39 | #define MIN_BURSTS_PER_BUFFER       2 | 
 | 40 | #define DEFAULT_BURSTS_PER_BUFFER   16 | 
 | 41 | // This is an arbitrary range. TODO review. | 
 | 42 | #define MAX_FRAMES_PER_BUFFER       (32 * 1024) | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 43 |  | 
 | 44 | AAudioServiceStreamShared::AAudioServiceStreamShared(AAudioService &audioService) | 
| Phil Burk | 39f02dd | 2017-08-04 09:13:31 -0700 | [diff] [blame] | 45 |     : AAudioServiceStreamBase(audioService) | 
| Phil Burk | 97350f9 | 2017-07-21 15:59:44 -0700 | [diff] [blame] | 46 |     , mTimestampPositionOffset(0) | 
| Phil Burk | 39f02dd | 2017-08-04 09:13:31 -0700 | [diff] [blame] | 47 |     , mXRunCount(0) { | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 48 | } | 
 | 49 |  | 
| Phil Burk | a5222e2 | 2017-07-28 13:31:14 -0700 | [diff] [blame] | 50 | std::string AAudioServiceStreamShared::dumpHeader() { | 
 | 51 |     std::stringstream result; | 
 | 52 |     result << AAudioServiceStreamBase::dumpHeader(); | 
 | 53 |     result << "    Write#     Read#   Avail   XRuns"; | 
 | 54 |     return result.str(); | 
 | 55 | } | 
 | 56 |  | 
 | 57 | std::string AAudioServiceStreamShared::dump() const { | 
 | 58 |     std::stringstream result; | 
| Phil Burk | 39f02dd | 2017-08-04 09:13:31 -0700 | [diff] [blame] | 59 |  | 
| Phil Burk | a5222e2 | 2017-07-28 13:31:14 -0700 | [diff] [blame] | 60 |     result << AAudioServiceStreamBase::dump(); | 
 | 61 |  | 
 | 62 |     auto fifo = mAudioDataQueue->getFifoBuffer(); | 
 | 63 |     int32_t readCounter = fifo->getReadCounter(); | 
 | 64 |     int32_t writeCounter = fifo->getWriteCounter(); | 
 | 65 |     result << std::setw(10) << writeCounter; | 
 | 66 |     result << std::setw(10) << readCounter; | 
 | 67 |     result << std::setw(8) << (writeCounter - readCounter); | 
 | 68 |     result << std::setw(8) << getXRunCount(); | 
 | 69 |  | 
 | 70 |     return result.str(); | 
 | 71 | } | 
 | 72 |  | 
| Phil Burk | ec89b2e | 2017-06-20 15:05:06 -0700 | [diff] [blame] | 73 | int32_t AAudioServiceStreamShared::calculateBufferCapacity(int32_t requestedCapacityFrames, | 
 | 74 |                                                            int32_t framesPerBurst) { | 
 | 75 |  | 
 | 76 |     if (requestedCapacityFrames > MAX_FRAMES_PER_BUFFER) { | 
| Phil Burk | 11e8d33 | 2017-05-24 09:59:02 -0700 | [diff] [blame] | 77 |         ALOGE("AAudioServiceStreamShared::calculateBufferCapacity() requested capacity %d > max %d", | 
| Phil Burk | ec89b2e | 2017-06-20 15:05:06 -0700 | [diff] [blame] | 78 |               requestedCapacityFrames, MAX_FRAMES_PER_BUFFER); | 
 | 79 |         return AAUDIO_ERROR_OUT_OF_RANGE; | 
 | 80 |     } | 
 | 81 |  | 
 | 82 |     // Determine how many bursts will fit in the buffer. | 
 | 83 |     int32_t numBursts; | 
 | 84 |     if (requestedCapacityFrames == AAUDIO_UNSPECIFIED) { | 
 | 85 |         // Use fewer bursts if default is too many. | 
 | 86 |         if ((DEFAULT_BURSTS_PER_BUFFER * framesPerBurst) > MAX_FRAMES_PER_BUFFER) { | 
 | 87 |             numBursts = MAX_FRAMES_PER_BUFFER / framesPerBurst; | 
 | 88 |         } else { | 
 | 89 |             numBursts = DEFAULT_BURSTS_PER_BUFFER; | 
 | 90 |         } | 
 | 91 |     } else { | 
 | 92 |         // round up to nearest burst boundary | 
 | 93 |         numBursts = (requestedCapacityFrames + framesPerBurst - 1) / framesPerBurst; | 
 | 94 |     } | 
 | 95 |  | 
 | 96 |     // Clip to bare minimum. | 
 | 97 |     if (numBursts < MIN_BURSTS_PER_BUFFER) { | 
 | 98 |         numBursts = MIN_BURSTS_PER_BUFFER; | 
 | 99 |     } | 
 | 100 |     // Check for numeric overflow. | 
 | 101 |     if (numBursts > 0x8000 || framesPerBurst > 0x8000) { | 
| Phil Burk | 11e8d33 | 2017-05-24 09:59:02 -0700 | [diff] [blame] | 102 |         ALOGE("AAudioServiceStreamShared::calculateBufferCapacity() overflow, capacity = %d * %d", | 
| Phil Burk | ec89b2e | 2017-06-20 15:05:06 -0700 | [diff] [blame] | 103 |               numBursts, framesPerBurst); | 
 | 104 |         return AAUDIO_ERROR_OUT_OF_RANGE; | 
 | 105 |     } | 
 | 106 |     int32_t capacityInFrames = numBursts * framesPerBurst; | 
 | 107 |  | 
 | 108 |     // Final sanity check. | 
 | 109 |     if (capacityInFrames > MAX_FRAMES_PER_BUFFER) { | 
| Phil Burk | 11e8d33 | 2017-05-24 09:59:02 -0700 | [diff] [blame] | 110 |         ALOGE("AAudioServiceStreamShared::calculateBufferCapacity() calc capacity %d > max %d", | 
| Phil Burk | ec89b2e | 2017-06-20 15:05:06 -0700 | [diff] [blame] | 111 |               capacityInFrames, MAX_FRAMES_PER_BUFFER); | 
 | 112 |         return AAUDIO_ERROR_OUT_OF_RANGE; | 
 | 113 |     } | 
| Phil Burk | 11e8d33 | 2017-05-24 09:59:02 -0700 | [diff] [blame] | 114 |     ALOGD("AAudioServiceStreamShared::calculateBufferCapacity() requested %d frames, actual = %d", | 
| Phil Burk | ec89b2e | 2017-06-20 15:05:06 -0700 | [diff] [blame] | 115 |           requestedCapacityFrames, capacityInFrames); | 
 | 116 |     return capacityInFrames; | 
 | 117 | } | 
 | 118 |  | 
| Phil Burk | 39f02dd | 2017-08-04 09:13:31 -0700 | [diff] [blame] | 119 | aaudio_result_t AAudioServiceStreamShared::open(const aaudio::AAudioStreamRequest &request)  { | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 120 |  | 
| Phil Burk | 11e8d33 | 2017-05-24 09:59:02 -0700 | [diff] [blame] | 121 |     sp<AAudioServiceStreamShared> keep(this); | 
 | 122 |  | 
| Phil Burk | 39f02dd | 2017-08-04 09:13:31 -0700 | [diff] [blame] | 123 |     aaudio_result_t result = AAudioServiceStreamBase::open(request, AAUDIO_SHARING_MODE_SHARED); | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 124 |     if (result != AAUDIO_OK) { | 
| Phil Burk | ec89b2e | 2017-06-20 15:05:06 -0700 | [diff] [blame] | 125 |         ALOGE("AAudioServiceStreamBase open() returned %d", result); | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 126 |         return result; | 
 | 127 |     } | 
 | 128 |  | 
 | 129 |     const AAudioStreamConfiguration &configurationInput = request.getConstantConfiguration(); | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 130 |  | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 131 |  | 
 | 132 |     // Is the request compatible with the shared endpoint? | 
| Phil Burk | 39f02dd | 2017-08-04 09:13:31 -0700 | [diff] [blame] | 133 |     setFormat(configurationInput.getFormat()); | 
 | 134 |     if (getFormat() == AAUDIO_FORMAT_UNSPECIFIED) { | 
 | 135 |         setFormat(AAUDIO_FORMAT_PCM_FLOAT); | 
 | 136 |     } else if (getFormat() != AAUDIO_FORMAT_PCM_FLOAT) { | 
 | 137 |         ALOGE("AAudioServiceStreamShared::open() mAudioFormat = %d, need FLOAT", getFormat()); | 
| Phil Burk | ec89b2e | 2017-06-20 15:05:06 -0700 | [diff] [blame] | 138 |         result = AAUDIO_ERROR_INVALID_FORMAT; | 
 | 139 |         goto error; | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 140 |     } | 
 | 141 |  | 
| Phil Burk | 39f02dd | 2017-08-04 09:13:31 -0700 | [diff] [blame] | 142 |     setSampleRate(configurationInput.getSampleRate()); | 
 | 143 |     if (getSampleRate() == AAUDIO_UNSPECIFIED) { | 
 | 144 |         setSampleRate(mServiceEndpoint->getSampleRate()); | 
 | 145 |     } else if (getSampleRate() != mServiceEndpoint->getSampleRate()) { | 
| Phil Burk | 11e8d33 | 2017-05-24 09:59:02 -0700 | [diff] [blame] | 146 |         ALOGE("AAudioServiceStreamShared::open() mSampleRate = %d, need %d", | 
| Phil Burk | 39f02dd | 2017-08-04 09:13:31 -0700 | [diff] [blame] | 147 |               getSampleRate(), mServiceEndpoint->getSampleRate()); | 
| Phil Burk | ec89b2e | 2017-06-20 15:05:06 -0700 | [diff] [blame] | 148 |         result = AAUDIO_ERROR_INVALID_RATE; | 
 | 149 |         goto error; | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 150 |     } | 
 | 151 |  | 
| Phil Burk | 39f02dd | 2017-08-04 09:13:31 -0700 | [diff] [blame] | 152 |     setSamplesPerFrame(configurationInput.getSamplesPerFrame()); | 
 | 153 |     if (getSamplesPerFrame() == AAUDIO_UNSPECIFIED) { | 
 | 154 |         setSamplesPerFrame(mServiceEndpoint->getSamplesPerFrame()); | 
 | 155 |     } else if (getSamplesPerFrame() != mServiceEndpoint->getSamplesPerFrame()) { | 
| Phil Burk | 11e8d33 | 2017-05-24 09:59:02 -0700 | [diff] [blame] | 156 |         ALOGE("AAudioServiceStreamShared::open() mSamplesPerFrame = %d, need %d", | 
| Phil Burk | 39f02dd | 2017-08-04 09:13:31 -0700 | [diff] [blame] | 157 |               getSamplesPerFrame(), mServiceEndpoint->getSamplesPerFrame()); | 
| Phil Burk | ec89b2e | 2017-06-20 15:05:06 -0700 | [diff] [blame] | 158 |         result = AAUDIO_ERROR_OUT_OF_RANGE; | 
 | 159 |         goto error; | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 160 |     } | 
 | 161 |  | 
| Phil Burk | 39f02dd | 2017-08-04 09:13:31 -0700 | [diff] [blame] | 162 |     setBufferCapacity(calculateBufferCapacity(configurationInput.getBufferCapacity(), | 
 | 163 |                                      mFramesPerBurst)); | 
 | 164 |     if (getBufferCapacity() < 0) { | 
 | 165 |         result = getBufferCapacity(); // negative error code | 
 | 166 |         setBufferCapacity(0); | 
| Phil Burk | ec89b2e | 2017-06-20 15:05:06 -0700 | [diff] [blame] | 167 |         goto error; | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 168 |     } | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 169 |  | 
 | 170 |     // Create audio data shared memory buffer for client. | 
 | 171 |     mAudioDataQueue = new SharedRingBuffer(); | 
| Phil Burk | 39f02dd | 2017-08-04 09:13:31 -0700 | [diff] [blame] | 172 |     result = mAudioDataQueue->allocate(calculateBytesPerFrame(), getBufferCapacity()); | 
| Phil Burk | ec89b2e | 2017-06-20 15:05:06 -0700 | [diff] [blame] | 173 |     if (result != AAUDIO_OK) { | 
| Phil Burk | 11e8d33 | 2017-05-24 09:59:02 -0700 | [diff] [blame] | 174 |         ALOGE("AAudioServiceStreamShared::open() could not allocate FIFO with %d frames", | 
| Phil Burk | 39f02dd | 2017-08-04 09:13:31 -0700 | [diff] [blame] | 175 |               getBufferCapacity()); | 
| Phil Burk | ec89b2e | 2017-06-20 15:05:06 -0700 | [diff] [blame] | 176 |         result = AAUDIO_ERROR_NO_MEMORY; | 
 | 177 |         goto error; | 
 | 178 |     } | 
 | 179 |  | 
 | 180 |     ALOGD("AAudioServiceStreamShared::open() actual rate = %d, channels = %d, deviceId = %d", | 
| Phil Burk | 39f02dd | 2017-08-04 09:13:31 -0700 | [diff] [blame] | 181 |           getSampleRate(), getSamplesPerFrame(), mServiceEndpoint->getDeviceId()); | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 182 |  | 
| Phil Burk | 11e8d33 | 2017-05-24 09:59:02 -0700 | [diff] [blame] | 183 |     result = mServiceEndpoint->registerStream(keep); | 
| Phil Burk | ec89b2e | 2017-06-20 15:05:06 -0700 | [diff] [blame] | 184 |     if (result != AAUDIO_OK) { | 
 | 185 |         goto error; | 
 | 186 |     } | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 187 |  | 
| Phil Burk | 5a26e66 | 2017-07-07 12:44:48 -0700 | [diff] [blame] | 188 |     setState(AAUDIO_STREAM_STATE_OPEN); | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 189 |     return AAUDIO_OK; | 
| Phil Burk | ec89b2e | 2017-06-20 15:05:06 -0700 | [diff] [blame] | 190 |  | 
 | 191 | error: | 
 | 192 |     close(); | 
 | 193 |     return result; | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 194 | } | 
 | 195 |  | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 196 |  | 
 | 197 | aaudio_result_t AAudioServiceStreamShared::close()  { | 
| Phil Burk | 39f02dd | 2017-08-04 09:13:31 -0700 | [diff] [blame] | 198 |     aaudio_result_t result = AAudioServiceStreamBase::close(); | 
| Phil Burk | 98d6d92 | 2017-07-06 11:52:45 -0700 | [diff] [blame] | 199 |  | 
| Phil Burk | 39f02dd | 2017-08-04 09:13:31 -0700 | [diff] [blame] | 200 |     delete mAudioDataQueue; | 
 | 201 |     mAudioDataQueue = nullptr; | 
| Eric Laurent | cb4dae2 | 2017-07-01 19:39:32 -0700 | [diff] [blame] | 202 |  | 
| Phil Burk | 39f02dd | 2017-08-04 09:13:31 -0700 | [diff] [blame] | 203 |     return result; | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 204 | } | 
 | 205 |  | 
 | 206 | /** | 
 | 207 |  * Get an immutable description of the data queue created by this service. | 
 | 208 |  */ | 
 | 209 | aaudio_result_t AAudioServiceStreamShared::getDownDataDescription(AudioEndpointParcelable &parcelable) | 
 | 210 | { | 
 | 211 |     // Gather information on the data queue. | 
 | 212 |     mAudioDataQueue->fillParcelable(parcelable, | 
 | 213 |                                     parcelable.mDownDataQueueParcelable); | 
 | 214 |     parcelable.mDownDataQueueParcelable.setFramesPerBurst(getFramesPerBurst()); | 
 | 215 |     return AAUDIO_OK; | 
 | 216 | } | 
 | 217 |  | 
| Phil Burk | 97350f9 | 2017-07-21 15:59:44 -0700 | [diff] [blame] | 218 | void AAudioServiceStreamShared::markTransferTime(Timestamp ×tamp) { | 
 | 219 |     mAtomicTimestamp.write(timestamp); | 
| Phil Burk | 71f35bb | 2017-04-13 16:05:07 -0700 | [diff] [blame] | 220 | } | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 221 |  | 
| Phil Burk | 39f02dd | 2017-08-04 09:13:31 -0700 | [diff] [blame] | 222 | // Get timestamp that was written by mixer or distributor. | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 223 | aaudio_result_t AAudioServiceStreamShared::getFreeRunningPosition(int64_t *positionFrames, | 
| Phil Burk | 39f02dd | 2017-08-04 09:13:31 -0700 | [diff] [blame] | 224 |                                                                   int64_t *timeNanos) { | 
 | 225 |     // TODO Get presentation timestamp from the HAL | 
| Phil Burk | 97350f9 | 2017-07-21 15:59:44 -0700 | [diff] [blame] | 226 |     if (mAtomicTimestamp.isValid()) { | 
 | 227 |         Timestamp timestamp = mAtomicTimestamp.read(); | 
 | 228 |         *positionFrames = timestamp.getPosition(); | 
 | 229 |         *timeNanos = timestamp.getNanoseconds(); | 
 | 230 |         return AAUDIO_OK; | 
 | 231 |     } else { | 
 | 232 |         return AAUDIO_ERROR_UNAVAILABLE; | 
 | 233 |     } | 
 | 234 | } | 
 | 235 |  | 
 | 236 | // Get timestamp from lower level service. | 
 | 237 | aaudio_result_t AAudioServiceStreamShared::getHardwareTimestamp(int64_t *positionFrames, | 
| Phil Burk | 39f02dd | 2017-08-04 09:13:31 -0700 | [diff] [blame] | 238 |                                                                 int64_t *timeNanos) { | 
| Phil Burk | 97350f9 | 2017-07-21 15:59:44 -0700 | [diff] [blame] | 239 |  | 
 | 240 |     aaudio_result_t result = mServiceEndpoint->getTimestamp(positionFrames, timeNanos); | 
 | 241 |     if (result == AAUDIO_OK) { | 
 | 242 |         *positionFrames -= mTimestampPositionOffset.load(); // Offset from shared MMAP stream | 
 | 243 |     } | 
 | 244 |     return result; | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 245 | } |