blob: 5203e50675825f716ab5cab25d10b18c314f9428 [file] [log] [blame]
Phil Burkc0c70e32017-02-09 13:18:38 -08001/*
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 Laurentcb4dae22017-07-01 19:39:32 -070017#define LOG_TAG "AAudioServiceStreamMMAP"
Phil Burkc0c70e32017-02-09 13:18:38 -080018//#define LOG_NDEBUG 0
19#include <utils/Log.h>
20
21#include <atomic>
Phil Burkf95ed732020-09-30 18:48:17 +000022#include <inttypes.h>
Phil Burk39f02dd2017-08-04 09:13:31 -070023#include <iomanip>
24#include <iostream>
Phil Burkc0c70e32017-02-09 13:18:38 -080025#include <stdint.h>
26
jiabinb86b4032024-05-23 18:03:41 +000027#include <com_android_media_aaudio.h>
Phil Burkc0c70e32017-02-09 13:18:38 -080028#include <utils/String16.h>
29#include <media/nbaio/AudioStreamOutSink.h>
30#include <media/MmapStreamInterface.h>
31
Phil Burk39f02dd2017-08-04 09:13:31 -070032#include "binding/AudioEndpointParcelable.h"
33#include "utility/AAudioUtilities.h"
34
35#include "AAudioServiceEndpointMMAP.h"
Phil Burkc0c70e32017-02-09 13:18:38 -080036#include "AAudioServiceStreamBase.h"
37#include "AAudioServiceStreamMMAP.h"
Phil Burkc0c70e32017-02-09 13:18:38 -080038#include "SharedMemoryProxy.h"
Phil Burkc0c70e32017-02-09 13:18:38 -080039
Phil Burke72481c2017-08-08 13:20:45 -070040using android::base::unique_fd;
Phil Burkc0c70e32017-02-09 13:18:38 -080041using namespace android;
42using namespace aaudio;
43
Phil Burkc0c70e32017-02-09 13:18:38 -080044/**
Phil Burk11e8d332017-05-24 09:59:02 -070045 * Service Stream that uses an MMAP buffer.
Phil Burkc0c70e32017-02-09 13:18:38 -080046 */
47
Phil Burk39f02dd2017-08-04 09:13:31 -070048AAudioServiceStreamMMAP::AAudioServiceStreamMMAP(android::AAudioService &aAudioService,
Eric Laurentcb4dae22017-07-01 19:39:32 -070049 bool inService)
Phil Burk39f02dd2017-08-04 09:13:31 -070050 : AAudioServiceStreamBase(aAudioService)
Eric Laurentcb4dae22017-07-01 19:39:32 -070051 , mInService(inService) {
Phil Burkc0c70e32017-02-09 13:18:38 -080052}
53
Phil Burkc0c70e32017-02-09 13:18:38 -080054// Open stream on HAL and pass information about the shared memory buffer back to the client.
Phil Burk39f02dd2017-08-04 09:13:31 -070055aaudio_result_t AAudioServiceStreamMMAP::open(const aaudio::AAudioStreamRequest &request) {
Phil Burkc0c70e32017-02-09 13:18:38 -080056
Phil Burk39f02dd2017-08-04 09:13:31 -070057 sp<AAudioServiceStreamMMAP> keep(this);
58
Phil Burk15f97c92018-09-04 14:06:27 -070059 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);
Phil Burkc0c70e32017-02-09 13:18:38 -080066 if (result != AAUDIO_OK) {
Phil Burkc0c70e32017-02-09 13:18:38 -080067 return result;
68 }
69
Phil Burk6e2770e2018-05-01 13:03:52 -070070 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);
Phil Burk39f02dd2017-08-04 09:13:31 -070077 if (result != AAUDIO_OK) {
Phil Burk6e2770e2018-05-01 13:03:52 -070078 return result;
Phil Burkc0c70e32017-02-09 13:18:38 -080079 }
Phil Burkc0c70e32017-02-09 13:18:38 -080080
Phil Burk5a26e662017-07-07 12:44:48 -070081 setState(AAUDIO_STREAM_STATE_OPEN);
Phil Burk39f02dd2017-08-04 09:13:31 -070082
Phil Burkc0c70e32017-02-09 13:18:38 -080083 return AAUDIO_OK;
84}
85
Phil Burkfbf031e2017-10-12 15:58:31 -070086// Start the flow of data.
jiabinb86b4032024-05-23 18:03:41 +000087aaudio_result_t AAudioServiceStreamMMAP::startDevice_l() {
88 aaudio_result_t result = AAudioServiceStreamBase::startDevice_l();
Phil Burk39f02dd2017-08-04 09:13:31 -070089 if (!mInService && result == AAUDIO_OK) {
Phil Burkbcc36742017-08-31 17:24:51 -070090 // Note that this can sometimes take 200 to 300 msec for a cold start!
jiabinb86b4032024-05-23 18:03:41 +000091 result = startClient_l(
92 mMmapClient, nullptr /*const audio_attributes_t* */, &mClientHandle);
Phil Burkc0c70e32017-02-09 13:18:38 -080093 }
94 return result;
95}
96
Phil Burkfbf031e2017-10-12 15:58:31 -070097// Stop the flow of data such that start() can resume with loss of data.
Phil Burk7ebbc112020-05-13 15:55:17 -070098aaudio_result_t AAudioServiceStreamMMAP::pause_l() {
Eric Laurentcb4dae22017-07-01 19:39:32 -070099 if (!isRunning()) {
100 return AAUDIO_OK;
101 }
Phil Burk7ebbc112020-05-13 15:55:17 -0700102 aaudio_result_t result = AAudioServiceStreamBase::pause_l();
Phil Burk39f02dd2017-08-04 09:13:31 -0700103 // TODO put before base::pause()?
Eric Laurentcb4dae22017-07-01 19:39:32 -0700104 if (!mInService) {
jiabinb86b4032024-05-23 18:03:41 +0000105 (void) stopClient_l(mClientHandle);
Eric Laurentcb4dae22017-07-01 19:39:32 -0700106 }
Phil Burk39f02dd2017-08-04 09:13:31 -0700107 return result;
Phil Burkc0c70e32017-02-09 13:18:38 -0800108}
109
Phil Burk7ebbc112020-05-13 15:55:17 -0700110aaudio_result_t AAudioServiceStreamMMAP::stop_l() {
Eric Laurentcb4dae22017-07-01 19:39:32 -0700111 if (!isRunning()) {
112 return AAUDIO_OK;
113 }
Phil Burk7ebbc112020-05-13 15:55:17 -0700114 aaudio_result_t result = AAudioServiceStreamBase::stop_l();
Phil Burk39f02dd2017-08-04 09:13:31 -0700115 // TODO put before base::stop()?
Eric Laurentcb4dae22017-07-01 19:39:32 -0700116 if (!mInService) {
jiabinb86b4032024-05-23 18:03:41 +0000117 (void) stopClient_l(mClientHandle);
Eric Laurentcb4dae22017-07-01 19:39:32 -0700118 }
Phil Burk39f02dd2017-08-04 09:13:31 -0700119 return result;
Phil Burkc0c70e32017-02-09 13:18:38 -0800120}
121
jiabinf7f06152021-11-22 18:10:14 +0000122aaudio_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
135aaudio_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
Eric Laurentcb4dae22017-07-01 19:39:32 -0700151aaudio_result_t AAudioServiceStreamMMAP::startClient(const android::AudioClient& client,
jiabind1f1cb62020-03-24 11:57:57 -0700152 const audio_attributes_t *attr,
Phil Burkcffd50f2024-06-03 23:52:19 +0000153 audio_port_handle_t *portHandlePtr) {
jiabinb86b4032024-05-23 18:03:41 +0000154 if (com::android::media::aaudio::start_stop_client_from_command_thread()) {
Phil Burkcffd50f2024-06-03 23:52:19 +0000155 return sendStartClientCommand(client, attr, portHandlePtr);
jiabinb86b4032024-05-23 18:03:41 +0000156 } 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.
Phil Burkcffd50f2024-06-03 23:52:19 +0000163 aaudio_result_t result = endpoint->startClient(client, attr, portHandlePtr);
164 ALOGD("%s() flag off, got port %d", __func__,
165 ((portHandlePtr == nullptr) ? -1 : *portHandlePtr));
jiabinb86b4032024-05-23 18:03:41 +0000166 return result;
167 }
168}
169
170aaudio_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
184aaudio_result_t AAudioServiceStreamMMAP::startClient_l(const android::AudioClient& client,
185 const audio_attributes_t *attr,
186 audio_port_handle_t *clientHandle) {
Phil Burk6e2770e2018-05-01 13:03:52 -0700187 sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
188 if (endpoint == nullptr) {
189 ALOGE("%s() has no endpoint", __func__);
190 return AAUDIO_ERROR_INVALID_STATE;
191 }
Phil Burkbcc36742017-08-31 17:24:51 -0700192 // Start the client on behalf of the application. Generate a new porthandle.
jiabind1f1cb62020-03-24 11:57:57 -0700193 aaudio_result_t result = endpoint->startClient(client, attr, clientHandle);
Phil Burk39f02dd2017-08-04 09:13:31 -0700194 return result;
Eric Laurentcb4dae22017-07-01 19:39:32 -0700195}
196
jiabinb86b4032024-05-23 18:03:41 +0000197aaudio_result_t AAudioServiceStreamMMAP::stopClient_l(audio_port_handle_t clientHandle) {
Phil Burk6e2770e2018-05-01 13:03:52 -0700198 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);
Phil Burk39f02dd2017-08-04 09:13:31 -0700204 return result;
Eric Laurentcb4dae22017-07-01 19:39:32 -0700205}
206
Phil Burk97350f92017-07-21 15:59:44 -0700207// Get free-running DSP or DMA hardware position from the HAL.
jiabin2a594622021-10-14 00:32:25 +0000208aaudio_result_t AAudioServiceStreamMMAP::getFreeRunningPosition_l(int64_t *positionFrames,
Phil Burk39f02dd2017-08-04 09:13:31 -0700209 int64_t *timeNanos) {
Phil Burk6e2770e2018-05-01 13:03:52 -0700210 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
Phil Burk39f02dd2017-08-04 09:13:31 -0700218 aaudio_result_t result = serviceEndpointMMAP->getFreeRunningPosition(positionFrames, timeNanos);
219 if (result == AAUDIO_OK) {
220 Timestamp timestamp(*positionFrames, *timeNanos);
Phil Burka53ffa62018-10-10 16:21:37 -0700221 mAtomicStreamTimestamp.write(timestamp);
Phil Burk97350f92017-07-21 15:59:44 -0700222 *positionFrames = timestamp.getPosition();
223 *timeNanos = timestamp.getNanoseconds();
Phil Burk39f02dd2017-08-04 09:13:31 -0700224 } else if (result != AAUDIO_ERROR_UNAVAILABLE) {
jiabin2a594622021-10-14 00:32:25 +0000225 disconnect_l();
Phil Burkc0c70e32017-02-09 13:18:38 -0800226 }
Phil Burk940083c2017-07-17 17:00:02 -0700227 return result;
Phil Burkc0c70e32017-02-09 13:18:38 -0800228}
229
jiabinb7d8c5a2020-08-26 17:24:52 -0700230// Get timestamp from presentation position.
Phil Burkf95ed732020-09-30 18:48:17 +0000231// If it fails, get timestamp that was written by getFreeRunningPosition()
jiabin2a594622021-10-14 00:32:25 +0000232aaudio_result_t AAudioServiceStreamMMAP::getHardwareTimestamp_l(int64_t *positionFrames,
Phil Burk97350f92017-07-21 15:59:44 -0700233 int64_t *timeNanos) {
Phil Burk6e2770e2018-05-01 13:03:52 -0700234 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
jiabinb7d8c5a2020-08-26 17:24:52 -0700242 uint64_t position;
jiabina5df87b2020-12-29 10:45:19 -0800243 aaudio_result_t result = serviceEndpointMMAP->getExternalPosition(&position, timeNanos);
244 if (result == AAUDIO_OK) {
245 ALOGV("%s() getExternalPosition() says pos = %" PRIi64 ", time = %" PRIi64,
Phil Burkf95ed732020-09-30 18:48:17 +0000246 __func__, position, *timeNanos);
jiabinb7d8c5a2020-08-26 17:24:52 -0700247 *positionFrames = (int64_t) position;
248 return AAUDIO_OK;
jiabina5df87b2020-12-29 10:45:19 -0800249 } else {
250 ALOGV("%s() getExternalPosition() returns error %d", __func__, result);
251 }
252
Phil Burkf95ed732020-09-30 18:48:17 +0000253 if (mAtomicStreamTimestamp.isValid()) {
Phil Burka53ffa62018-10-10 16:21:37 -0700254 Timestamp timestamp = mAtomicStreamTimestamp.read();
Phil Burk97350f92017-07-21 15:59:44 -0700255 *positionFrames = timestamp.getPosition();
Phil Burk39f02dd2017-08-04 09:13:31 -0700256 *timeNanos = timestamp.getNanoseconds() + serviceEndpointMMAP->getHardwareTimeOffsetNanos();
Phil Burk97350f92017-07-21 15:59:44 -0700257 return AAUDIO_OK;
258 } else {
259 return AAUDIO_ERROR_UNAVAILABLE;
260 }
261}
262
Phil Burkfbf031e2017-10-12 15:58:31 -0700263// Get an immutable description of the data queue from the HAL.
jiabin2a594622021-10-14 00:32:25 +0000264aaudio_result_t AAudioServiceStreamMMAP::getAudioDataDescription_l(
265 AudioEndpointParcelable* parcelable)
Phil Burkc0c70e32017-02-09 13:18:38 -0800266{
Phil Burk6e2770e2018-05-01 13:03:52 -0700267 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());
Phil Burk39f02dd2017-08-04 09:13:31 -0700274 return serviceEndpointMMAP->getDownDataDescription(parcelable);
Phil Burkec89b2e2017-06-20 15:05:06 -0700275}
jiabinfc791ee2023-02-15 19:43:40 +0000276
277int64_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
288void 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}