| 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 | fbf031e | 2017-10-12 15:58:31 -0700 | [diff] [blame] | 77 |         ALOGE("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 | fbf031e | 2017-10-12 15:58:31 -0700 | [diff] [blame] | 102 |         ALOGE("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 |  | 
| Phil Burk | 18142ae | 2020-07-28 12:44:37 -0700 | [diff] [blame] | 108 |     // Final range check. | 
| Phil Burk | ec89b2e | 2017-06-20 15:05:06 -0700 | [diff] [blame] | 109 |     if (capacityInFrames > MAX_FRAMES_PER_BUFFER) { | 
| Phil Burk | fbf031e | 2017-10-12 15:58:31 -0700 | [diff] [blame] | 110 |         ALOGE("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 | 7ba4655 | 2019-04-15 08:58:08 -0700 | [diff] [blame] | 114 |     ALOGV("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 | 15f97c9 | 2018-09-04 14:06:27 -0700 | [diff] [blame] | 123 |     if (request.getConstantConfiguration().getSharingMode() != AAUDIO_SHARING_MODE_SHARED) { | 
 | 124 |         ALOGE("%s() sharingMode mismatch %d", __func__, | 
 | 125 |               request.getConstantConfiguration().getSharingMode()); | 
 | 126 |         return AAUDIO_ERROR_INTERNAL; | 
 | 127 |     } | 
 | 128 |  | 
 | 129 |     aaudio_result_t result = AAudioServiceStreamBase::open(request); | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 130 |     if (result != AAUDIO_OK) { | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 131 |         return result; | 
 | 132 |     } | 
 | 133 |  | 
 | 134 |     const AAudioStreamConfiguration &configurationInput = request.getConstantConfiguration(); | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 135 |  | 
| Phil Burk | 6e2770e | 2018-05-01 13:03:52 -0700 | [diff] [blame] | 136 |     sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote(); | 
 | 137 |     if (endpoint == nullptr) { | 
 | 138 |         result = AAUDIO_ERROR_INVALID_STATE; | 
 | 139 |         goto error; | 
 | 140 |     } | 
 | 141 |  | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 142 |     // Is the request compatible with the shared endpoint? | 
| Phil Burk | 39f02dd | 2017-08-04 09:13:31 -0700 | [diff] [blame] | 143 |     setFormat(configurationInput.getFormat()); | 
| Phil Burk | 0127c1b | 2018-03-29 13:48:06 -0700 | [diff] [blame] | 144 |     if (getFormat() == AUDIO_FORMAT_DEFAULT) { | 
 | 145 |         setFormat(AUDIO_FORMAT_PCM_FLOAT); | 
 | 146 |     } else if (getFormat() != AUDIO_FORMAT_PCM_FLOAT) { | 
| Phil Burk | 7ba4655 | 2019-04-15 08:58:08 -0700 | [diff] [blame] | 147 |         ALOGD("%s() audio_format_t mAudioFormat = %d, need FLOAT", __func__, getFormat()); | 
| Phil Burk | ec89b2e | 2017-06-20 15:05:06 -0700 | [diff] [blame] | 148 |         result = AAUDIO_ERROR_INVALID_FORMAT; | 
 | 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 |     setSampleRate(configurationInput.getSampleRate()); | 
 | 153 |     if (getSampleRate() == AAUDIO_UNSPECIFIED) { | 
| Phil Burk | 6e2770e | 2018-05-01 13:03:52 -0700 | [diff] [blame] | 154 |         setSampleRate(endpoint->getSampleRate()); | 
 | 155 |     } else if (getSampleRate() != endpoint->getSampleRate()) { | 
| Phil Burk | 7ba4655 | 2019-04-15 08:58:08 -0700 | [diff] [blame] | 156 |         ALOGD("%s() mSampleRate = %d, need %d", | 
| Phil Burk | 6e2770e | 2018-05-01 13:03:52 -0700 | [diff] [blame] | 157 |               __func__, getSampleRate(), endpoint->getSampleRate()); | 
| Phil Burk | ec89b2e | 2017-06-20 15:05:06 -0700 | [diff] [blame] | 158 |         result = AAUDIO_ERROR_INVALID_RATE; | 
 | 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 |     setSamplesPerFrame(configurationInput.getSamplesPerFrame()); | 
 | 163 |     if (getSamplesPerFrame() == AAUDIO_UNSPECIFIED) { | 
| Phil Burk | 6e2770e | 2018-05-01 13:03:52 -0700 | [diff] [blame] | 164 |         setSamplesPerFrame(endpoint->getSamplesPerFrame()); | 
 | 165 |     } else if (getSamplesPerFrame() != endpoint->getSamplesPerFrame()) { | 
| Phil Burk | 7ba4655 | 2019-04-15 08:58:08 -0700 | [diff] [blame] | 166 |         ALOGD("%s() mSamplesPerFrame = %d, need %d", | 
| Phil Burk | 6e2770e | 2018-05-01 13:03:52 -0700 | [diff] [blame] | 167 |               __func__, getSamplesPerFrame(), endpoint->getSamplesPerFrame()); | 
| Phil Burk | ec89b2e | 2017-06-20 15:05:06 -0700 | [diff] [blame] | 168 |         result = AAUDIO_ERROR_OUT_OF_RANGE; | 
 | 169 |         goto error; | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 170 |     } | 
 | 171 |  | 
| Phil Burk | 39f02dd | 2017-08-04 09:13:31 -0700 | [diff] [blame] | 172 |     setBufferCapacity(calculateBufferCapacity(configurationInput.getBufferCapacity(), | 
 | 173 |                                      mFramesPerBurst)); | 
 | 174 |     if (getBufferCapacity() < 0) { | 
 | 175 |         result = getBufferCapacity(); // negative error code | 
 | 176 |         setBufferCapacity(0); | 
| Phil Burk | ec89b2e | 2017-06-20 15:05:06 -0700 | [diff] [blame] | 177 |         goto error; | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 178 |     } | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 179 |  | 
| Phil Burk | 523b304 | 2017-09-13 13:03:08 -0700 | [diff] [blame] | 180 |     { | 
 | 181 |         std::lock_guard<std::mutex> lock(mAudioDataQueueLock); | 
 | 182 |         // Create audio data shared memory buffer for client. | 
 | 183 |         mAudioDataQueue = new SharedRingBuffer(); | 
 | 184 |         result = mAudioDataQueue->allocate(calculateBytesPerFrame(), getBufferCapacity()); | 
 | 185 |         if (result != AAUDIO_OK) { | 
| Phil Burk | 55e5eab | 2018-04-10 15:16:38 -0700 | [diff] [blame] | 186 |             ALOGE("%s() could not allocate FIFO with %d frames", | 
 | 187 |                   __func__, getBufferCapacity()); | 
| Phil Burk | 523b304 | 2017-09-13 13:03:08 -0700 | [diff] [blame] | 188 |             result = AAUDIO_ERROR_NO_MEMORY; | 
 | 189 |             goto error; | 
 | 190 |         } | 
| Phil Burk | ec89b2e | 2017-06-20 15:05:06 -0700 | [diff] [blame] | 191 |     } | 
 | 192 |  | 
| Phil Burk | 6e2770e | 2018-05-01 13:03:52 -0700 | [diff] [blame] | 193 |     result = endpoint->registerStream(keep); | 
| Phil Burk | ec89b2e | 2017-06-20 15:05:06 -0700 | [diff] [blame] | 194 |     if (result != AAUDIO_OK) { | 
 | 195 |         goto error; | 
 | 196 |     } | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 197 |  | 
| Phil Burk | 5a26e66 | 2017-07-07 12:44:48 -0700 | [diff] [blame] | 198 |     setState(AAUDIO_STREAM_STATE_OPEN); | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 199 |     return AAUDIO_OK; | 
| Phil Burk | ec89b2e | 2017-06-20 15:05:06 -0700 | [diff] [blame] | 200 |  | 
 | 201 | error: | 
 | 202 |     close(); | 
 | 203 |     return result; | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 204 | } | 
 | 205 |  | 
| Phil Burk | 7ebbc11 | 2020-05-13 15:55:17 -0700 | [diff] [blame] | 206 | aaudio_result_t AAudioServiceStreamShared::close_l()  { | 
 | 207 |     aaudio_result_t result = AAudioServiceStreamBase::close_l(); | 
| Phil Burk | 98d6d92 | 2017-07-06 11:52:45 -0700 | [diff] [blame] | 208 |  | 
| Phil Burk | 523b304 | 2017-09-13 13:03:08 -0700 | [diff] [blame] | 209 |     { | 
 | 210 |         std::lock_guard<std::mutex> lock(mAudioDataQueueLock); | 
 | 211 |         delete mAudioDataQueue; | 
 | 212 |         mAudioDataQueue = nullptr; | 
 | 213 |     } | 
| Eric Laurent | cb4dae2 | 2017-07-01 19:39:32 -0700 | [diff] [blame] | 214 |  | 
| Phil Burk | 39f02dd | 2017-08-04 09:13:31 -0700 | [diff] [blame] | 215 |     return result; | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 216 | } | 
 | 217 |  | 
 | 218 | /** | 
 | 219 |  * Get an immutable description of the data queue created by this service. | 
 | 220 |  */ | 
| Phil Burk | 523b304 | 2017-09-13 13:03:08 -0700 | [diff] [blame] | 221 | aaudio_result_t AAudioServiceStreamShared::getAudioDataDescription( | 
 | 222 |         AudioEndpointParcelable &parcelable) | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 223 | { | 
| Phil Burk | 523b304 | 2017-09-13 13:03:08 -0700 | [diff] [blame] | 224 |     std::lock_guard<std::mutex> lock(mAudioDataQueueLock); | 
 | 225 |     if (mAudioDataQueue == nullptr) { | 
| Phil Burk | 7ba4655 | 2019-04-15 08:58:08 -0700 | [diff] [blame] | 226 |         ALOGW("%s(): mUpMessageQueue null! - stream not open", __func__); | 
| Phil Burk | 523b304 | 2017-09-13 13:03:08 -0700 | [diff] [blame] | 227 |         return AAUDIO_ERROR_NULL; | 
 | 228 |     } | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 229 |     // Gather information on the data queue. | 
 | 230 |     mAudioDataQueue->fillParcelable(parcelable, | 
 | 231 |                                     parcelable.mDownDataQueueParcelable); | 
 | 232 |     parcelable.mDownDataQueueParcelable.setFramesPerBurst(getFramesPerBurst()); | 
 | 233 |     return AAUDIO_OK; | 
 | 234 | } | 
 | 235 |  | 
| Phil Burk | 97350f9 | 2017-07-21 15:59:44 -0700 | [diff] [blame] | 236 | void AAudioServiceStreamShared::markTransferTime(Timestamp ×tamp) { | 
| Phil Burk | a53ffa6 | 2018-10-10 16:21:37 -0700 | [diff] [blame] | 237 |     mAtomicStreamTimestamp.write(timestamp); | 
| Phil Burk | 71f35bb | 2017-04-13 16:05:07 -0700 | [diff] [blame] | 238 | } | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 239 |  | 
| Phil Burk | 39f02dd | 2017-08-04 09:13:31 -0700 | [diff] [blame] | 240 | // Get timestamp that was written by mixer or distributor. | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 241 | aaudio_result_t AAudioServiceStreamShared::getFreeRunningPosition(int64_t *positionFrames, | 
| Phil Burk | 39f02dd | 2017-08-04 09:13:31 -0700 | [diff] [blame] | 242 |                                                                   int64_t *timeNanos) { | 
 | 243 |     // TODO Get presentation timestamp from the HAL | 
| Phil Burk | a53ffa6 | 2018-10-10 16:21:37 -0700 | [diff] [blame] | 244 |     if (mAtomicStreamTimestamp.isValid()) { | 
 | 245 |         Timestamp timestamp = mAtomicStreamTimestamp.read(); | 
| Phil Burk | 97350f9 | 2017-07-21 15:59:44 -0700 | [diff] [blame] | 246 |         *positionFrames = timestamp.getPosition(); | 
 | 247 |         *timeNanos = timestamp.getNanoseconds(); | 
 | 248 |         return AAUDIO_OK; | 
 | 249 |     } else { | 
 | 250 |         return AAUDIO_ERROR_UNAVAILABLE; | 
 | 251 |     } | 
 | 252 | } | 
 | 253 |  | 
 | 254 | // Get timestamp from lower level service. | 
 | 255 | aaudio_result_t AAudioServiceStreamShared::getHardwareTimestamp(int64_t *positionFrames, | 
| Phil Burk | 39f02dd | 2017-08-04 09:13:31 -0700 | [diff] [blame] | 256 |                                                                 int64_t *timeNanos) { | 
| Phil Burk | 97350f9 | 2017-07-21 15:59:44 -0700 | [diff] [blame] | 257 |  | 
| Phil Burk | bcc3674 | 2017-08-31 17:24:51 -0700 | [diff] [blame] | 258 |     int64_t position = 0; | 
| Phil Burk | 6e2770e | 2018-05-01 13:03:52 -0700 | [diff] [blame] | 259 |     sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote(); | 
 | 260 |     if (endpoint == nullptr) { | 
| Phil Burk | 7ba4655 | 2019-04-15 08:58:08 -0700 | [diff] [blame] | 261 |         ALOGW("%s() has no endpoint", __func__); | 
| Phil Burk | 6e2770e | 2018-05-01 13:03:52 -0700 | [diff] [blame] | 262 |         return AAUDIO_ERROR_INVALID_STATE; | 
 | 263 |     } | 
 | 264 |  | 
 | 265 |     aaudio_result_t result = endpoint->getTimestamp(&position, timeNanos); | 
| Phil Burk | 97350f9 | 2017-07-21 15:59:44 -0700 | [diff] [blame] | 266 |     if (result == AAUDIO_OK) { | 
| Phil Burk | bcc3674 | 2017-08-31 17:24:51 -0700 | [diff] [blame] | 267 |         int64_t offset = mTimestampPositionOffset.load(); | 
 | 268 |         // TODO, do not go below starting value | 
 | 269 |         position -= offset; // Offset from shared MMAP stream | 
| Phil Burk | 55e5eab | 2018-04-10 15:16:38 -0700 | [diff] [blame] | 270 |         ALOGV("%s() %8lld = %8lld - %8lld", | 
 | 271 |               __func__, (long long) position, (long long) (position + offset), (long long) offset); | 
| Phil Burk | 97350f9 | 2017-07-21 15:59:44 -0700 | [diff] [blame] | 272 |     } | 
| Phil Burk | bcc3674 | 2017-08-31 17:24:51 -0700 | [diff] [blame] | 273 |     *positionFrames = position; | 
| Phil Burk | 97350f9 | 2017-07-21 15:59:44 -0700 | [diff] [blame] | 274 |     return result; | 
| Phil Burk | c0c70e3 | 2017-02-09 13:18:38 -0800 | [diff] [blame] | 275 | } |