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 17 #define LOG_TAG "AAudioServiceStreamMMAP" 18 //#define LOG_NDEBUG 0 19 #include <utils/Log.h> 20 21 #include <atomic> 22 #include <iomanip> 23 #include <iostream> 24 #include <stdint.h> 25 26 #include <utils/String16.h> 27 #include <media/nbaio/AudioStreamOutSink.h> 28 #include <media/MmapStreamInterface.h> 29 30 #include "binding/AudioEndpointParcelable.h" 31 #include "utility/AAudioUtilities.h" 32 33 #include "AAudioServiceEndpointMMAP.h" 34 #include "AAudioServiceStreamBase.h" 35 #include "AAudioServiceStreamMMAP.h" 36 #include "SharedMemoryProxy.h" 37 38 using android::base::unique_fd; 39 using namespace android; 40 using namespace aaudio; 41 42 /** 43 * Service Stream that uses an MMAP buffer. 44 */ 45 46 AAudioServiceStreamMMAP::AAudioServiceStreamMMAP(android::AAudioService &aAudioService, 47 bool inService) 48 : AAudioServiceStreamBase(aAudioService) 49 , mInService(inService) { 50 } 51 52 aaudio_result_t AAudioServiceStreamMMAP::close() { 53 if (getState() == AAUDIO_STREAM_STATE_CLOSED) { 54 return AAUDIO_OK; 55 } 56 57 stop(); 58 59 return AAudioServiceStreamBase::close(); 60 } 61 62 // Open stream on HAL and pass information about the shared memory buffer back to the client. 63 aaudio_result_t AAudioServiceStreamMMAP::open(const aaudio::AAudioStreamRequest &request) { 64 65 sp<AAudioServiceStreamMMAP> keep(this); 66 67 if (request.getConstantConfiguration().getSharingMode() != AAUDIO_SHARING_MODE_EXCLUSIVE) { 68 ALOGE("%s() sharingMode mismatch %d", __func__, 69 request.getConstantConfiguration().getSharingMode()); 70 return AAUDIO_ERROR_INTERNAL; 71 } 72 73 aaudio_result_t result = AAudioServiceStreamBase::open(request); 74 if (result != AAUDIO_OK) { 75 return result; 76 } 77 78 sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote(); 79 if (endpoint == nullptr) { 80 ALOGE("%s() has no endpoint", __func__); 81 return AAUDIO_ERROR_INVALID_STATE; 82 } 83 84 result = endpoint->registerStream(keep); 85 if (result != AAUDIO_OK) { 86 return result; 87 } 88 89 setState(AAUDIO_STREAM_STATE_OPEN); 90 91 return AAUDIO_OK; 92 } 93 94 // Start the flow of data. 95 aaudio_result_t AAudioServiceStreamMMAP::startDevice() { 96 aaudio_result_t result = AAudioServiceStreamBase::startDevice(); 97 if (!mInService && result == AAUDIO_OK) { 98 // Note that this can sometimes take 200 to 300 msec for a cold start! 99 result = startClient(mMmapClient, &mClientHandle); 100 } 101 return result; 102 } 103 104 // Stop the flow of data such that start() can resume with loss of data. 105 aaudio_result_t AAudioServiceStreamMMAP::pause() { 106 if (!isRunning()) { 107 return AAUDIO_OK; 108 } 109 aaudio_result_t result = AAudioServiceStreamBase::pause(); 110 // TODO put before base::pause()? 111 if (!mInService) { 112 (void) stopClient(mClientHandle); 113 } 114 return result; 115 } 116 117 aaudio_result_t AAudioServiceStreamMMAP::stop() { 118 if (!isRunning()) { 119 return AAUDIO_OK; 120 } 121 aaudio_result_t result = AAudioServiceStreamBase::stop(); 122 // TODO put before base::stop()? 123 if (!mInService) { 124 (void) stopClient(mClientHandle); 125 } 126 return result; 127 } 128 129 aaudio_result_t AAudioServiceStreamMMAP::startClient(const android::AudioClient& client, 130 audio_port_handle_t *clientHandle) { 131 sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote(); 132 if (endpoint == nullptr) { 133 ALOGE("%s() has no endpoint", __func__); 134 return AAUDIO_ERROR_INVALID_STATE; 135 } 136 // Start the client on behalf of the application. Generate a new porthandle. 137 aaudio_result_t result = endpoint->startClient(client, clientHandle); 138 return result; 139 } 140 141 aaudio_result_t AAudioServiceStreamMMAP::stopClient(audio_port_handle_t clientHandle) { 142 sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote(); 143 if (endpoint == nullptr) { 144 ALOGE("%s() has no endpoint", __func__); 145 return AAUDIO_ERROR_INVALID_STATE; 146 } 147 aaudio_result_t result = endpoint->stopClient(clientHandle); 148 return result; 149 } 150 151 // Get free-running DSP or DMA hardware position from the HAL. 152 aaudio_result_t AAudioServiceStreamMMAP::getFreeRunningPosition(int64_t *positionFrames, 153 int64_t *timeNanos) { 154 sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote(); 155 if (endpoint == nullptr) { 156 ALOGE("%s() has no endpoint", __func__); 157 return AAUDIO_ERROR_INVALID_STATE; 158 } 159 sp<AAudioServiceEndpointMMAP> serviceEndpointMMAP = 160 static_cast<AAudioServiceEndpointMMAP *>(endpoint.get()); 161 162 aaudio_result_t result = serviceEndpointMMAP->getFreeRunningPosition(positionFrames, timeNanos); 163 if (result == AAUDIO_OK) { 164 Timestamp timestamp(*positionFrames, *timeNanos); 165 mAtomicStreamTimestamp.write(timestamp); 166 *positionFrames = timestamp.getPosition(); 167 *timeNanos = timestamp.getNanoseconds(); 168 } else if (result != AAUDIO_ERROR_UNAVAILABLE) { 169 disconnect(); 170 } 171 return result; 172 } 173 174 // Get timestamp that was written by getFreeRunningPosition() 175 aaudio_result_t AAudioServiceStreamMMAP::getHardwareTimestamp(int64_t *positionFrames, 176 int64_t *timeNanos) { 177 178 sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote(); 179 if (endpoint == nullptr) { 180 ALOGE("%s() has no endpoint", __func__); 181 return AAUDIO_ERROR_INVALID_STATE; 182 } 183 sp<AAudioServiceEndpointMMAP> serviceEndpointMMAP = 184 static_cast<AAudioServiceEndpointMMAP *>(endpoint.get()); 185 186 // TODO Get presentation timestamp from the HAL 187 if (mAtomicStreamTimestamp.isValid()) { 188 Timestamp timestamp = mAtomicStreamTimestamp.read(); 189 *positionFrames = timestamp.getPosition(); 190 *timeNanos = timestamp.getNanoseconds() + serviceEndpointMMAP->getHardwareTimeOffsetNanos(); 191 return AAUDIO_OK; 192 } else { 193 return AAUDIO_ERROR_UNAVAILABLE; 194 } 195 } 196 197 // Get an immutable description of the data queue from the HAL. 198 aaudio_result_t AAudioServiceStreamMMAP::getAudioDataDescription( 199 AudioEndpointParcelable &parcelable) 200 { 201 sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote(); 202 if (endpoint == nullptr) { 203 ALOGE("%s() has no endpoint", __func__); 204 return AAUDIO_ERROR_INVALID_STATE; 205 } 206 sp<AAudioServiceEndpointMMAP> serviceEndpointMMAP = 207 static_cast<AAudioServiceEndpointMMAP *>(endpoint.get()); 208 return serviceEndpointMMAP->getDownDataDescription(parcelable); 209 } 210