xref: /aosp_15_r20/frameworks/av/services/oboeservice/AAudioServiceStreamBase.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
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