blob: fc53949ab2af5401071ef05105ed77a7c3a6d78f [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,
153 audio_port_handle_t *clientHandle) {
jiabinb86b4032024-05-23 18:03:41 +0000154 if (com::android::media::aaudio::start_stop_client_from_command_thread()) {
155 return sendStartClientCommand(client, attr, clientHandle);
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, clientHandle);
164 return result;
165 }
166}
167
168aaudio_result_t AAudioServiceStreamMMAP::stopClient(audio_port_handle_t clientHandle) {
169 if (com::android::media::aaudio::start_stop_client_from_command_thread()) {
170 return sendStopClientCommand(clientHandle);
171 } else {
172 sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
173 if (endpoint == nullptr) {
174 ALOGE("%s() has no endpoint", __func__);
175 return AAUDIO_ERROR_INVALID_STATE;
176 }
177 aaudio_result_t result = endpoint->stopClient(clientHandle);
178 return result;
179 }
180}
181
182aaudio_result_t AAudioServiceStreamMMAP::startClient_l(const android::AudioClient& client,
183 const audio_attributes_t *attr,
184 audio_port_handle_t *clientHandle) {
Phil Burk6e2770e2018-05-01 13:03:52 -0700185 sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
186 if (endpoint == nullptr) {
187 ALOGE("%s() has no endpoint", __func__);
188 return AAUDIO_ERROR_INVALID_STATE;
189 }
Phil Burkbcc36742017-08-31 17:24:51 -0700190 // Start the client on behalf of the application. Generate a new porthandle.
jiabind1f1cb62020-03-24 11:57:57 -0700191 aaudio_result_t result = endpoint->startClient(client, attr, clientHandle);
Phil Burk39f02dd2017-08-04 09:13:31 -0700192 return result;
Eric Laurentcb4dae22017-07-01 19:39:32 -0700193}
194
jiabinb86b4032024-05-23 18:03:41 +0000195aaudio_result_t AAudioServiceStreamMMAP::stopClient_l(audio_port_handle_t clientHandle) {
Phil Burk6e2770e2018-05-01 13:03:52 -0700196 sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
197 if (endpoint == nullptr) {
198 ALOGE("%s() has no endpoint", __func__);
199 return AAUDIO_ERROR_INVALID_STATE;
200 }
201 aaudio_result_t result = endpoint->stopClient(clientHandle);
Phil Burk39f02dd2017-08-04 09:13:31 -0700202 return result;
Eric Laurentcb4dae22017-07-01 19:39:32 -0700203}
204
Phil Burk97350f92017-07-21 15:59:44 -0700205// Get free-running DSP or DMA hardware position from the HAL.
jiabin2a594622021-10-14 00:32:25 +0000206aaudio_result_t AAudioServiceStreamMMAP::getFreeRunningPosition_l(int64_t *positionFrames,
Phil Burk39f02dd2017-08-04 09:13:31 -0700207 int64_t *timeNanos) {
Phil Burk6e2770e2018-05-01 13:03:52 -0700208 sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
209 if (endpoint == nullptr) {
210 ALOGE("%s() has no endpoint", __func__);
211 return AAUDIO_ERROR_INVALID_STATE;
212 }
213 sp<AAudioServiceEndpointMMAP> serviceEndpointMMAP =
214 static_cast<AAudioServiceEndpointMMAP *>(endpoint.get());
215
Phil Burk39f02dd2017-08-04 09:13:31 -0700216 aaudio_result_t result = serviceEndpointMMAP->getFreeRunningPosition(positionFrames, timeNanos);
217 if (result == AAUDIO_OK) {
218 Timestamp timestamp(*positionFrames, *timeNanos);
Phil Burka53ffa62018-10-10 16:21:37 -0700219 mAtomicStreamTimestamp.write(timestamp);
Phil Burk97350f92017-07-21 15:59:44 -0700220 *positionFrames = timestamp.getPosition();
221 *timeNanos = timestamp.getNanoseconds();
Phil Burk39f02dd2017-08-04 09:13:31 -0700222 } else if (result != AAUDIO_ERROR_UNAVAILABLE) {
jiabin2a594622021-10-14 00:32:25 +0000223 disconnect_l();
Phil Burkc0c70e32017-02-09 13:18:38 -0800224 }
Phil Burk940083c2017-07-17 17:00:02 -0700225 return result;
Phil Burkc0c70e32017-02-09 13:18:38 -0800226}
227
jiabinb7d8c5a2020-08-26 17:24:52 -0700228// Get timestamp from presentation position.
Phil Burkf95ed732020-09-30 18:48:17 +0000229// If it fails, get timestamp that was written by getFreeRunningPosition()
jiabin2a594622021-10-14 00:32:25 +0000230aaudio_result_t AAudioServiceStreamMMAP::getHardwareTimestamp_l(int64_t *positionFrames,
Phil Burk97350f92017-07-21 15:59:44 -0700231 int64_t *timeNanos) {
Phil Burk6e2770e2018-05-01 13:03:52 -0700232 sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
233 if (endpoint == nullptr) {
234 ALOGE("%s() has no endpoint", __func__);
235 return AAUDIO_ERROR_INVALID_STATE;
236 }
237 sp<AAudioServiceEndpointMMAP> serviceEndpointMMAP =
238 static_cast<AAudioServiceEndpointMMAP *>(endpoint.get());
239
jiabinb7d8c5a2020-08-26 17:24:52 -0700240 uint64_t position;
jiabina5df87b2020-12-29 10:45:19 -0800241 aaudio_result_t result = serviceEndpointMMAP->getExternalPosition(&position, timeNanos);
242 if (result == AAUDIO_OK) {
243 ALOGV("%s() getExternalPosition() says pos = %" PRIi64 ", time = %" PRIi64,
Phil Burkf95ed732020-09-30 18:48:17 +0000244 __func__, position, *timeNanos);
jiabinb7d8c5a2020-08-26 17:24:52 -0700245 *positionFrames = (int64_t) position;
246 return AAUDIO_OK;
jiabina5df87b2020-12-29 10:45:19 -0800247 } else {
248 ALOGV("%s() getExternalPosition() returns error %d", __func__, result);
249 }
250
Phil Burkf95ed732020-09-30 18:48:17 +0000251 if (mAtomicStreamTimestamp.isValid()) {
Phil Burka53ffa62018-10-10 16:21:37 -0700252 Timestamp timestamp = mAtomicStreamTimestamp.read();
Phil Burk97350f92017-07-21 15:59:44 -0700253 *positionFrames = timestamp.getPosition();
Phil Burk39f02dd2017-08-04 09:13:31 -0700254 *timeNanos = timestamp.getNanoseconds() + serviceEndpointMMAP->getHardwareTimeOffsetNanos();
Phil Burk97350f92017-07-21 15:59:44 -0700255 return AAUDIO_OK;
256 } else {
257 return AAUDIO_ERROR_UNAVAILABLE;
258 }
259}
260
Phil Burkfbf031e2017-10-12 15:58:31 -0700261// Get an immutable description of the data queue from the HAL.
jiabin2a594622021-10-14 00:32:25 +0000262aaudio_result_t AAudioServiceStreamMMAP::getAudioDataDescription_l(
263 AudioEndpointParcelable* parcelable)
Phil Burkc0c70e32017-02-09 13:18:38 -0800264{
Phil Burk6e2770e2018-05-01 13:03:52 -0700265 sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
266 if (endpoint == nullptr) {
267 ALOGE("%s() has no endpoint", __func__);
268 return AAUDIO_ERROR_INVALID_STATE;
269 }
270 sp<AAudioServiceEndpointMMAP> serviceEndpointMMAP =
271 static_cast<AAudioServiceEndpointMMAP *>(endpoint.get());
Phil Burk39f02dd2017-08-04 09:13:31 -0700272 return serviceEndpointMMAP->getDownDataDescription(parcelable);
Phil Burkec89b2e2017-06-20 15:05:06 -0700273}
jiabinfc791ee2023-02-15 19:43:40 +0000274
275int64_t AAudioServiceStreamMMAP::nextDataReportTime_l() {
276 sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
277 if (endpoint == nullptr) {
278 ALOGE("%s() has no endpoint", __func__);
279 return std::numeric_limits<int64_t>::max();
280 }
281 sp<AAudioServiceEndpointMMAP> serviceEndpointMMAP =
282 static_cast<AAudioServiceEndpointMMAP *>(endpoint.get());
283 return serviceEndpointMMAP->nextDataReportTime();
284}
285
286void AAudioServiceStreamMMAP::reportData_l() {
287 sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
288 if (endpoint == nullptr) {
289 ALOGE("%s() has no endpoint", __func__);
290 return;
291 }
292 sp<AAudioServiceEndpointMMAP> serviceEndpointMMAP =
293 static_cast<AAudioServiceEndpointMMAP *>(endpoint.get());
294 return serviceEndpointMMAP->reportData();
295}