1*ec779b8eSAndroid Build Coastguard Worker /*
2*ec779b8eSAndroid Build Coastguard Worker * Copyright (C) 2016 The Android Open Source Project
3*ec779b8eSAndroid Build Coastguard Worker *
4*ec779b8eSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*ec779b8eSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*ec779b8eSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*ec779b8eSAndroid Build Coastguard Worker *
8*ec779b8eSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*ec779b8eSAndroid Build Coastguard Worker *
10*ec779b8eSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*ec779b8eSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*ec779b8eSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*ec779b8eSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*ec779b8eSAndroid Build Coastguard Worker * limitations under the License.
15*ec779b8eSAndroid Build Coastguard Worker */
16*ec779b8eSAndroid Build Coastguard Worker
17*ec779b8eSAndroid Build Coastguard Worker #define LOG_TAG "AAudioServiceStreamBase"
18*ec779b8eSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
19*ec779b8eSAndroid Build Coastguard Worker #include <utils/Log.h>
20*ec779b8eSAndroid Build Coastguard Worker
21*ec779b8eSAndroid Build Coastguard Worker #include <iomanip>
22*ec779b8eSAndroid Build Coastguard Worker #include <iostream>
23*ec779b8eSAndroid Build Coastguard Worker #include <mutex>
24*ec779b8eSAndroid Build Coastguard Worker
25*ec779b8eSAndroid Build Coastguard Worker #include <com_android_media_aaudio.h>
26*ec779b8eSAndroid Build Coastguard Worker #include <media/MediaMetricsItem.h>
27*ec779b8eSAndroid Build Coastguard Worker #include <media/TypeConverter.h>
28*ec779b8eSAndroid Build Coastguard Worker #include <mediautils/SchedulingPolicyService.h>
29*ec779b8eSAndroid Build Coastguard Worker
30*ec779b8eSAndroid Build Coastguard Worker #include "binding/AAudioServiceMessage.h"
31*ec779b8eSAndroid Build Coastguard Worker #include "core/AudioGlobal.h"
32*ec779b8eSAndroid Build Coastguard Worker #include "utility/AudioClock.h"
33*ec779b8eSAndroid Build Coastguard Worker
34*ec779b8eSAndroid Build Coastguard Worker #include "AAudioEndpointManager.h"
35*ec779b8eSAndroid Build Coastguard Worker #include "AAudioService.h"
36*ec779b8eSAndroid Build Coastguard Worker #include "AAudioServiceEndpoint.h"
37*ec779b8eSAndroid Build Coastguard Worker #include "AAudioServiceStreamBase.h"
38*ec779b8eSAndroid Build Coastguard Worker
39*ec779b8eSAndroid Build Coastguard Worker using namespace android; // TODO just import names needed
40*ec779b8eSAndroid Build Coastguard Worker using namespace aaudio; // TODO just import names needed
41*ec779b8eSAndroid Build Coastguard Worker
42*ec779b8eSAndroid Build Coastguard Worker using content::AttributionSourceState;
43*ec779b8eSAndroid Build Coastguard Worker
44*ec779b8eSAndroid Build Coastguard Worker static const int64_t TIMEOUT_NANOS = 3LL * 1000 * 1000 * 1000;
45*ec779b8eSAndroid Build Coastguard Worker // If the stream is idle for more than `IDLE_TIMEOUT_NANOS`, the stream will be put into standby.
46*ec779b8eSAndroid Build Coastguard Worker static const int64_t IDLE_TIMEOUT_NANOS = 3e9;
47*ec779b8eSAndroid Build Coastguard Worker
48*ec779b8eSAndroid Build Coastguard Worker /**
49*ec779b8eSAndroid Build Coastguard Worker * Base class for streams in the service.
50*ec779b8eSAndroid Build Coastguard Worker * @return
51*ec779b8eSAndroid Build Coastguard Worker */
52*ec779b8eSAndroid Build Coastguard Worker
AAudioServiceStreamBase(AAudioService & audioService)53*ec779b8eSAndroid Build Coastguard Worker AAudioServiceStreamBase::AAudioServiceStreamBase(AAudioService &audioService)
54*ec779b8eSAndroid Build Coastguard Worker : mCommandThread("AACommand")
55*ec779b8eSAndroid Build Coastguard Worker , mAtomicStreamTimestamp()
56*ec779b8eSAndroid Build Coastguard Worker , mAudioService(audioService) {
57*ec779b8eSAndroid Build Coastguard Worker mMmapClient.attributionSource = AttributionSourceState();
58*ec779b8eSAndroid Build Coastguard Worker }
59*ec779b8eSAndroid Build Coastguard Worker
~AAudioServiceStreamBase()60*ec779b8eSAndroid Build Coastguard Worker AAudioServiceStreamBase::~AAudioServiceStreamBase() {
61*ec779b8eSAndroid Build Coastguard Worker ALOGD("%s() called", __func__);
62*ec779b8eSAndroid Build Coastguard Worker
63*ec779b8eSAndroid Build Coastguard Worker // May not be set if open failed.
64*ec779b8eSAndroid Build Coastguard Worker if (mMetricsId.size() > 0) {
65*ec779b8eSAndroid Build Coastguard Worker mediametrics::LogItem(mMetricsId)
66*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_DTOR)
67*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_STATE, AudioGlobal_convertStreamStateToText(getState()))
68*ec779b8eSAndroid Build Coastguard Worker .record();
69*ec779b8eSAndroid Build Coastguard Worker }
70*ec779b8eSAndroid Build Coastguard Worker
71*ec779b8eSAndroid Build Coastguard Worker // If the stream is deleted when OPEN or in use then audio resources will leak.
72*ec779b8eSAndroid Build Coastguard Worker // This would indicate an internal error. So we want to find this ASAP.
73*ec779b8eSAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(!(getState() == AAUDIO_STREAM_STATE_CLOSED
74*ec779b8eSAndroid Build Coastguard Worker || getState() == AAUDIO_STREAM_STATE_UNINITIALIZED),
75*ec779b8eSAndroid Build Coastguard Worker "service stream %p still open, state = %d",
76*ec779b8eSAndroid Build Coastguard Worker this, getState());
77*ec779b8eSAndroid Build Coastguard Worker
78*ec779b8eSAndroid Build Coastguard Worker // Stop the command thread before destroying.
79*ec779b8eSAndroid Build Coastguard Worker stopCommandThread();
80*ec779b8eSAndroid Build Coastguard Worker }
81*ec779b8eSAndroid Build Coastguard Worker
dumpHeader()82*ec779b8eSAndroid Build Coastguard Worker std::string AAudioServiceStreamBase::dumpHeader() {
83*ec779b8eSAndroid Build Coastguard Worker return {" T Handle UId Port Run State Format Burst Chan Mask Capacity"
84*ec779b8eSAndroid Build Coastguard Worker " HwFormat HwChan HwRate"};
85*ec779b8eSAndroid Build Coastguard Worker }
86*ec779b8eSAndroid Build Coastguard Worker
dump() const87*ec779b8eSAndroid Build Coastguard Worker std::string AAudioServiceStreamBase::dump() const {
88*ec779b8eSAndroid Build Coastguard Worker std::stringstream result;
89*ec779b8eSAndroid Build Coastguard Worker
90*ec779b8eSAndroid Build Coastguard Worker result << " 0x" << std::setfill('0') << std::setw(8) << std::hex << mHandle
91*ec779b8eSAndroid Build Coastguard Worker << std::dec << std::setfill(' ') ;
92*ec779b8eSAndroid Build Coastguard Worker result << std::setw(6) << mMmapClient.attributionSource.uid;
93*ec779b8eSAndroid Build Coastguard Worker result << std::setw(7) << mClientHandle;
94*ec779b8eSAndroid Build Coastguard Worker result << std::setw(4) << (isRunning() ? "yes" : " no");
95*ec779b8eSAndroid Build Coastguard Worker result << std::setw(6) << getState();
96*ec779b8eSAndroid Build Coastguard Worker result << std::setw(7) << getFormat();
97*ec779b8eSAndroid Build Coastguard Worker result << std::setw(6) << mFramesPerBurst;
98*ec779b8eSAndroid Build Coastguard Worker result << std::setw(5) << getSamplesPerFrame();
99*ec779b8eSAndroid Build Coastguard Worker result << std::setw(8) << std::hex << getChannelMask() << std::dec;
100*ec779b8eSAndroid Build Coastguard Worker result << std::setw(9) << getBufferCapacity();
101*ec779b8eSAndroid Build Coastguard Worker result << std::setw(9) << getHardwareFormat();
102*ec779b8eSAndroid Build Coastguard Worker result << std::setw(7) << getHardwareSamplesPerFrame();
103*ec779b8eSAndroid Build Coastguard Worker result << std::setw(7) << getHardwareSampleRate();
104*ec779b8eSAndroid Build Coastguard Worker
105*ec779b8eSAndroid Build Coastguard Worker return result.str();
106*ec779b8eSAndroid Build Coastguard Worker }
107*ec779b8eSAndroid Build Coastguard Worker
logOpen(aaudio_handle_t streamHandle)108*ec779b8eSAndroid Build Coastguard Worker void AAudioServiceStreamBase::logOpen(aaudio_handle_t streamHandle) {
109*ec779b8eSAndroid Build Coastguard Worker // This is the first log sent from the AAudio Service for a stream.
110*ec779b8eSAndroid Build Coastguard Worker mMetricsId = std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_STREAM)
111*ec779b8eSAndroid Build Coastguard Worker + std::to_string(streamHandle);
112*ec779b8eSAndroid Build Coastguard Worker
113*ec779b8eSAndroid Build Coastguard Worker audio_attributes_t attributes = AAudioServiceEndpoint::getAudioAttributesFrom(this);
114*ec779b8eSAndroid Build Coastguard Worker
115*ec779b8eSAndroid Build Coastguard Worker // Once this item is logged by the server, the client with the same PID, UID
116*ec779b8eSAndroid Build Coastguard Worker // can also log properties.
117*ec779b8eSAndroid Build Coastguard Worker mediametrics::LogItem(mMetricsId)
118*ec779b8eSAndroid Build Coastguard Worker .setPid(getOwnerProcessId())
119*ec779b8eSAndroid Build Coastguard Worker .setUid(getOwnerUserId())
120*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_ALLOWUID, (int32_t)getOwnerUserId())
121*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_OPEN)
122*ec779b8eSAndroid Build Coastguard Worker // the following are immutable
123*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_BUFFERCAPACITYFRAMES, (int32_t)getBufferCapacity())
124*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_BURSTFRAMES, (int32_t)getFramesPerBurst())
125*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_CHANNELCOUNT, (int32_t)getSamplesPerFrame())
126*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_CONTENTTYPE, toString(attributes.content_type).c_str())
127*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_DIRECTION,
128*ec779b8eSAndroid Build Coastguard Worker AudioGlobal_convertDirectionToText(getDirection()))
129*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_ENCODING, toString(getFormat()).c_str())
130*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_ROUTEDDEVICEID, android::getFirstDeviceId(getDeviceIds()))
131*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_ROUTEDDEVICEIDS, android::toString(getDeviceIds()).c_str())
132*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_SAMPLERATE, (int32_t)getSampleRate())
133*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_SESSIONID, (int32_t)getSessionId())
134*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_SOURCE, toString(attributes.source).c_str())
135*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_USAGE, toString(attributes.usage).c_str())
136*ec779b8eSAndroid Build Coastguard Worker .record();
137*ec779b8eSAndroid Build Coastguard Worker }
138*ec779b8eSAndroid Build Coastguard Worker
open(const aaudio::AAudioStreamRequest & request)139*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t AAudioServiceStreamBase::open(const aaudio::AAudioStreamRequest &request) {
140*ec779b8eSAndroid Build Coastguard Worker AAudioEndpointManager &mEndpointManager = AAudioEndpointManager::getInstance();
141*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t result = AAUDIO_OK;
142*ec779b8eSAndroid Build Coastguard Worker
143*ec779b8eSAndroid Build Coastguard Worker mMmapClient.attributionSource = request.getAttributionSource();
144*ec779b8eSAndroid Build Coastguard Worker // TODO b/182392769: use attribution source util
145*ec779b8eSAndroid Build Coastguard Worker mMmapClient.attributionSource.uid = VALUE_OR_FATAL(
146*ec779b8eSAndroid Build Coastguard Worker legacy2aidl_uid_t_int32_t(IPCThreadState::self()->getCallingUid()));
147*ec779b8eSAndroid Build Coastguard Worker mMmapClient.attributionSource.pid = VALUE_OR_FATAL(
148*ec779b8eSAndroid Build Coastguard Worker legacy2aidl_pid_t_int32_t(IPCThreadState::self()->getCallingPid()));
149*ec779b8eSAndroid Build Coastguard Worker
150*ec779b8eSAndroid Build Coastguard Worker // Limit scope of lock to avoid recursive lock in close().
151*ec779b8eSAndroid Build Coastguard Worker {
152*ec779b8eSAndroid Build Coastguard Worker std::lock_guard<std::mutex> lock(mUpMessageQueueLock);
153*ec779b8eSAndroid Build Coastguard Worker if (mUpMessageQueue != nullptr) {
154*ec779b8eSAndroid Build Coastguard Worker ALOGE("%s() called twice", __func__);
155*ec779b8eSAndroid Build Coastguard Worker return AAUDIO_ERROR_INVALID_STATE;
156*ec779b8eSAndroid Build Coastguard Worker }
157*ec779b8eSAndroid Build Coastguard Worker
158*ec779b8eSAndroid Build Coastguard Worker mUpMessageQueue = std::make_shared<SharedRingBuffer>();
159*ec779b8eSAndroid Build Coastguard Worker result = mUpMessageQueue->allocate(sizeof(AAudioServiceMessage),
160*ec779b8eSAndroid Build Coastguard Worker QUEUE_UP_CAPACITY_COMMANDS);
161*ec779b8eSAndroid Build Coastguard Worker if (result != AAUDIO_OK) {
162*ec779b8eSAndroid Build Coastguard Worker goto error;
163*ec779b8eSAndroid Build Coastguard Worker }
164*ec779b8eSAndroid Build Coastguard Worker
165*ec779b8eSAndroid Build Coastguard Worker // This is not protected by a lock because the stream cannot be
166*ec779b8eSAndroid Build Coastguard Worker // referenced until the service returns a handle to the client.
167*ec779b8eSAndroid Build Coastguard Worker // So only one thread can open a stream.
168*ec779b8eSAndroid Build Coastguard Worker mServiceEndpoint = mEndpointManager.openEndpoint(mAudioService,
169*ec779b8eSAndroid Build Coastguard Worker request);
170*ec779b8eSAndroid Build Coastguard Worker if (mServiceEndpoint == nullptr) {
171*ec779b8eSAndroid Build Coastguard Worker result = AAUDIO_ERROR_UNAVAILABLE;
172*ec779b8eSAndroid Build Coastguard Worker goto error;
173*ec779b8eSAndroid Build Coastguard Worker }
174*ec779b8eSAndroid Build Coastguard Worker // Save a weak pointer that we will use to access the endpoint.
175*ec779b8eSAndroid Build Coastguard Worker mServiceEndpointWeak = mServiceEndpoint;
176*ec779b8eSAndroid Build Coastguard Worker
177*ec779b8eSAndroid Build Coastguard Worker mFramesPerBurst = mServiceEndpoint->getFramesPerBurst();
178*ec779b8eSAndroid Build Coastguard Worker copyFrom(*mServiceEndpoint);
179*ec779b8eSAndroid Build Coastguard Worker }
180*ec779b8eSAndroid Build Coastguard Worker
181*ec779b8eSAndroid Build Coastguard Worker // Make sure this object does not get deleted before the run() method
182*ec779b8eSAndroid Build Coastguard Worker // can protect it by making a strong pointer.
183*ec779b8eSAndroid Build Coastguard Worker mCommandQueue.startWaiting();
184*ec779b8eSAndroid Build Coastguard Worker mThreadEnabled = true;
185*ec779b8eSAndroid Build Coastguard Worker incStrong(nullptr); // See run() method.
186*ec779b8eSAndroid Build Coastguard Worker result = mCommandThread.start(this);
187*ec779b8eSAndroid Build Coastguard Worker if (result != AAUDIO_OK) {
188*ec779b8eSAndroid Build Coastguard Worker decStrong(nullptr); // run() can't do it so we have to do it here.
189*ec779b8eSAndroid Build Coastguard Worker goto error;
190*ec779b8eSAndroid Build Coastguard Worker }
191*ec779b8eSAndroid Build Coastguard Worker return result;
192*ec779b8eSAndroid Build Coastguard Worker
193*ec779b8eSAndroid Build Coastguard Worker error:
194*ec779b8eSAndroid Build Coastguard Worker closeAndClear();
195*ec779b8eSAndroid Build Coastguard Worker stopCommandThread();
196*ec779b8eSAndroid Build Coastguard Worker return result;
197*ec779b8eSAndroid Build Coastguard Worker }
198*ec779b8eSAndroid Build Coastguard Worker
close()199*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t AAudioServiceStreamBase::close() {
200*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t result = sendCommand(CLOSE, nullptr, true /*waitForReply*/, TIMEOUT_NANOS);
201*ec779b8eSAndroid Build Coastguard Worker if (result == AAUDIO_ERROR_ALREADY_CLOSED) {
202*ec779b8eSAndroid Build Coastguard Worker // AAUDIO_ERROR_ALREADY_CLOSED is not a really error but just indicate the stream has
203*ec779b8eSAndroid Build Coastguard Worker // already been closed. In that case, there is no need to close the stream once more.
204*ec779b8eSAndroid Build Coastguard Worker ALOGD("The stream(%d) is already closed", mHandle);
205*ec779b8eSAndroid Build Coastguard Worker return AAUDIO_OK;
206*ec779b8eSAndroid Build Coastguard Worker }
207*ec779b8eSAndroid Build Coastguard Worker
208*ec779b8eSAndroid Build Coastguard Worker stopCommandThread();
209*ec779b8eSAndroid Build Coastguard Worker
210*ec779b8eSAndroid Build Coastguard Worker return result;
211*ec779b8eSAndroid Build Coastguard Worker }
212*ec779b8eSAndroid Build Coastguard Worker
close_l()213*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t AAudioServiceStreamBase::close_l() {
214*ec779b8eSAndroid Build Coastguard Worker if (getState() == AAUDIO_STREAM_STATE_CLOSED) {
215*ec779b8eSAndroid Build Coastguard Worker return AAUDIO_ERROR_ALREADY_CLOSED;
216*ec779b8eSAndroid Build Coastguard Worker }
217*ec779b8eSAndroid Build Coastguard Worker
218*ec779b8eSAndroid Build Coastguard Worker // This will stop the stream, just in case it was not already stopped.
219*ec779b8eSAndroid Build Coastguard Worker stop_l();
220*ec779b8eSAndroid Build Coastguard Worker
221*ec779b8eSAndroid Build Coastguard Worker return closeAndClear();
222*ec779b8eSAndroid Build Coastguard Worker }
223*ec779b8eSAndroid Build Coastguard Worker
startDevice_l()224*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t AAudioServiceStreamBase::startDevice_l() {
225*ec779b8eSAndroid Build Coastguard Worker mClientHandle = AUDIO_PORT_HANDLE_NONE;
226*ec779b8eSAndroid Build Coastguard Worker sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
227*ec779b8eSAndroid Build Coastguard Worker if (endpoint == nullptr) {
228*ec779b8eSAndroid Build Coastguard Worker ALOGE("%s() has no endpoint", __func__);
229*ec779b8eSAndroid Build Coastguard Worker return AAUDIO_ERROR_INVALID_STATE;
230*ec779b8eSAndroid Build Coastguard Worker }
231*ec779b8eSAndroid Build Coastguard Worker if (!endpoint->isConnected()) {
232*ec779b8eSAndroid Build Coastguard Worker ALOGE("%s() endpoint was already disconnected", __func__);
233*ec779b8eSAndroid Build Coastguard Worker return AAUDIO_ERROR_DISCONNECTED;
234*ec779b8eSAndroid Build Coastguard Worker }
235*ec779b8eSAndroid Build Coastguard Worker return endpoint->startStream(this, &mClientHandle);
236*ec779b8eSAndroid Build Coastguard Worker }
237*ec779b8eSAndroid Build Coastguard Worker
238*ec779b8eSAndroid Build Coastguard Worker /**
239*ec779b8eSAndroid Build Coastguard Worker * Start the flow of audio data.
240*ec779b8eSAndroid Build Coastguard Worker *
241*ec779b8eSAndroid Build Coastguard Worker * An AAUDIO_SERVICE_EVENT_STARTED will be sent to the client when complete.
242*ec779b8eSAndroid Build Coastguard Worker */
start()243*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t AAudioServiceStreamBase::start() {
244*ec779b8eSAndroid Build Coastguard Worker return sendCommand(START, nullptr, true /*waitForReply*/, TIMEOUT_NANOS);
245*ec779b8eSAndroid Build Coastguard Worker }
246*ec779b8eSAndroid Build Coastguard Worker
start_l()247*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t AAudioServiceStreamBase::start_l() {
248*ec779b8eSAndroid Build Coastguard Worker const int64_t beginNs = AudioClock::getNanoseconds();
249*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t result = AAUDIO_OK;
250*ec779b8eSAndroid Build Coastguard Worker
251*ec779b8eSAndroid Build Coastguard Worker if (auto state = getState();
252*ec779b8eSAndroid Build Coastguard Worker state == AAUDIO_STREAM_STATE_CLOSED || isDisconnected_l()) {
253*ec779b8eSAndroid Build Coastguard Worker ALOGW("%s() already CLOSED, returns INVALID_STATE, handle = %d",
254*ec779b8eSAndroid Build Coastguard Worker __func__, getHandle());
255*ec779b8eSAndroid Build Coastguard Worker return AAUDIO_ERROR_INVALID_STATE;
256*ec779b8eSAndroid Build Coastguard Worker }
257*ec779b8eSAndroid Build Coastguard Worker
258*ec779b8eSAndroid Build Coastguard Worker if (mStandby) {
259*ec779b8eSAndroid Build Coastguard Worker ALOGW("%s() the stream is standby, return ERROR_STANDBY, "
260*ec779b8eSAndroid Build Coastguard Worker "expecting the client call exitStandby before start", __func__);
261*ec779b8eSAndroid Build Coastguard Worker return AAUDIO_ERROR_STANDBY;
262*ec779b8eSAndroid Build Coastguard Worker }
263*ec779b8eSAndroid Build Coastguard Worker
264*ec779b8eSAndroid Build Coastguard Worker mediametrics::Defer defer([&] {
265*ec779b8eSAndroid Build Coastguard Worker mediametrics::LogItem(mMetricsId)
266*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_START)
267*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(AudioClock::getNanoseconds() - beginNs))
268*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_STATE, AudioGlobal_convertStreamStateToText(getState()))
269*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)result)
270*ec779b8eSAndroid Build Coastguard Worker .record(); });
271*ec779b8eSAndroid Build Coastguard Worker
272*ec779b8eSAndroid Build Coastguard Worker if (isRunning()) {
273*ec779b8eSAndroid Build Coastguard Worker return result;
274*ec779b8eSAndroid Build Coastguard Worker }
275*ec779b8eSAndroid Build Coastguard Worker
276*ec779b8eSAndroid Build Coastguard Worker setFlowing(false);
277*ec779b8eSAndroid Build Coastguard Worker setSuspended(false);
278*ec779b8eSAndroid Build Coastguard Worker
279*ec779b8eSAndroid Build Coastguard Worker // Start with fresh presentation timestamps.
280*ec779b8eSAndroid Build Coastguard Worker mAtomicStreamTimestamp.clear();
281*ec779b8eSAndroid Build Coastguard Worker
282*ec779b8eSAndroid Build Coastguard Worker mClientHandle = AUDIO_PORT_HANDLE_NONE;
283*ec779b8eSAndroid Build Coastguard Worker result = startDevice_l();
284*ec779b8eSAndroid Build Coastguard Worker if (result != AAUDIO_OK) goto error;
285*ec779b8eSAndroid Build Coastguard Worker
286*ec779b8eSAndroid Build Coastguard Worker // This should happen at the end of the start.
287*ec779b8eSAndroid Build Coastguard Worker sendServiceEvent(AAUDIO_SERVICE_EVENT_STARTED, static_cast<int64_t>(mClientHandle));
288*ec779b8eSAndroid Build Coastguard Worker setState(AAUDIO_STREAM_STATE_STARTED);
289*ec779b8eSAndroid Build Coastguard Worker
290*ec779b8eSAndroid Build Coastguard Worker return result;
291*ec779b8eSAndroid Build Coastguard Worker
292*ec779b8eSAndroid Build Coastguard Worker error:
293*ec779b8eSAndroid Build Coastguard Worker disconnect_l();
294*ec779b8eSAndroid Build Coastguard Worker return result;
295*ec779b8eSAndroid Build Coastguard Worker }
296*ec779b8eSAndroid Build Coastguard Worker
pause()297*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t AAudioServiceStreamBase::pause() {
298*ec779b8eSAndroid Build Coastguard Worker return sendCommand(PAUSE, nullptr, true /*waitForReply*/, TIMEOUT_NANOS);
299*ec779b8eSAndroid Build Coastguard Worker }
300*ec779b8eSAndroid Build Coastguard Worker
pause_l()301*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t AAudioServiceStreamBase::pause_l() {
302*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t result = AAUDIO_OK;
303*ec779b8eSAndroid Build Coastguard Worker if (!isRunning()) {
304*ec779b8eSAndroid Build Coastguard Worker return result;
305*ec779b8eSAndroid Build Coastguard Worker }
306*ec779b8eSAndroid Build Coastguard Worker const int64_t beginNs = AudioClock::getNanoseconds();
307*ec779b8eSAndroid Build Coastguard Worker
308*ec779b8eSAndroid Build Coastguard Worker mediametrics::Defer defer([&] {
309*ec779b8eSAndroid Build Coastguard Worker mediametrics::LogItem(mMetricsId)
310*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_PAUSE)
311*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(AudioClock::getNanoseconds() - beginNs))
312*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_STATE, AudioGlobal_convertStreamStateToText(getState()))
313*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)result)
314*ec779b8eSAndroid Build Coastguard Worker .record(); });
315*ec779b8eSAndroid Build Coastguard Worker
316*ec779b8eSAndroid Build Coastguard Worker setState(AAUDIO_STREAM_STATE_PAUSING);
317*ec779b8eSAndroid Build Coastguard Worker
318*ec779b8eSAndroid Build Coastguard Worker sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
319*ec779b8eSAndroid Build Coastguard Worker if (endpoint == nullptr) {
320*ec779b8eSAndroid Build Coastguard Worker ALOGE("%s() has no endpoint", __func__);
321*ec779b8eSAndroid Build Coastguard Worker result = AAUDIO_ERROR_INVALID_STATE; // for MediaMetric tracking
322*ec779b8eSAndroid Build Coastguard Worker return result;
323*ec779b8eSAndroid Build Coastguard Worker }
324*ec779b8eSAndroid Build Coastguard Worker result = endpoint->stopStream(this, mClientHandle);
325*ec779b8eSAndroid Build Coastguard Worker if (result != AAUDIO_OK) {
326*ec779b8eSAndroid Build Coastguard Worker ALOGE("%s() mServiceEndpoint returned %d, %s", __func__, result, getTypeText());
327*ec779b8eSAndroid Build Coastguard Worker disconnect_l(); // TODO should we return or pause Base first?
328*ec779b8eSAndroid Build Coastguard Worker }
329*ec779b8eSAndroid Build Coastguard Worker
330*ec779b8eSAndroid Build Coastguard Worker sendServiceEvent(AAUDIO_SERVICE_EVENT_PAUSED);
331*ec779b8eSAndroid Build Coastguard Worker setState(AAUDIO_STREAM_STATE_PAUSED);
332*ec779b8eSAndroid Build Coastguard Worker return result;
333*ec779b8eSAndroid Build Coastguard Worker }
334*ec779b8eSAndroid Build Coastguard Worker
stop()335*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t AAudioServiceStreamBase::stop() {
336*ec779b8eSAndroid Build Coastguard Worker return sendCommand(STOP, nullptr, true /*waitForReply*/, TIMEOUT_NANOS);
337*ec779b8eSAndroid Build Coastguard Worker }
338*ec779b8eSAndroid Build Coastguard Worker
stop_l()339*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t AAudioServiceStreamBase::stop_l() {
340*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t result = AAUDIO_OK;
341*ec779b8eSAndroid Build Coastguard Worker if (!isRunning()) {
342*ec779b8eSAndroid Build Coastguard Worker ALOGW("%s() stream not running, returning early", __func__);
343*ec779b8eSAndroid Build Coastguard Worker return result;
344*ec779b8eSAndroid Build Coastguard Worker }
345*ec779b8eSAndroid Build Coastguard Worker const int64_t beginNs = AudioClock::getNanoseconds();
346*ec779b8eSAndroid Build Coastguard Worker
347*ec779b8eSAndroid Build Coastguard Worker mediametrics::Defer defer([&] {
348*ec779b8eSAndroid Build Coastguard Worker mediametrics::LogItem(mMetricsId)
349*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_STOP)
350*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(AudioClock::getNanoseconds() - beginNs))
351*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_STATE, AudioGlobal_convertStreamStateToText(getState()))
352*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)result)
353*ec779b8eSAndroid Build Coastguard Worker .record(); });
354*ec779b8eSAndroid Build Coastguard Worker
355*ec779b8eSAndroid Build Coastguard Worker setState(AAUDIO_STREAM_STATE_STOPPING);
356*ec779b8eSAndroid Build Coastguard Worker
357*ec779b8eSAndroid Build Coastguard Worker if (result != AAUDIO_OK) {
358*ec779b8eSAndroid Build Coastguard Worker disconnect_l();
359*ec779b8eSAndroid Build Coastguard Worker return result;
360*ec779b8eSAndroid Build Coastguard Worker }
361*ec779b8eSAndroid Build Coastguard Worker
362*ec779b8eSAndroid Build Coastguard Worker sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
363*ec779b8eSAndroid Build Coastguard Worker if (endpoint == nullptr) {
364*ec779b8eSAndroid Build Coastguard Worker ALOGE("%s() has no endpoint", __func__);
365*ec779b8eSAndroid Build Coastguard Worker result = AAUDIO_ERROR_INVALID_STATE; // for MediaMetric tracking
366*ec779b8eSAndroid Build Coastguard Worker return result;
367*ec779b8eSAndroid Build Coastguard Worker }
368*ec779b8eSAndroid Build Coastguard Worker // TODO wait for data to be played out
369*ec779b8eSAndroid Build Coastguard Worker result = endpoint->stopStream(this, mClientHandle);
370*ec779b8eSAndroid Build Coastguard Worker if (result != AAUDIO_OK) {
371*ec779b8eSAndroid Build Coastguard Worker ALOGE("%s() stopStream returned %d, %s", __func__, result, getTypeText());
372*ec779b8eSAndroid Build Coastguard Worker disconnect_l();
373*ec779b8eSAndroid Build Coastguard Worker // TODO what to do with result here?
374*ec779b8eSAndroid Build Coastguard Worker }
375*ec779b8eSAndroid Build Coastguard Worker
376*ec779b8eSAndroid Build Coastguard Worker sendServiceEvent(AAUDIO_SERVICE_EVENT_STOPPED);
377*ec779b8eSAndroid Build Coastguard Worker setState(AAUDIO_STREAM_STATE_STOPPED);
378*ec779b8eSAndroid Build Coastguard Worker return result;
379*ec779b8eSAndroid Build Coastguard Worker }
380*ec779b8eSAndroid Build Coastguard Worker
flush()381*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t AAudioServiceStreamBase::flush() {
382*ec779b8eSAndroid Build Coastguard Worker return sendCommand(FLUSH, nullptr, true /*waitForReply*/, TIMEOUT_NANOS);
383*ec779b8eSAndroid Build Coastguard Worker }
384*ec779b8eSAndroid Build Coastguard Worker
flush_l()385*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t AAudioServiceStreamBase::flush_l() {
386*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t result = AAudio_isFlushAllowed(getState());
387*ec779b8eSAndroid Build Coastguard Worker if (result != AAUDIO_OK) {
388*ec779b8eSAndroid Build Coastguard Worker return result;
389*ec779b8eSAndroid Build Coastguard Worker }
390*ec779b8eSAndroid Build Coastguard Worker const int64_t beginNs = AudioClock::getNanoseconds();
391*ec779b8eSAndroid Build Coastguard Worker
392*ec779b8eSAndroid Build Coastguard Worker mediametrics::Defer defer([&] {
393*ec779b8eSAndroid Build Coastguard Worker mediametrics::LogItem(mMetricsId)
394*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_FLUSH)
395*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(AudioClock::getNanoseconds() - beginNs))
396*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_STATE, AudioGlobal_convertStreamStateToText(getState()))
397*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)result)
398*ec779b8eSAndroid Build Coastguard Worker .record(); });
399*ec779b8eSAndroid Build Coastguard Worker
400*ec779b8eSAndroid Build Coastguard Worker // Data will get flushed when the client receives the FLUSHED event.
401*ec779b8eSAndroid Build Coastguard Worker sendServiceEvent(AAUDIO_SERVICE_EVENT_FLUSHED);
402*ec779b8eSAndroid Build Coastguard Worker setState(AAUDIO_STREAM_STATE_FLUSHED);
403*ec779b8eSAndroid Build Coastguard Worker return AAUDIO_OK;
404*ec779b8eSAndroid Build Coastguard Worker }
405*ec779b8eSAndroid Build Coastguard Worker
406*ec779b8eSAndroid Build Coastguard Worker // implement Runnable, periodically send timestamps to client and process commands from queue.
407*ec779b8eSAndroid Build Coastguard Worker // Enter standby mode if idle for a while.
408*ec779b8eSAndroid Build Coastguard Worker __attribute__((no_sanitize("integer")))
run()409*ec779b8eSAndroid Build Coastguard Worker void AAudioServiceStreamBase::run() {
410*ec779b8eSAndroid Build Coastguard Worker ALOGD("%s() %s entering >>>>>>>>>>>>>> COMMANDS", __func__, getTypeText());
411*ec779b8eSAndroid Build Coastguard Worker // Hold onto the ref counted stream until the end.
412*ec779b8eSAndroid Build Coastguard Worker android::sp<AAudioServiceStreamBase> holdStream(this);
413*ec779b8eSAndroid Build Coastguard Worker TimestampScheduler timestampScheduler;
414*ec779b8eSAndroid Build Coastguard Worker int64_t nextTimestampReportTime;
415*ec779b8eSAndroid Build Coastguard Worker int64_t nextDataReportTime;
416*ec779b8eSAndroid Build Coastguard Worker // When to try to enter standby.
417*ec779b8eSAndroid Build Coastguard Worker int64_t standbyTime = AudioClock::getNanoseconds() + IDLE_TIMEOUT_NANOS;
418*ec779b8eSAndroid Build Coastguard Worker // Balance the incStrong from when the thread was launched.
419*ec779b8eSAndroid Build Coastguard Worker holdStream->decStrong(nullptr);
420*ec779b8eSAndroid Build Coastguard Worker
421*ec779b8eSAndroid Build Coastguard Worker // Taking mLock while starting the thread. All the operation must be able to
422*ec779b8eSAndroid Build Coastguard Worker // run with holding the lock.
423*ec779b8eSAndroid Build Coastguard Worker std::scoped_lock<std::mutex> _l(mLock);
424*ec779b8eSAndroid Build Coastguard Worker
425*ec779b8eSAndroid Build Coastguard Worker int32_t loopCount = 0;
426*ec779b8eSAndroid Build Coastguard Worker while (mThreadEnabled.load()) {
427*ec779b8eSAndroid Build Coastguard Worker loopCount++;
428*ec779b8eSAndroid Build Coastguard Worker int64_t timeoutNanos = -1; // wait forever
429*ec779b8eSAndroid Build Coastguard Worker if (isDisconnected_l() || isIdle_l()) {
430*ec779b8eSAndroid Build Coastguard Worker if (isStandbyImplemented() && !isStandby_l()) {
431*ec779b8eSAndroid Build Coastguard Worker // If not in standby mode, wait until standby time.
432*ec779b8eSAndroid Build Coastguard Worker timeoutNanos = standbyTime - AudioClock::getNanoseconds();
433*ec779b8eSAndroid Build Coastguard Worker timeoutNanos = std::max<int64_t>(0, timeoutNanos);
434*ec779b8eSAndroid Build Coastguard Worker }
435*ec779b8eSAndroid Build Coastguard Worker // Otherwise, keep `timeoutNanos` as -1 to wait forever until next command.
436*ec779b8eSAndroid Build Coastguard Worker } else if (isRunning()) {
437*ec779b8eSAndroid Build Coastguard Worker timeoutNanos = std::min(nextTimestampReportTime, nextDataReportTime)
438*ec779b8eSAndroid Build Coastguard Worker - AudioClock::getNanoseconds();
439*ec779b8eSAndroid Build Coastguard Worker timeoutNanos = std::max<int64_t>(0, timeoutNanos);
440*ec779b8eSAndroid Build Coastguard Worker }
441*ec779b8eSAndroid Build Coastguard Worker auto command = mCommandQueue.waitForCommand(timeoutNanos);
442*ec779b8eSAndroid Build Coastguard Worker if (!mThreadEnabled) {
443*ec779b8eSAndroid Build Coastguard Worker // Break the loop if the thread is disabled.
444*ec779b8eSAndroid Build Coastguard Worker break;
445*ec779b8eSAndroid Build Coastguard Worker }
446*ec779b8eSAndroid Build Coastguard Worker
447*ec779b8eSAndroid Build Coastguard Worker // Is it time to send timestamps?
448*ec779b8eSAndroid Build Coastguard Worker if (isRunning() && !isDisconnected_l()) {
449*ec779b8eSAndroid Build Coastguard Worker auto currentTimestamp = AudioClock::getNanoseconds();
450*ec779b8eSAndroid Build Coastguard Worker if (currentTimestamp >= nextDataReportTime) {
451*ec779b8eSAndroid Build Coastguard Worker reportData_l();
452*ec779b8eSAndroid Build Coastguard Worker nextDataReportTime = nextDataReportTime_l();
453*ec779b8eSAndroid Build Coastguard Worker }
454*ec779b8eSAndroid Build Coastguard Worker if (currentTimestamp >= nextTimestampReportTime) {
455*ec779b8eSAndroid Build Coastguard Worker // It is time to update timestamp.
456*ec779b8eSAndroid Build Coastguard Worker if (sendCurrentTimestamp_l() != AAUDIO_OK) {
457*ec779b8eSAndroid Build Coastguard Worker ALOGE("Failed to send current timestamp, stop updating timestamp");
458*ec779b8eSAndroid Build Coastguard Worker disconnect_l();
459*ec779b8eSAndroid Build Coastguard Worker }
460*ec779b8eSAndroid Build Coastguard Worker nextTimestampReportTime = timestampScheduler.nextAbsoluteTime();
461*ec779b8eSAndroid Build Coastguard Worker }
462*ec779b8eSAndroid Build Coastguard Worker }
463*ec779b8eSAndroid Build Coastguard Worker
464*ec779b8eSAndroid Build Coastguard Worker // Is it time to enter standby?
465*ec779b8eSAndroid Build Coastguard Worker if ((isIdle_l() || isDisconnected_l())
466*ec779b8eSAndroid Build Coastguard Worker && isStandbyImplemented()
467*ec779b8eSAndroid Build Coastguard Worker && !isStandby_l()
468*ec779b8eSAndroid Build Coastguard Worker && (AudioClock::getNanoseconds() >= standbyTime)) {
469*ec779b8eSAndroid Build Coastguard Worker ALOGD("%s() call standby_l(), %d loops", __func__, loopCount);
470*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t result = standby_l();
471*ec779b8eSAndroid Build Coastguard Worker if (result != AAUDIO_OK) {
472*ec779b8eSAndroid Build Coastguard Worker ALOGW("Failed to enter standby, error = %d", result);
473*ec779b8eSAndroid Build Coastguard Worker // Try again later.
474*ec779b8eSAndroid Build Coastguard Worker standbyTime = AudioClock::getNanoseconds() + IDLE_TIMEOUT_NANOS;
475*ec779b8eSAndroid Build Coastguard Worker }
476*ec779b8eSAndroid Build Coastguard Worker }
477*ec779b8eSAndroid Build Coastguard Worker
478*ec779b8eSAndroid Build Coastguard Worker if (command != nullptr) {
479*ec779b8eSAndroid Build Coastguard Worker ALOGD("%s() got COMMAND opcode %d after %d loops",
480*ec779b8eSAndroid Build Coastguard Worker __func__, command->operationCode, loopCount);
481*ec779b8eSAndroid Build Coastguard Worker std::scoped_lock<std::mutex> _commandLock(command->lock);
482*ec779b8eSAndroid Build Coastguard Worker switch (command->operationCode) {
483*ec779b8eSAndroid Build Coastguard Worker case START:
484*ec779b8eSAndroid Build Coastguard Worker command->result = start_l();
485*ec779b8eSAndroid Build Coastguard Worker timestampScheduler.setBurstPeriod(mFramesPerBurst, getSampleRate());
486*ec779b8eSAndroid Build Coastguard Worker timestampScheduler.start(AudioClock::getNanoseconds());
487*ec779b8eSAndroid Build Coastguard Worker nextTimestampReportTime = timestampScheduler.nextAbsoluteTime();
488*ec779b8eSAndroid Build Coastguard Worker nextDataReportTime = nextDataReportTime_l();
489*ec779b8eSAndroid Build Coastguard Worker break;
490*ec779b8eSAndroid Build Coastguard Worker case PAUSE:
491*ec779b8eSAndroid Build Coastguard Worker command->result = pause_l();
492*ec779b8eSAndroid Build Coastguard Worker standbyTime = AudioClock::getNanoseconds() + IDLE_TIMEOUT_NANOS;
493*ec779b8eSAndroid Build Coastguard Worker break;
494*ec779b8eSAndroid Build Coastguard Worker case STOP:
495*ec779b8eSAndroid Build Coastguard Worker command->result = stop_l();
496*ec779b8eSAndroid Build Coastguard Worker standbyTime = AudioClock::getNanoseconds() + IDLE_TIMEOUT_NANOS;
497*ec779b8eSAndroid Build Coastguard Worker break;
498*ec779b8eSAndroid Build Coastguard Worker case FLUSH:
499*ec779b8eSAndroid Build Coastguard Worker command->result = flush_l();
500*ec779b8eSAndroid Build Coastguard Worker break;
501*ec779b8eSAndroid Build Coastguard Worker case CLOSE:
502*ec779b8eSAndroid Build Coastguard Worker command->result = close_l();
503*ec779b8eSAndroid Build Coastguard Worker break;
504*ec779b8eSAndroid Build Coastguard Worker case DISCONNECT:
505*ec779b8eSAndroid Build Coastguard Worker disconnect_l();
506*ec779b8eSAndroid Build Coastguard Worker break;
507*ec779b8eSAndroid Build Coastguard Worker case REGISTER_AUDIO_THREAD: {
508*ec779b8eSAndroid Build Coastguard Worker auto param = (RegisterAudioThreadParam *) command->parameter.get();
509*ec779b8eSAndroid Build Coastguard Worker command->result =
510*ec779b8eSAndroid Build Coastguard Worker param == nullptr ? AAUDIO_ERROR_ILLEGAL_ARGUMENT
511*ec779b8eSAndroid Build Coastguard Worker : registerAudioThread_l(param->mOwnerPid,
512*ec779b8eSAndroid Build Coastguard Worker param->mClientThreadId,
513*ec779b8eSAndroid Build Coastguard Worker param->mPriority);
514*ec779b8eSAndroid Build Coastguard Worker }
515*ec779b8eSAndroid Build Coastguard Worker break;
516*ec779b8eSAndroid Build Coastguard Worker case UNREGISTER_AUDIO_THREAD: {
517*ec779b8eSAndroid Build Coastguard Worker auto param = (UnregisterAudioThreadParam *) command->parameter.get();
518*ec779b8eSAndroid Build Coastguard Worker command->result =
519*ec779b8eSAndroid Build Coastguard Worker param == nullptr ? AAUDIO_ERROR_ILLEGAL_ARGUMENT
520*ec779b8eSAndroid Build Coastguard Worker : unregisterAudioThread_l(param->mClientThreadId);
521*ec779b8eSAndroid Build Coastguard Worker }
522*ec779b8eSAndroid Build Coastguard Worker break;
523*ec779b8eSAndroid Build Coastguard Worker case GET_DESCRIPTION: {
524*ec779b8eSAndroid Build Coastguard Worker auto param = (GetDescriptionParam *) command->parameter.get();
525*ec779b8eSAndroid Build Coastguard Worker command->result = param == nullptr ? AAUDIO_ERROR_ILLEGAL_ARGUMENT
526*ec779b8eSAndroid Build Coastguard Worker : getDescription_l(param->mParcelable);
527*ec779b8eSAndroid Build Coastguard Worker }
528*ec779b8eSAndroid Build Coastguard Worker break;
529*ec779b8eSAndroid Build Coastguard Worker case EXIT_STANDBY: {
530*ec779b8eSAndroid Build Coastguard Worker auto param = (ExitStandbyParam *) command->parameter.get();
531*ec779b8eSAndroid Build Coastguard Worker command->result = param == nullptr ? AAUDIO_ERROR_ILLEGAL_ARGUMENT
532*ec779b8eSAndroid Build Coastguard Worker : exitStandby_l(param->mParcelable);
533*ec779b8eSAndroid Build Coastguard Worker standbyTime = AudioClock::getNanoseconds() + IDLE_TIMEOUT_NANOS;
534*ec779b8eSAndroid Build Coastguard Worker } break;
535*ec779b8eSAndroid Build Coastguard Worker case START_CLIENT: {
536*ec779b8eSAndroid Build Coastguard Worker auto param = (StartClientParam *) command->parameter.get();
537*ec779b8eSAndroid Build Coastguard Worker command->result = param == nullptr ? AAUDIO_ERROR_ILLEGAL_ARGUMENT
538*ec779b8eSAndroid Build Coastguard Worker : startClient_l(param->mClient,
539*ec779b8eSAndroid Build Coastguard Worker param->mAttr,
540*ec779b8eSAndroid Build Coastguard Worker param->mClientHandle);
541*ec779b8eSAndroid Build Coastguard Worker } break;
542*ec779b8eSAndroid Build Coastguard Worker case STOP_CLIENT: {
543*ec779b8eSAndroid Build Coastguard Worker auto param = (StopClientParam *) command->parameter.get();
544*ec779b8eSAndroid Build Coastguard Worker command->result = param == nullptr ? AAUDIO_ERROR_ILLEGAL_ARGUMENT
545*ec779b8eSAndroid Build Coastguard Worker : stopClient_l(param->mClientHandle);
546*ec779b8eSAndroid Build Coastguard Worker } break;
547*ec779b8eSAndroid Build Coastguard Worker default:
548*ec779b8eSAndroid Build Coastguard Worker ALOGE("Invalid command op code: %d", command->operationCode);
549*ec779b8eSAndroid Build Coastguard Worker break;
550*ec779b8eSAndroid Build Coastguard Worker }
551*ec779b8eSAndroid Build Coastguard Worker if (command->isWaitingForReply) {
552*ec779b8eSAndroid Build Coastguard Worker command->isWaitingForReply = false;
553*ec779b8eSAndroid Build Coastguard Worker command->conditionVariable.notify_one();
554*ec779b8eSAndroid Build Coastguard Worker }
555*ec779b8eSAndroid Build Coastguard Worker }
556*ec779b8eSAndroid Build Coastguard Worker }
557*ec779b8eSAndroid Build Coastguard Worker ALOGD("%s() %s exiting after %d loops <<<<<<<<<<<<<< COMMANDS",
558*ec779b8eSAndroid Build Coastguard Worker __func__, getTypeText(), loopCount);
559*ec779b8eSAndroid Build Coastguard Worker }
560*ec779b8eSAndroid Build Coastguard Worker
disconnect()561*ec779b8eSAndroid Build Coastguard Worker void AAudioServiceStreamBase::disconnect() {
562*ec779b8eSAndroid Build Coastguard Worker sendCommand(DISCONNECT);
563*ec779b8eSAndroid Build Coastguard Worker }
564*ec779b8eSAndroid Build Coastguard Worker
disconnect_l()565*ec779b8eSAndroid Build Coastguard Worker void AAudioServiceStreamBase::disconnect_l() {
566*ec779b8eSAndroid Build Coastguard Worker if (!isDisconnected_l() && getState() != AAUDIO_STREAM_STATE_CLOSED) {
567*ec779b8eSAndroid Build Coastguard Worker
568*ec779b8eSAndroid Build Coastguard Worker mediametrics::LogItem(mMetricsId)
569*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_DISCONNECT)
570*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_STATE, AudioGlobal_convertStreamStateToText(getState()))
571*ec779b8eSAndroid Build Coastguard Worker .record();
572*ec779b8eSAndroid Build Coastguard Worker
573*ec779b8eSAndroid Build Coastguard Worker sendServiceEvent(AAUDIO_SERVICE_EVENT_DISCONNECTED);
574*ec779b8eSAndroid Build Coastguard Worker setDisconnected_l(true);
575*ec779b8eSAndroid Build Coastguard Worker }
576*ec779b8eSAndroid Build Coastguard Worker }
577*ec779b8eSAndroid Build Coastguard Worker
registerAudioThread(pid_t clientThreadId,int priority)578*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t AAudioServiceStreamBase::registerAudioThread(pid_t clientThreadId, int priority) {
579*ec779b8eSAndroid Build Coastguard Worker const pid_t ownerPid = IPCThreadState::self()->getCallingPid(); // TODO review
580*ec779b8eSAndroid Build Coastguard Worker return sendCommand(REGISTER_AUDIO_THREAD,
581*ec779b8eSAndroid Build Coastguard Worker std::make_shared<RegisterAudioThreadParam>(ownerPid, clientThreadId, priority),
582*ec779b8eSAndroid Build Coastguard Worker true /*waitForReply*/,
583*ec779b8eSAndroid Build Coastguard Worker TIMEOUT_NANOS);
584*ec779b8eSAndroid Build Coastguard Worker }
585*ec779b8eSAndroid Build Coastguard Worker
registerAudioThread_l(pid_t ownerPid,pid_t clientThreadId,int priority)586*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t AAudioServiceStreamBase::registerAudioThread_l(
587*ec779b8eSAndroid Build Coastguard Worker pid_t ownerPid, pid_t clientThreadId, int priority) {
588*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t result = AAUDIO_OK;
589*ec779b8eSAndroid Build Coastguard Worker if (getRegisteredThread() != AAudioServiceStreamBase::ILLEGAL_THREAD_ID) {
590*ec779b8eSAndroid Build Coastguard Worker ALOGE("AAudioService::registerAudioThread(), thread already registered");
591*ec779b8eSAndroid Build Coastguard Worker result = AAUDIO_ERROR_INVALID_STATE;
592*ec779b8eSAndroid Build Coastguard Worker } else {
593*ec779b8eSAndroid Build Coastguard Worker setRegisteredThread(clientThreadId);
594*ec779b8eSAndroid Build Coastguard Worker int err = android::requestPriority(ownerPid, clientThreadId,
595*ec779b8eSAndroid Build Coastguard Worker priority, true /* isForApp */);
596*ec779b8eSAndroid Build Coastguard Worker if (err != 0) {
597*ec779b8eSAndroid Build Coastguard Worker ALOGE("AAudioService::registerAudioThread(%d) failed, errno = %d, priority = %d",
598*ec779b8eSAndroid Build Coastguard Worker clientThreadId, errno, priority);
599*ec779b8eSAndroid Build Coastguard Worker result = AAUDIO_ERROR_INTERNAL;
600*ec779b8eSAndroid Build Coastguard Worker }
601*ec779b8eSAndroid Build Coastguard Worker }
602*ec779b8eSAndroid Build Coastguard Worker return result;
603*ec779b8eSAndroid Build Coastguard Worker }
604*ec779b8eSAndroid Build Coastguard Worker
unregisterAudioThread(pid_t clientThreadId)605*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t AAudioServiceStreamBase::unregisterAudioThread(pid_t clientThreadId) {
606*ec779b8eSAndroid Build Coastguard Worker return sendCommand(UNREGISTER_AUDIO_THREAD,
607*ec779b8eSAndroid Build Coastguard Worker std::make_shared<UnregisterAudioThreadParam>(clientThreadId),
608*ec779b8eSAndroid Build Coastguard Worker true /*waitForReply*/,
609*ec779b8eSAndroid Build Coastguard Worker TIMEOUT_NANOS);
610*ec779b8eSAndroid Build Coastguard Worker }
611*ec779b8eSAndroid Build Coastguard Worker
unregisterAudioThread_l(pid_t clientThreadId)612*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t AAudioServiceStreamBase::unregisterAudioThread_l(pid_t clientThreadId) {
613*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t result = AAUDIO_OK;
614*ec779b8eSAndroid Build Coastguard Worker if (getRegisteredThread() != clientThreadId) {
615*ec779b8eSAndroid Build Coastguard Worker ALOGE("%s(), wrong thread", __func__);
616*ec779b8eSAndroid Build Coastguard Worker result = AAUDIO_ERROR_ILLEGAL_ARGUMENT;
617*ec779b8eSAndroid Build Coastguard Worker } else {
618*ec779b8eSAndroid Build Coastguard Worker setRegisteredThread(0);
619*ec779b8eSAndroid Build Coastguard Worker }
620*ec779b8eSAndroid Build Coastguard Worker return result;
621*ec779b8eSAndroid Build Coastguard Worker }
622*ec779b8eSAndroid Build Coastguard Worker
setState(aaudio_stream_state_t state)623*ec779b8eSAndroid Build Coastguard Worker void AAudioServiceStreamBase::setState(aaudio_stream_state_t state) {
624*ec779b8eSAndroid Build Coastguard Worker // CLOSED is a final state.
625*ec779b8eSAndroid Build Coastguard Worker if (mState != AAUDIO_STREAM_STATE_CLOSED) {
626*ec779b8eSAndroid Build Coastguard Worker mState = state;
627*ec779b8eSAndroid Build Coastguard Worker } else {
628*ec779b8eSAndroid Build Coastguard Worker ALOGW_IF(mState != state, "%s(%d) when already CLOSED", __func__, state);
629*ec779b8eSAndroid Build Coastguard Worker }
630*ec779b8eSAndroid Build Coastguard Worker }
631*ec779b8eSAndroid Build Coastguard Worker
sendServiceEvent(aaudio_service_event_t event,double dataDouble)632*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t AAudioServiceStreamBase::sendServiceEvent(aaudio_service_event_t event,
633*ec779b8eSAndroid Build Coastguard Worker double dataDouble) {
634*ec779b8eSAndroid Build Coastguard Worker AAudioServiceMessage command;
635*ec779b8eSAndroid Build Coastguard Worker command.what = AAudioServiceMessage::code::EVENT;
636*ec779b8eSAndroid Build Coastguard Worker command.event.event = event;
637*ec779b8eSAndroid Build Coastguard Worker command.event.dataDouble = dataDouble;
638*ec779b8eSAndroid Build Coastguard Worker return writeUpMessageQueue(&command);
639*ec779b8eSAndroid Build Coastguard Worker }
640*ec779b8eSAndroid Build Coastguard Worker
sendServiceEvent(aaudio_service_event_t event,int64_t dataLong)641*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t AAudioServiceStreamBase::sendServiceEvent(aaudio_service_event_t event,
642*ec779b8eSAndroid Build Coastguard Worker int64_t dataLong) {
643*ec779b8eSAndroid Build Coastguard Worker AAudioServiceMessage command;
644*ec779b8eSAndroid Build Coastguard Worker command.what = AAudioServiceMessage::code::EVENT;
645*ec779b8eSAndroid Build Coastguard Worker command.event.event = event;
646*ec779b8eSAndroid Build Coastguard Worker command.event.dataLong = dataLong;
647*ec779b8eSAndroid Build Coastguard Worker return writeUpMessageQueue(&command);
648*ec779b8eSAndroid Build Coastguard Worker }
649*ec779b8eSAndroid Build Coastguard Worker
isUpMessageQueueBusy()650*ec779b8eSAndroid Build Coastguard Worker bool AAudioServiceStreamBase::isUpMessageQueueBusy() {
651*ec779b8eSAndroid Build Coastguard Worker std::lock_guard<std::mutex> lock(mUpMessageQueueLock);
652*ec779b8eSAndroid Build Coastguard Worker if (mUpMessageQueue == nullptr) {
653*ec779b8eSAndroid Build Coastguard Worker ALOGE("%s(): mUpMessageQueue null! - stream not open", __func__);
654*ec779b8eSAndroid Build Coastguard Worker return true;
655*ec779b8eSAndroid Build Coastguard Worker }
656*ec779b8eSAndroid Build Coastguard Worker // Is it half full or more
657*ec779b8eSAndroid Build Coastguard Worker return mUpMessageQueue->getFractionalFullness() >= 0.5;
658*ec779b8eSAndroid Build Coastguard Worker }
659*ec779b8eSAndroid Build Coastguard Worker
writeUpMessageQueue(AAudioServiceMessage * command)660*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t AAudioServiceStreamBase::writeUpMessageQueue(AAudioServiceMessage *command) {
661*ec779b8eSAndroid Build Coastguard Worker std::lock_guard<std::mutex> lock(mUpMessageQueueLock);
662*ec779b8eSAndroid Build Coastguard Worker if (mUpMessageQueue == nullptr) {
663*ec779b8eSAndroid Build Coastguard Worker ALOGE("%s(): mUpMessageQueue null! - stream not open", __func__);
664*ec779b8eSAndroid Build Coastguard Worker return AAUDIO_ERROR_NULL;
665*ec779b8eSAndroid Build Coastguard Worker }
666*ec779b8eSAndroid Build Coastguard Worker int32_t count = mUpMessageQueue->getFifoBuffer()->write(command, 1);
667*ec779b8eSAndroid Build Coastguard Worker if (count != 1) {
668*ec779b8eSAndroid Build Coastguard Worker ALOGW("%s(): Queue full. Did client stop? Suspending stream. what = %u, %s",
669*ec779b8eSAndroid Build Coastguard Worker __func__, static_cast<unsigned>(command->what), getTypeText());
670*ec779b8eSAndroid Build Coastguard Worker setSuspended(true);
671*ec779b8eSAndroid Build Coastguard Worker return AAUDIO_ERROR_WOULD_BLOCK;
672*ec779b8eSAndroid Build Coastguard Worker } else {
673*ec779b8eSAndroid Build Coastguard Worker if (isSuspended()) {
674*ec779b8eSAndroid Build Coastguard Worker ALOGW("%s(): Queue no longer full. Un-suspending the stream.", __func__);
675*ec779b8eSAndroid Build Coastguard Worker setSuspended(false);
676*ec779b8eSAndroid Build Coastguard Worker }
677*ec779b8eSAndroid Build Coastguard Worker return AAUDIO_OK;
678*ec779b8eSAndroid Build Coastguard Worker }
679*ec779b8eSAndroid Build Coastguard Worker }
680*ec779b8eSAndroid Build Coastguard Worker
sendXRunCount(int32_t xRunCount)681*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t AAudioServiceStreamBase::sendXRunCount(int32_t xRunCount) {
682*ec779b8eSAndroid Build Coastguard Worker return sendServiceEvent(AAUDIO_SERVICE_EVENT_XRUN, (int64_t) xRunCount);
683*ec779b8eSAndroid Build Coastguard Worker }
684*ec779b8eSAndroid Build Coastguard Worker
sendCurrentTimestamp_l()685*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t AAudioServiceStreamBase::sendCurrentTimestamp_l() {
686*ec779b8eSAndroid Build Coastguard Worker AAudioServiceMessage command;
687*ec779b8eSAndroid Build Coastguard Worker // It is not worth filling up the queue with timestamps.
688*ec779b8eSAndroid Build Coastguard Worker // That can cause the stream to get suspended.
689*ec779b8eSAndroid Build Coastguard Worker // So just drop the timestamp if the queue is getting full.
690*ec779b8eSAndroid Build Coastguard Worker if (isUpMessageQueueBusy()) {
691*ec779b8eSAndroid Build Coastguard Worker return AAUDIO_OK;
692*ec779b8eSAndroid Build Coastguard Worker }
693*ec779b8eSAndroid Build Coastguard Worker
694*ec779b8eSAndroid Build Coastguard Worker // Send a timestamp for the clock model.
695*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t result = getFreeRunningPosition_l(&command.timestamp.position,
696*ec779b8eSAndroid Build Coastguard Worker &command.timestamp.timestamp);
697*ec779b8eSAndroid Build Coastguard Worker if (result == AAUDIO_OK) {
698*ec779b8eSAndroid Build Coastguard Worker ALOGV("%s() SERVICE %8lld at %lld", __func__,
699*ec779b8eSAndroid Build Coastguard Worker (long long) command.timestamp.position,
700*ec779b8eSAndroid Build Coastguard Worker (long long) command.timestamp.timestamp);
701*ec779b8eSAndroid Build Coastguard Worker command.what = AAudioServiceMessage::code::TIMESTAMP_SERVICE;
702*ec779b8eSAndroid Build Coastguard Worker result = writeUpMessageQueue(&command);
703*ec779b8eSAndroid Build Coastguard Worker
704*ec779b8eSAndroid Build Coastguard Worker if (result == AAUDIO_OK) {
705*ec779b8eSAndroid Build Coastguard Worker // Send a hardware timestamp for presentation time.
706*ec779b8eSAndroid Build Coastguard Worker result = getHardwareTimestamp_l(&command.timestamp.position,
707*ec779b8eSAndroid Build Coastguard Worker &command.timestamp.timestamp);
708*ec779b8eSAndroid Build Coastguard Worker if (result == AAUDIO_OK) {
709*ec779b8eSAndroid Build Coastguard Worker ALOGV("%s() HARDWARE %8lld at %lld", __func__,
710*ec779b8eSAndroid Build Coastguard Worker (long long) command.timestamp.position,
711*ec779b8eSAndroid Build Coastguard Worker (long long) command.timestamp.timestamp);
712*ec779b8eSAndroid Build Coastguard Worker command.what = AAudioServiceMessage::code::TIMESTAMP_HARDWARE;
713*ec779b8eSAndroid Build Coastguard Worker result = writeUpMessageQueue(&command);
714*ec779b8eSAndroid Build Coastguard Worker }
715*ec779b8eSAndroid Build Coastguard Worker }
716*ec779b8eSAndroid Build Coastguard Worker }
717*ec779b8eSAndroid Build Coastguard Worker
718*ec779b8eSAndroid Build Coastguard Worker if (result == AAUDIO_ERROR_UNAVAILABLE) { // TODO review best error code
719*ec779b8eSAndroid Build Coastguard Worker result = AAUDIO_OK; // just not available yet, try again later
720*ec779b8eSAndroid Build Coastguard Worker }
721*ec779b8eSAndroid Build Coastguard Worker return result;
722*ec779b8eSAndroid Build Coastguard Worker }
723*ec779b8eSAndroid Build Coastguard Worker
724*ec779b8eSAndroid Build Coastguard Worker /**
725*ec779b8eSAndroid Build Coastguard Worker * Get an immutable description of the in-memory queues
726*ec779b8eSAndroid Build Coastguard Worker * used to communicate with the underlying HAL or Service.
727*ec779b8eSAndroid Build Coastguard Worker */
getDescription(AudioEndpointParcelable & parcelable)728*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t AAudioServiceStreamBase::getDescription(AudioEndpointParcelable &parcelable) {
729*ec779b8eSAndroid Build Coastguard Worker return sendCommand(
730*ec779b8eSAndroid Build Coastguard Worker GET_DESCRIPTION,
731*ec779b8eSAndroid Build Coastguard Worker std::make_shared<GetDescriptionParam>(&parcelable),
732*ec779b8eSAndroid Build Coastguard Worker true /*waitForReply*/,
733*ec779b8eSAndroid Build Coastguard Worker TIMEOUT_NANOS);
734*ec779b8eSAndroid Build Coastguard Worker }
735*ec779b8eSAndroid Build Coastguard Worker
getDescription_l(AudioEndpointParcelable * parcelable)736*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t AAudioServiceStreamBase::getDescription_l(AudioEndpointParcelable* parcelable) {
737*ec779b8eSAndroid Build Coastguard Worker {
738*ec779b8eSAndroid Build Coastguard Worker std::lock_guard<std::mutex> lock(mUpMessageQueueLock);
739*ec779b8eSAndroid Build Coastguard Worker if (mUpMessageQueue == nullptr) {
740*ec779b8eSAndroid Build Coastguard Worker ALOGE("%s(): mUpMessageQueue null! - stream not open", __func__);
741*ec779b8eSAndroid Build Coastguard Worker return AAUDIO_ERROR_NULL;
742*ec779b8eSAndroid Build Coastguard Worker }
743*ec779b8eSAndroid Build Coastguard Worker // Gather information on the message queue.
744*ec779b8eSAndroid Build Coastguard Worker mUpMessageQueue->fillParcelable(parcelable,
745*ec779b8eSAndroid Build Coastguard Worker parcelable->mUpMessageQueueParcelable);
746*ec779b8eSAndroid Build Coastguard Worker }
747*ec779b8eSAndroid Build Coastguard Worker return getAudioDataDescription_l(parcelable);
748*ec779b8eSAndroid Build Coastguard Worker }
749*ec779b8eSAndroid Build Coastguard Worker
exitStandby(AudioEndpointParcelable * parcelable)750*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t AAudioServiceStreamBase::exitStandby(AudioEndpointParcelable *parcelable) {
751*ec779b8eSAndroid Build Coastguard Worker auto command = std::make_shared<AAudioCommand>(
752*ec779b8eSAndroid Build Coastguard Worker EXIT_STANDBY,
753*ec779b8eSAndroid Build Coastguard Worker std::make_shared<ExitStandbyParam>(parcelable),
754*ec779b8eSAndroid Build Coastguard Worker true /*waitForReply*/,
755*ec779b8eSAndroid Build Coastguard Worker TIMEOUT_NANOS);
756*ec779b8eSAndroid Build Coastguard Worker return mCommandQueue.sendCommand(command);
757*ec779b8eSAndroid Build Coastguard Worker }
758*ec779b8eSAndroid Build Coastguard Worker
sendStartClientCommand(const android::AudioClient & client,const audio_attributes_t * attr,audio_port_handle_t * clientHandle)759*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t AAudioServiceStreamBase::sendStartClientCommand(const android::AudioClient &client,
760*ec779b8eSAndroid Build Coastguard Worker const audio_attributes_t *attr,
761*ec779b8eSAndroid Build Coastguard Worker audio_port_handle_t *clientHandle) {
762*ec779b8eSAndroid Build Coastguard Worker auto command = std::make_shared<AAudioCommand>(
763*ec779b8eSAndroid Build Coastguard Worker START_CLIENT,
764*ec779b8eSAndroid Build Coastguard Worker std::make_shared<StartClientParam>(client, attr, clientHandle),
765*ec779b8eSAndroid Build Coastguard Worker true /*waitForReply*/,
766*ec779b8eSAndroid Build Coastguard Worker TIMEOUT_NANOS);
767*ec779b8eSAndroid Build Coastguard Worker return mCommandQueue.sendCommand(command);
768*ec779b8eSAndroid Build Coastguard Worker }
769*ec779b8eSAndroid Build Coastguard Worker
sendStopClientCommand(audio_port_handle_t clientHandle)770*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t AAudioServiceStreamBase::sendStopClientCommand(audio_port_handle_t clientHandle) {
771*ec779b8eSAndroid Build Coastguard Worker auto command = std::make_shared<AAudioCommand>(
772*ec779b8eSAndroid Build Coastguard Worker STOP_CLIENT,
773*ec779b8eSAndroid Build Coastguard Worker std::make_shared<StopClientParam>(clientHandle),
774*ec779b8eSAndroid Build Coastguard Worker true /*waitForReply*/,
775*ec779b8eSAndroid Build Coastguard Worker TIMEOUT_NANOS);
776*ec779b8eSAndroid Build Coastguard Worker return mCommandQueue.sendCommand(command);
777*ec779b8eSAndroid Build Coastguard Worker }
778*ec779b8eSAndroid Build Coastguard Worker
onVolumeChanged(float volume)779*ec779b8eSAndroid Build Coastguard Worker void AAudioServiceStreamBase::onVolumeChanged(float volume) {
780*ec779b8eSAndroid Build Coastguard Worker sendServiceEvent(AAUDIO_SERVICE_EVENT_VOLUME, volume);
781*ec779b8eSAndroid Build Coastguard Worker }
782*ec779b8eSAndroid Build Coastguard Worker
sendCommand(aaudio_command_opcode opCode,std::shared_ptr<AAudioCommandParam> param,bool waitForReply,int64_t timeoutNanos)783*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t AAudioServiceStreamBase::sendCommand(aaudio_command_opcode opCode,
784*ec779b8eSAndroid Build Coastguard Worker std::shared_ptr<AAudioCommandParam> param,
785*ec779b8eSAndroid Build Coastguard Worker bool waitForReply,
786*ec779b8eSAndroid Build Coastguard Worker int64_t timeoutNanos) {
787*ec779b8eSAndroid Build Coastguard Worker return mCommandQueue.sendCommand(std::make_shared<AAudioCommand>(
788*ec779b8eSAndroid Build Coastguard Worker opCode, param, waitForReply, timeoutNanos));
789*ec779b8eSAndroid Build Coastguard Worker }
790*ec779b8eSAndroid Build Coastguard Worker
closeAndClear()791*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t AAudioServiceStreamBase::closeAndClear() {
792*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t result = AAUDIO_OK;
793*ec779b8eSAndroid Build Coastguard Worker sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
794*ec779b8eSAndroid Build Coastguard Worker if (endpoint == nullptr) {
795*ec779b8eSAndroid Build Coastguard Worker result = AAUDIO_ERROR_INVALID_STATE;
796*ec779b8eSAndroid Build Coastguard Worker } else {
797*ec779b8eSAndroid Build Coastguard Worker endpoint->unregisterStream(this);
798*ec779b8eSAndroid Build Coastguard Worker AAudioEndpointManager &endpointManager = AAudioEndpointManager::getInstance();
799*ec779b8eSAndroid Build Coastguard Worker endpointManager.closeEndpoint(endpoint);
800*ec779b8eSAndroid Build Coastguard Worker
801*ec779b8eSAndroid Build Coastguard Worker // AAudioService::closeStream() prevents two threads from closing at the same time.
802*ec779b8eSAndroid Build Coastguard Worker mServiceEndpoint.clear(); // endpoint will hold the pointer after this method returns.
803*ec779b8eSAndroid Build Coastguard Worker }
804*ec779b8eSAndroid Build Coastguard Worker
805*ec779b8eSAndroid Build Coastguard Worker setState(AAUDIO_STREAM_STATE_CLOSED);
806*ec779b8eSAndroid Build Coastguard Worker
807*ec779b8eSAndroid Build Coastguard Worker mediametrics::LogItem(mMetricsId)
808*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CLOSE)
809*ec779b8eSAndroid Build Coastguard Worker .record();
810*ec779b8eSAndroid Build Coastguard Worker return result;
811*ec779b8eSAndroid Build Coastguard Worker }
812*ec779b8eSAndroid Build Coastguard Worker
stopCommandThread()813*ec779b8eSAndroid Build Coastguard Worker void AAudioServiceStreamBase::stopCommandThread() {
814*ec779b8eSAndroid Build Coastguard Worker bool threadEnabled = true;
815*ec779b8eSAndroid Build Coastguard Worker if (mThreadEnabled.compare_exchange_strong(threadEnabled, false)) {
816*ec779b8eSAndroid Build Coastguard Worker mCommandQueue.stopWaiting();
817*ec779b8eSAndroid Build Coastguard Worker mCommandThread.stop();
818*ec779b8eSAndroid Build Coastguard Worker }
819*ec779b8eSAndroid Build Coastguard Worker }
820