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 <inttypes.h>
23 #include <iomanip>
24 #include <iostream>
25 #include <stdint.h>
26
27 #include <com_android_media_aaudio.h>
28 #include <utils/String16.h>
29 #include <media/nbaio/AudioStreamOutSink.h>
30 #include <media/MmapStreamInterface.h>
31
32 #include "binding/AudioEndpointParcelable.h"
33 #include "utility/AAudioUtilities.h"
34
35 #include "AAudioServiceEndpointMMAP.h"
36 #include "AAudioServiceStreamBase.h"
37 #include "AAudioServiceStreamMMAP.h"
38 #include "SharedMemoryProxy.h"
39
40 using android::base::unique_fd;
41 using namespace android;
42 using namespace aaudio;
43
44 /**
45 * Service Stream that uses an MMAP buffer.
46 */
47
AAudioServiceStreamMMAP(android::AAudioService & aAudioService,bool inService)48 AAudioServiceStreamMMAP::AAudioServiceStreamMMAP(android::AAudioService &aAudioService,
49 bool inService)
50 : AAudioServiceStreamBase(aAudioService)
51 , mInService(inService) {
52 }
53
54 // Open stream on HAL and pass information about the shared memory buffer back to the client.
open(const aaudio::AAudioStreamRequest & request)55 aaudio_result_t AAudioServiceStreamMMAP::open(const aaudio::AAudioStreamRequest &request) {
56
57 sp<AAudioServiceStreamMMAP> keep(this);
58
59 if (request.getConstantConfiguration().getSharingMode() != AAUDIO_SHARING_MODE_EXCLUSIVE) {
60 ALOGE("%s() sharingMode mismatch %d", __func__,
61 request.getConstantConfiguration().getSharingMode());
62 return AAUDIO_ERROR_INTERNAL;
63 }
64
65 aaudio_result_t result = AAudioServiceStreamBase::open(request);
66 if (result != AAUDIO_OK) {
67 return result;
68 }
69
70 sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
71 if (endpoint == nullptr) {
72 ALOGE("%s() has no endpoint", __func__);
73 return AAUDIO_ERROR_INVALID_STATE;
74 }
75
76 result = endpoint->registerStream(keep);
77 if (result != AAUDIO_OK) {
78 return result;
79 }
80
81 setState(AAUDIO_STREAM_STATE_OPEN);
82
83 return AAUDIO_OK;
84 }
85
86 // Start the flow of data.
startDevice_l()87 aaudio_result_t AAudioServiceStreamMMAP::startDevice_l() {
88 aaudio_result_t result = AAudioServiceStreamBase::startDevice_l();
89 if (!mInService && result == AAUDIO_OK) {
90 // Note that this can sometimes take 200 to 300 msec for a cold start!
91 result = startClient_l(
92 mMmapClient, nullptr /*const audio_attributes_t* */, &mClientHandle);
93 }
94 return result;
95 }
96
97 // Stop the flow of data such that start() can resume with loss of data.
pause_l()98 aaudio_result_t AAudioServiceStreamMMAP::pause_l() {
99 if (!isRunning()) {
100 return AAUDIO_OK;
101 }
102 aaudio_result_t result = AAudioServiceStreamBase::pause_l();
103 // TODO put before base::pause()?
104 if (!mInService) {
105 (void) stopClient_l(mClientHandle);
106 }
107 return result;
108 }
109
stop_l()110 aaudio_result_t AAudioServiceStreamMMAP::stop_l() {
111 if (!isRunning()) {
112 return AAUDIO_OK;
113 }
114 aaudio_result_t result = AAudioServiceStreamBase::stop_l();
115 // TODO put before base::stop()?
116 if (!mInService) {
117 (void) stopClient_l(mClientHandle);
118 }
119 return result;
120 }
121
standby_l()122 aaudio_result_t AAudioServiceStreamMMAP::standby_l() {
123 sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
124 if (endpoint == nullptr) {
125 ALOGE("%s() has no endpoint", __func__);
126 return AAUDIO_ERROR_INVALID_STATE;
127 }
128 aaudio_result_t result = endpoint->standby();
129 if (result == AAUDIO_OK) {
130 setStandby_l(true);
131 }
132 return result;
133 }
134
exitStandby_l(AudioEndpointParcelable * parcelable)135 aaudio_result_t AAudioServiceStreamMMAP::exitStandby_l(AudioEndpointParcelable* parcelable) {
136 sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
137 if (endpoint == nullptr) {
138 ALOGE("%s() has no endpoint", __func__);
139 return AAUDIO_ERROR_INVALID_STATE;
140 }
141 aaudio_result_t result = endpoint->exitStandby(parcelable);
142 if (result == AAUDIO_OK) {
143 setStandby_l(false);
144 } else {
145 ALOGE("%s failed, result %d, disconnecting stream.", __func__, result);
146 disconnect_l();
147 }
148 return result;
149 }
150
startClient(const android::AudioClient & client,const audio_attributes_t * attr,audio_port_handle_t * portHandlePtr)151 aaudio_result_t AAudioServiceStreamMMAP::startClient(const android::AudioClient& client,
152 const audio_attributes_t *attr,
153 audio_port_handle_t *portHandlePtr) {
154 if (com::android::media::aaudio::start_stop_client_from_command_thread()) {
155 return sendStartClientCommand(client, attr, portHandlePtr);
156 } else {
157 sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
158 if (endpoint == nullptr) {
159 ALOGE("%s() has no endpoint", __func__);
160 return AAUDIO_ERROR_INVALID_STATE;
161 }
162 // Start the client on behalf of the application. Generate a new porthandle.
163 aaudio_result_t result = endpoint->startClient(client, attr, portHandlePtr);
164 ALOGD("%s() flag off, got port %d", __func__,
165 ((portHandlePtr == nullptr) ? -1 : *portHandlePtr));
166 return result;
167 }
168 }
169
stopClient(audio_port_handle_t clientHandle)170 aaudio_result_t AAudioServiceStreamMMAP::stopClient(audio_port_handle_t clientHandle) {
171 if (com::android::media::aaudio::start_stop_client_from_command_thread()) {
172 return sendStopClientCommand(clientHandle);
173 } else {
174 sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
175 if (endpoint == nullptr) {
176 ALOGE("%s() has no endpoint", __func__);
177 return AAUDIO_ERROR_INVALID_STATE;
178 }
179 aaudio_result_t result = endpoint->stopClient(clientHandle);
180 return result;
181 }
182 }
183
startClient_l(const android::AudioClient & client,const audio_attributes_t * attr,audio_port_handle_t * clientHandle)184 aaudio_result_t AAudioServiceStreamMMAP::startClient_l(const android::AudioClient& client,
185 const audio_attributes_t *attr,
186 audio_port_handle_t *clientHandle) {
187 sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
188 if (endpoint == nullptr) {
189 ALOGE("%s() has no endpoint", __func__);
190 return AAUDIO_ERROR_INVALID_STATE;
191 }
192 // Start the client on behalf of the application. Generate a new porthandle.
193 aaudio_result_t result = endpoint->startClient(client, attr, clientHandle);
194 return result;
195 }
196
stopClient_l(audio_port_handle_t clientHandle)197 aaudio_result_t AAudioServiceStreamMMAP::stopClient_l(audio_port_handle_t clientHandle) {
198 sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
199 if (endpoint == nullptr) {
200 ALOGE("%s() has no endpoint", __func__);
201 return AAUDIO_ERROR_INVALID_STATE;
202 }
203 aaudio_result_t result = endpoint->stopClient(clientHandle);
204 return result;
205 }
206
207 // Get free-running DSP or DMA hardware position from the HAL.
getFreeRunningPosition_l(int64_t * positionFrames,int64_t * timeNanos)208 aaudio_result_t AAudioServiceStreamMMAP::getFreeRunningPosition_l(int64_t *positionFrames,
209 int64_t *timeNanos) {
210 sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
211 if (endpoint == nullptr) {
212 ALOGE("%s() has no endpoint", __func__);
213 return AAUDIO_ERROR_INVALID_STATE;
214 }
215 sp<AAudioServiceEndpointMMAP> serviceEndpointMMAP =
216 static_cast<AAudioServiceEndpointMMAP *>(endpoint.get());
217
218 aaudio_result_t result = serviceEndpointMMAP->getFreeRunningPosition(positionFrames, timeNanos);
219 if (result == AAUDIO_OK) {
220 Timestamp timestamp(*positionFrames, *timeNanos);
221 mAtomicStreamTimestamp.write(timestamp);
222 *positionFrames = timestamp.getPosition();
223 *timeNanos = timestamp.getNanoseconds();
224 } else if (result != AAUDIO_ERROR_UNAVAILABLE) {
225 disconnect_l();
226 }
227 return result;
228 }
229
230 // Get timestamp from presentation position.
231 // If it fails, get timestamp that was written by getFreeRunningPosition()
getHardwareTimestamp_l(int64_t * positionFrames,int64_t * timeNanos)232 aaudio_result_t AAudioServiceStreamMMAP::getHardwareTimestamp_l(int64_t *positionFrames,
233 int64_t *timeNanos) {
234 sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
235 if (endpoint == nullptr) {
236 ALOGE("%s() has no endpoint", __func__);
237 return AAUDIO_ERROR_INVALID_STATE;
238 }
239 sp<AAudioServiceEndpointMMAP> serviceEndpointMMAP =
240 static_cast<AAudioServiceEndpointMMAP *>(endpoint.get());
241
242 uint64_t position;
243 aaudio_result_t result = serviceEndpointMMAP->getExternalPosition(&position, timeNanos);
244 if (result == AAUDIO_OK) {
245 ALOGV("%s() getExternalPosition() says pos = %" PRIi64 ", time = %" PRIi64,
246 __func__, position, *timeNanos);
247 *positionFrames = (int64_t) position;
248 return AAUDIO_OK;
249 } else {
250 ALOGV("%s() getExternalPosition() returns error %d", __func__, result);
251 }
252
253 if (mAtomicStreamTimestamp.isValid()) {
254 Timestamp timestamp = mAtomicStreamTimestamp.read();
255 *positionFrames = timestamp.getPosition();
256 *timeNanos = timestamp.getNanoseconds() + serviceEndpointMMAP->getHardwareTimeOffsetNanos();
257 return AAUDIO_OK;
258 } else {
259 return AAUDIO_ERROR_UNAVAILABLE;
260 }
261 }
262
263 // Get an immutable description of the data queue from the HAL.
getAudioDataDescription_l(AudioEndpointParcelable * parcelable)264 aaudio_result_t AAudioServiceStreamMMAP::getAudioDataDescription_l(
265 AudioEndpointParcelable* parcelable)
266 {
267 sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
268 if (endpoint == nullptr) {
269 ALOGE("%s() has no endpoint", __func__);
270 return AAUDIO_ERROR_INVALID_STATE;
271 }
272 sp<AAudioServiceEndpointMMAP> serviceEndpointMMAP =
273 static_cast<AAudioServiceEndpointMMAP *>(endpoint.get());
274 return serviceEndpointMMAP->getDownDataDescription(parcelable);
275 }
276
nextDataReportTime_l()277 int64_t AAudioServiceStreamMMAP::nextDataReportTime_l() {
278 sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
279 if (endpoint == nullptr) {
280 ALOGE("%s() has no endpoint", __func__);
281 return std::numeric_limits<int64_t>::max();
282 }
283 sp<AAudioServiceEndpointMMAP> serviceEndpointMMAP =
284 static_cast<AAudioServiceEndpointMMAP *>(endpoint.get());
285 return serviceEndpointMMAP->nextDataReportTime();
286 }
287
reportData_l()288 void AAudioServiceStreamMMAP::reportData_l() {
289 sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
290 if (endpoint == nullptr) {
291 ALOGE("%s() has no endpoint", __func__);
292 return;
293 }
294 sp<AAudioServiceEndpointMMAP> serviceEndpointMMAP =
295 static_cast<AAudioServiceEndpointMMAP *>(endpoint.get());
296 return serviceEndpointMMAP->reportData();
297 }
298