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