blob: 77abaf6ded1ab071712ebaf313d15f2cbe07c22f [file] [log] [blame]
Eric Laurent81784c32012-11-19 14:55:58 -08001/*
2**
3** Copyright 2012, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
Eric Laurent81784c32012-11-19 14:55:58 -080018#define LOG_TAG "AudioFlinger"
19//#define LOG_NDEBUG 0
Mikhail Naganov938be412019-09-04 11:38:47 -070020#define ATRACE_TAG ATRACE_TAG_AUDIO
Eric Laurent81784c32012-11-19 14:55:58 -080021
Andy Hungce240472023-07-19 11:40:07 -070022#include "MmapTracks.h"
23#include "PlaybackTracks.h"
24#include "RecordTracks.h"
25
26#include "Client.h"
27#include "IAfEffect.h"
28#include "IAfThread.h"
29#include "ResamplerBufferProvider.h"
30
31#include <audio_utils/minifloat.h>
32#include <media/AudioValidator.h>
33#include <media/RecordBufferConverter.h>
34#include <media/nbaio/Pipe.h>
35#include <media/nbaio/PipeReader.h>
36#include <mediautils/ServiceUtilities.h>
37#include <mediautils/SharedMemoryAllocator.h>
38#include <private/media/AudioTrackShared.h>
Eric Laurent81784c32012-11-19 14:55:58 -080039#include <utils/Log.h>
Mikhail Naganov938be412019-09-04 11:38:47 -070040#include <utils/Trace.h>
Eric Laurent81784c32012-11-19 14:55:58 -080041
Andy Hungce240472023-07-19 11:40:07 -070042#include <linux/futex.h>
43#include <math.h>
44#include <sys/syscall.h>
Glenn Kastenda6ef132013-01-10 12:31:01 -080045
Eric Laurent81784c32012-11-19 14:55:58 -080046// ----------------------------------------------------------------------------
47
48// Note: the following macro is used for extremely verbose logging message. In
49// order to run with ALOG_ASSERT turned on, we need to have LOG_NDEBUG set to
50// 0; but one side effect of this is to turn all LOGV's as well. Some messages
51// are so verbose that we want to suppress them even when we have ALOG_ASSERT
52// turned on. Do not uncomment the #def below unless you really know what you
53// are doing and want to see all of the extremely verbose messages.
54//#define VERY_VERY_VERBOSE_LOGGING
55#ifdef VERY_VERY_VERBOSE_LOGGING
56#define ALOGVV ALOGV
57#else
58#define ALOGVV(a...) do { } while(0)
59#endif
60
Kuowei Lid4adbdb2020-08-13 14:44:25 +080061// TODO: Remove when this is put into AidlConversionUtil.h
62#define VALUE_OR_RETURN_BINDER_STATUS(x) \
63 ({ \
64 auto _tmp = (x); \
65 if (!_tmp.ok()) return ::android::aidl_utils::binderStatusFromStatusT(_tmp.error()); \
66 std::move(_tmp.value()); \
67 })
68
Eric Laurent81784c32012-11-19 14:55:58 -080069namespace android {
70
Kuowei Lid4adbdb2020-08-13 14:44:25 +080071using ::android::aidl_utils::binderStatusFromStatusT;
Ytai Ben-Tsvibdc293a2020-11-02 17:01:38 -080072using binder::Status;
Svet Ganov33761132021-05-13 22:51:08 +000073using content::AttributionSourceState;
Ivan Lozano8cf3a072017-08-09 09:01:33 -070074using media::VolumeShaper;
Eric Laurent81784c32012-11-19 14:55:58 -080075// ----------------------------------------------------------------------------
76// TrackBase
77// ----------------------------------------------------------------------------
Andy Hung9d84af52018-09-12 18:03:44 -070078#undef LOG_TAG
79#define LOG_TAG "AF::TrackBase"
Eric Laurent81784c32012-11-19 14:55:58 -080080
Glenn Kastenda6ef132013-01-10 12:31:01 -080081static volatile int32_t nextTrackId = 55;
82
Eric Laurent81784c32012-11-19 14:55:58 -080083// TrackBase constructor must be called with AudioFlinger::mLock held
Andy Hung3ff4b552023-06-26 19:20:57 -070084TrackBase::TrackBase(
Andy Hung44f27182023-07-06 20:56:16 -070085 IAfThreadBase *thread,
Eric Laurent81784c32012-11-19 14:55:58 -080086 const sp<Client>& client,
Kevin Rocard1f564ac2018-03-29 13:53:10 -070087 const audio_attributes_t& attr,
Eric Laurent81784c32012-11-19 14:55:58 -080088 uint32_t sampleRate,
89 audio_format_t format,
90 audio_channel_mask_t channelMask,
91 size_t frameCount,
Eric Laurent83b88082014-06-20 18:31:16 -070092 void *buffer,
Andy Hung8fe68032017-06-05 16:17:51 -070093 size_t bufferSize,
Glenn Kastend848eb42016-03-08 13:42:11 -080094 audio_session_t sessionId,
Eric Laurent09f1ed22019-04-24 17:45:17 -070095 pid_t creatorPid,
Andy Hung1f12a8a2016-11-07 16:10:30 -080096 uid_t clientUid,
Glenn Kastend776ac62014-05-07 09:16:09 -070097 bool isOut,
Dmitry Sidorenkova41c2732023-05-15 13:47:07 -070098 const alloc_type alloc,
Eric Laurent20b9ef02016-12-05 11:03:16 -080099 track_type type,
Andy Hungb68f5eb2019-12-03 16:49:17 -0800100 audio_port_handle_t portId,
101 std::string metricsId)
Andy Hung02a6c4e2023-06-23 19:27:19 -0700102 :
Eric Laurent81784c32012-11-19 14:55:58 -0800103 mThread(thread),
Dmitry Sidorenkova41c2732023-05-15 13:47:07 -0700104 mAllocType(alloc),
Eric Laurent81784c32012-11-19 14:55:58 -0800105 mClient(client),
106 mCblk(NULL),
Andy Hung8fe68032017-06-05 16:17:51 -0700107 // mBuffer, mBufferSize
Eric Laurent81784c32012-11-19 14:55:58 -0800108 mState(IDLE),
Kevin Rocard1f564ac2018-03-29 13:53:10 -0700109 mAttr(attr),
Eric Laurent81784c32012-11-19 14:55:58 -0800110 mSampleRate(sampleRate),
111 mFormat(format),
112 mChannelMask(channelMask),
Andy Hunge5412692014-05-16 11:25:07 -0700113 mChannelCount(isOut ?
114 audio_channel_count_from_out_mask(channelMask) :
115 audio_channel_count_from_in_mask(channelMask)),
Dean Wheatleyd883e302023-10-20 06:11:43 +1100116 mFrameSize(audio_bytes_per_frame(mChannelCount, format)),
Eric Laurent81784c32012-11-19 14:55:58 -0800117 mFrameCount(frameCount),
Glenn Kastene3aa6592012-12-04 12:22:46 -0800118 mSessionId(sessionId),
119 mIsOut(isOut),
Eric Laurentbfb1b832013-01-07 09:53:42 -0800120 mId(android_atomic_inc(&nextTrackId)),
Eric Laurent83b88082014-06-20 18:31:16 -0700121 mTerminated(false),
Eric Laurentaaa44472014-09-12 17:41:50 -0700122 mType(type),
Kevin Rocard153f92d2018-12-18 18:33:28 -0800123 mThreadIoHandle(thread ? thread->id() : AUDIO_IO_HANDLE_NONE),
Eric Laurent6acd1d42017-01-04 14:23:29 -0800124 mPortId(portId),
Eric Laurent09f1ed22019-04-24 17:45:17 -0700125 mIsInvalid(false),
Kunal Malhotra3be68902023-02-28 22:03:15 +0000126 mTrackMetrics(std::move(metricsId), isOut, clientUid),
Eric Laurent09f1ed22019-04-24 17:45:17 -0700127 mCreatorPid(creatorPid)
Eric Laurent81784c32012-11-19 14:55:58 -0800128{
Marco Nelissendcb346b2015-09-09 10:47:29 -0700129 const uid_t callingUid = IPCThreadState::self()->getCallingUid();
Andy Hung4ef19fa2018-05-15 19:35:29 -0700130 if (!isAudioServerOrMediaServerUid(callingUid) || clientUid == AUDIO_UID_INVALID) {
Andy Hung1f12a8a2016-11-07 16:10:30 -0800131 ALOGW_IF(clientUid != AUDIO_UID_INVALID && clientUid != callingUid,
Andy Hung9d84af52018-09-12 18:03:44 -0700132 "%s(%d): uid %d tried to pass itself off as %d",
133 __func__, mId, callingUid, clientUid);
Andy Hung1f12a8a2016-11-07 16:10:30 -0800134 clientUid = callingUid;
Marco Nelissen462fd2f2013-01-14 14:12:05 -0800135 }
136 // clientUid contains the uid of the app that is responsible for this track, so we can blame
137 // battery usage on it.
138 mUid = clientUid;
139
Eric Laurent81784c32012-11-19 14:55:58 -0800140 // ALOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize);
Andy Hung1883f692017-02-13 18:48:39 -0800141
Andy Hung8fe68032017-06-05 16:17:51 -0700142 size_t minBufferSize = buffer == NULL ? roundup(frameCount) : frameCount;
Andy Hung1883f692017-02-13 18:48:39 -0800143 // check overflow when computing bufferSize due to multiplication by mFrameSize.
Andy Hung8fe68032017-06-05 16:17:51 -0700144 if (minBufferSize < frameCount // roundup rounds down for values above UINT_MAX / 2
Andy Hung1883f692017-02-13 18:48:39 -0800145 || mFrameSize == 0 // format needs to be correct
Andy Hung8fe68032017-06-05 16:17:51 -0700146 || minBufferSize > SIZE_MAX / mFrameSize) {
Andy Hung1883f692017-02-13 18:48:39 -0800147 android_errorWriteLog(0x534e4554, "34749571");
148 return;
149 }
Andy Hung8fe68032017-06-05 16:17:51 -0700150 minBufferSize *= mFrameSize;
151
152 if (buffer == nullptr) {
153 bufferSize = minBufferSize; // allocated here.
154 } else if (minBufferSize > bufferSize) {
155 android_errorWriteLog(0x534e4554, "38340117");
156 return;
157 }
Andy Hung1883f692017-02-13 18:48:39 -0800158
Eric Laurent81784c32012-11-19 14:55:58 -0800159 size_t size = sizeof(audio_track_cblk_t);
Eric Laurent83b88082014-06-20 18:31:16 -0700160 if (buffer == NULL && alloc == ALLOC_CBLK) {
Andy Hung1883f692017-02-13 18:48:39 -0800161 // check overflow when computing allocation size for streaming tracks.
162 if (size > SIZE_MAX - bufferSize) {
163 android_errorWriteLog(0x534e4554, "34749571");
164 return;
165 }
Eric Laurent81784c32012-11-19 14:55:58 -0800166 size += bufferSize;
167 }
168
169 if (client != 0) {
Atneya3c61d882021-09-20 14:52:15 -0400170 mCblkMemory = client->allocator().allocate(mediautils::NamedAllocRequest{{size},
171 std::string("Track ID: ").append(std::to_string(mId))});
Glenn Kasten663c2242013-09-24 11:52:37 -0700172 if (mCblkMemory == 0 ||
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -0700173 (mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->unsecurePointer())) == NULL) {
Andy Hung9d84af52018-09-12 18:03:44 -0700174 ALOGE("%s(%d): not enough memory for AudioTrack size=%zu", __func__, mId, size);
Atneya3c61d882021-09-20 14:52:15 -0400175 ALOGE("%s", client->allocator().dump().c_str());
Glenn Kasten663c2242013-09-24 11:52:37 -0700176 mCblkMemory.clear();
Eric Laurent81784c32012-11-19 14:55:58 -0800177 return;
178 }
179 } else {
Andy Hungafb31482017-02-13 18:50:48 -0800180 mCblk = (audio_track_cblk_t *) malloc(size);
181 if (mCblk == NULL) {
Andy Hung9d84af52018-09-12 18:03:44 -0700182 ALOGE("%s(%d): not enough memory for AudioTrack size=%zu", __func__, mId, size);
Andy Hungafb31482017-02-13 18:50:48 -0800183 return;
184 }
Eric Laurent81784c32012-11-19 14:55:58 -0800185 }
186
187 // construct the shared structure in-place.
188 if (mCblk != NULL) {
189 new(mCblk) audio_track_cblk_t();
Glenn Kastenc263ca02014-06-04 20:31:46 -0700190 switch (alloc) {
191 case ALLOC_READONLY: {
Glenn Kastend776ac62014-05-07 09:16:09 -0700192 const sp<MemoryDealer> roHeap(thread->readOnlyHeap());
193 if (roHeap == 0 ||
194 (mBufferMemory = roHeap->allocate(bufferSize)) == 0 ||
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -0700195 (mBuffer = mBufferMemory->unsecurePointer()) == NULL) {
Andy Hung9d84af52018-09-12 18:03:44 -0700196 ALOGE("%s(%d): not enough memory for read-only buffer size=%zu",
197 __func__, mId, bufferSize);
Glenn Kastend776ac62014-05-07 09:16:09 -0700198 if (roHeap != 0) {
199 roHeap->dump("buffer");
200 }
201 mCblkMemory.clear();
202 mBufferMemory.clear();
203 return;
204 }
Eric Laurent81784c32012-11-19 14:55:58 -0800205 memset(mBuffer, 0, bufferSize);
Glenn Kastenc263ca02014-06-04 20:31:46 -0700206 } break;
207 case ALLOC_PIPE:
208 mBufferMemory = thread->pipeMemory();
209 // mBuffer is the virtual address as seen from current process (mediaserver),
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -0700210 // and should normally be coming from mBufferMemory->unsecurePointer().
Glenn Kastenc263ca02014-06-04 20:31:46 -0700211 // However in this case the TrackBase does not reference the buffer directly.
212 // It should references the buffer via the pipe.
213 // Therefore, to detect incorrect usage of the buffer, we set mBuffer to NULL.
214 mBuffer = NULL;
Andy Hung8fe68032017-06-05 16:17:51 -0700215 bufferSize = 0;
Glenn Kastenc263ca02014-06-04 20:31:46 -0700216 break;
217 case ALLOC_CBLK:
Glenn Kastend776ac62014-05-07 09:16:09 -0700218 // clear all buffers
Eric Laurent83b88082014-06-20 18:31:16 -0700219 if (buffer == NULL) {
Glenn Kastend776ac62014-05-07 09:16:09 -0700220 mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
221 memset(mBuffer, 0, bufferSize);
222 } else {
Eric Laurent83b88082014-06-20 18:31:16 -0700223 mBuffer = buffer;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800224#if 0
Glenn Kastend776ac62014-05-07 09:16:09 -0700225 mCblk->mFlags = CBLK_FORCEREADY; // FIXME hack, need to fix the track ready logic
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800226#endif
Glenn Kastend776ac62014-05-07 09:16:09 -0700227 }
Glenn Kastenc263ca02014-06-04 20:31:46 -0700228 break;
Eric Laurent83b88082014-06-20 18:31:16 -0700229 case ALLOC_LOCAL:
230 mBuffer = calloc(1, bufferSize);
231 break;
232 case ALLOC_NONE:
233 mBuffer = buffer;
234 break;
Andy Hung8fe68032017-06-05 16:17:51 -0700235 default:
Andy Hung9d84af52018-09-12 18:03:44 -0700236 LOG_ALWAYS_FATAL("%s(%d): invalid allocation type: %d", __func__, mId, (int)alloc);
Eric Laurent81784c32012-11-19 14:55:58 -0800237 }
Andy Hung8fe68032017-06-05 16:17:51 -0700238 mBufferSize = bufferSize;
Glenn Kastenda6ef132013-01-10 12:31:01 -0800239
Glenn Kasten46909e72013-02-26 09:20:22 -0800240#ifdef TEE_SINK
Andy Hung8946a282018-04-19 20:04:56 -0700241 mTee.set(sampleRate, mChannelCount, format, NBAIO_Tee::TEE_FLAG_TRACK);
Glenn Kasten46909e72013-02-26 09:20:22 -0800242#endif
Andy Hung959b5b82021-09-24 10:46:20 -0700243 // mState is mirrored for the client to read.
244 mState.setMirror(&mCblk->mState);
245 // ensure our state matches up until we consolidate the enumeration.
246 static_assert(CBLK_STATE_IDLE == IDLE);
247 static_assert(CBLK_STATE_PAUSING == PAUSING);
Eric Laurent81784c32012-11-19 14:55:58 -0800248 }
249}
250
Svet Ganov33761132021-05-13 22:51:08 +0000251// TODO b/182392769: use attribution source util
252static AttributionSourceState audioServerAttributionSource(pid_t pid) {
253 AttributionSourceState attributionSource{};
254 attributionSource.uid = AID_AUDIOSERVER;
255 attributionSource.pid = pid;
256 attributionSource.token = sp<BBinder>::make();
257 return attributionSource;
Philip P. Moltmannbda45752020-07-17 16:41:18 -0700258}
259
Andy Hung3ff4b552023-06-26 19:20:57 -0700260status_t TrackBase::initCheck() const
Eric Laurent83b88082014-06-20 18:31:16 -0700261{
262 status_t status;
263 if (mType == TYPE_OUTPUT || mType == TYPE_PATCH) {
264 status = cblk() != NULL ? NO_ERROR : NO_MEMORY;
265 } else {
266 status = getCblk() != 0 ? NO_ERROR : NO_MEMORY;
267 }
268 return status;
269}
270
Andy Hung3ff4b552023-06-26 19:20:57 -0700271TrackBase::~TrackBase()
Eric Laurent81784c32012-11-19 14:55:58 -0800272{
Glenn Kastene3aa6592012-12-04 12:22:46 -0800273 // delete the proxy before deleting the shared memory it refers to, to avoid dangling reference
Eric Laurent5bba2f62016-03-18 11:14:14 -0700274 mServerProxy.clear();
Andy Hung689e82c2019-08-21 17:53:17 -0700275 releaseCblk();
Eric Laurent81784c32012-11-19 14:55:58 -0800276 mCblkMemory.clear(); // free the shared memory before releasing the heap it belongs to
277 if (mClient != 0) {
Eric Laurent021cf962014-05-13 10:18:14 -0700278 // Client destructor must run with AudioFlinger client mutex locked
Andy Hung2ac52f12023-08-28 18:36:53 -0700279 audio_utils::lock_guard _l(mClient->afClientCallback()->clientMutex());
Eric Laurent81784c32012-11-19 14:55:58 -0800280 // If the client's reference count drops to zero, the associated destructor
281 // must run with AudioFlinger lock held. Thus the explicit clear() rather than
282 // relying on the automatic clear() at end of scope.
283 mClient.clear();
284 }
Dmitry Sidorenkova41c2732023-05-15 13:47:07 -0700285 if (mAllocType == ALLOC_LOCAL) {
286 free(mBuffer);
287 mBuffer = nullptr;
288 }
Eric Laurent3bcffa12014-06-12 18:38:45 -0700289 // flush the binder command buffer
290 IPCThreadState::self()->flushCommands();
Eric Laurent81784c32012-11-19 14:55:58 -0800291}
292
293// AudioBufferProvider interface
294// getNextBuffer() = 0;
Glenn Kastend79072e2016-01-06 08:41:20 -0800295// This implementation of releaseBuffer() is used by Track and RecordTrack
Andy Hung3ff4b552023-06-26 19:20:57 -0700296void TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)
Eric Laurent81784c32012-11-19 14:55:58 -0800297{
Glenn Kasten46909e72013-02-26 09:20:22 -0800298#ifdef TEE_SINK
Andy Hung8946a282018-04-19 20:04:56 -0700299 mTee.write(buffer->raw, buffer->frameCount);
Glenn Kasten46909e72013-02-26 09:20:22 -0800300#endif
Glenn Kastenda6ef132013-01-10 12:31:01 -0800301
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800302 ServerProxy::Buffer buf;
303 buf.mFrameCount = buffer->frameCount;
304 buf.mRaw = buffer->raw;
Eric Laurent81784c32012-11-19 14:55:58 -0800305 buffer->frameCount = 0;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800306 buffer->raw = NULL;
307 mServerProxy->releaseBuffer(&buf);
Eric Laurent81784c32012-11-19 14:55:58 -0800308}
309
Andy Hung3ff4b552023-06-26 19:20:57 -0700310status_t TrackBase::setSyncEvent(
Andy Hung068e08e2023-05-15 19:02:55 -0700311 const sp<audioflinger::SyncEvent>& event)
Eric Laurent81784c32012-11-19 14:55:58 -0800312{
Andy Hung068e08e2023-05-15 19:02:55 -0700313 mSyncEvents.emplace_back(event);
Eric Laurent81784c32012-11-19 14:55:58 -0800314 return NO_ERROR;
315}
316
Andy Hung3ff4b552023-06-26 19:20:57 -0700317PatchTrackBase::PatchTrackBase(const sp<ClientProxy>& proxy,
Andy Hung837229a2023-07-14 16:57:01 -0700318 IAfThreadBase* thread, const Timeout& timeout)
Kevin Rocard45986c72018-12-18 18:22:59 -0800319 : mProxy(proxy)
320{
321 if (timeout) {
322 setPeerTimeout(*timeout);
323 } else {
324 // Double buffer mixer
Andy Hung837229a2023-07-14 16:57:01 -0700325 uint64_t mixBufferNs = ((uint64_t)2 * thread->frameCount() * 1000000000) /
326 thread->sampleRate();
Kevin Rocard45986c72018-12-18 18:22:59 -0800327 setPeerTimeout(std::chrono::nanoseconds{mixBufferNs});
328 }
329}
330
Andy Hung3ff4b552023-06-26 19:20:57 -0700331void PatchTrackBase::setPeerTimeout(std::chrono::nanoseconds timeout) {
Kevin Rocard45986c72018-12-18 18:22:59 -0800332 mPeerTimeout.tv_sec = timeout.count() / std::nano::den;
333 mPeerTimeout.tv_nsec = timeout.count() % std::nano::den;
334}
335
336
Eric Laurent81784c32012-11-19 14:55:58 -0800337// ----------------------------------------------------------------------------
338// Playback
339// ----------------------------------------------------------------------------
Andy Hung9d84af52018-09-12 18:03:44 -0700340#undef LOG_TAG
341#define LOG_TAG "AF::TrackHandle"
Eric Laurent81784c32012-11-19 14:55:58 -0800342
Andy Hungaaa18282023-06-23 19:27:19 -0700343class TrackHandle : public android::media::BnAudioTrack {
344public:
Andy Hung02a6c4e2023-06-23 19:27:19 -0700345 explicit TrackHandle(const sp<IAfTrack>& track);
Andy Hungaaa18282023-06-23 19:27:19 -0700346 ~TrackHandle() override;
347
348 binder::Status getCblk(std::optional<media::SharedFileRegion>* _aidl_return) final;
349 binder::Status start(int32_t* _aidl_return) final;
350 binder::Status stop() final;
351 binder::Status flush() final;
352 binder::Status pause() final;
353 binder::Status attachAuxEffect(int32_t effectId, int32_t* _aidl_return) final;
354 binder::Status setParameters(const std::string& keyValuePairs,
355 int32_t* _aidl_return) final;
356 binder::Status selectPresentation(int32_t presentationId, int32_t programId,
357 int32_t* _aidl_return) final;
358 binder::Status getTimestamp(media::AudioTimestampInternal* timestamp,
359 int32_t* _aidl_return) final;
360 binder::Status signal() final;
361 binder::Status applyVolumeShaper(const media::VolumeShaperConfiguration& configuration,
362 const media::VolumeShaperOperation& operation,
363 int32_t* _aidl_return) final;
364 binder::Status getVolumeShaperState(
365 int32_t id,
366 std::optional<media::VolumeShaperState>* _aidl_return) final;
367 binder::Status getDualMonoMode(
368 media::audio::common::AudioDualMonoMode* _aidl_return) final;
369 binder::Status setDualMonoMode(
370 media::audio::common::AudioDualMonoMode mode) final;
371 binder::Status getAudioDescriptionMixLevel(float* _aidl_return) final;
372 binder::Status setAudioDescriptionMixLevel(float leveldB) final;
373 binder::Status getPlaybackRateParameters(
374 media::audio::common::AudioPlaybackRate* _aidl_return) final;
375 binder::Status setPlaybackRateParameters(
376 const media::audio::common::AudioPlaybackRate& playbackRate) final;
377
378private:
Andy Hung02a6c4e2023-06-23 19:27:19 -0700379 const sp<IAfTrack> mTrack;
Andy Hungaaa18282023-06-23 19:27:19 -0700380};
381
382/* static */
Andy Hung02a6c4e2023-06-23 19:27:19 -0700383sp<media::IAudioTrack> IAfTrack::createIAudioTrackAdapter(const sp<IAfTrack>& track) {
Andy Hungaaa18282023-06-23 19:27:19 -0700384 return sp<TrackHandle>::make(track);
385}
386
Andy Hung02a6c4e2023-06-23 19:27:19 -0700387TrackHandle::TrackHandle(const sp<IAfTrack>& track)
Eric Laurent81784c32012-11-19 14:55:58 -0800388 : BnAudioTrack(),
389 mTrack(track)
390{
Andy Hung225aef62022-12-06 16:33:20 -0800391 setMinSchedulerPolicy(SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
Eric Laurent81784c32012-11-19 14:55:58 -0800392}
393
Andy Hungaaa18282023-06-23 19:27:19 -0700394TrackHandle::~TrackHandle() {
Eric Laurent81784c32012-11-19 14:55:58 -0800395 // just stop the track on deletion, associated resources
396 // will be freed from the main thread once all pending buffers have
397 // been played. Unless it's not in the active track list, in which
398 // case we free everything now...
399 mTrack->destroy();
400}
401
Andy Hungaaa18282023-06-23 19:27:19 -0700402Status TrackHandle::getCblk(
Ytai Ben-Tsvibdc293a2020-11-02 17:01:38 -0800403 std::optional<media::SharedFileRegion>* _aidl_return) {
404 *_aidl_return = legacy2aidl_NullableIMemory_SharedFileRegion(mTrack->getCblk()).value();
405 return Status::ok();
Eric Laurent81784c32012-11-19 14:55:58 -0800406}
407
Andy Hungaaa18282023-06-23 19:27:19 -0700408Status TrackHandle::start(int32_t* _aidl_return) {
Ytai Ben-Tsvibdc293a2020-11-02 17:01:38 -0800409 *_aidl_return = mTrack->start();
410 return Status::ok();
Eric Laurent81784c32012-11-19 14:55:58 -0800411}
412
Andy Hungaaa18282023-06-23 19:27:19 -0700413Status TrackHandle::stop() {
Eric Laurent81784c32012-11-19 14:55:58 -0800414 mTrack->stop();
Ytai Ben-Tsvibdc293a2020-11-02 17:01:38 -0800415 return Status::ok();
Eric Laurent81784c32012-11-19 14:55:58 -0800416}
417
Andy Hungaaa18282023-06-23 19:27:19 -0700418Status TrackHandle::flush() {
Eric Laurent81784c32012-11-19 14:55:58 -0800419 mTrack->flush();
Ytai Ben-Tsvibdc293a2020-11-02 17:01:38 -0800420 return Status::ok();
Eric Laurent81784c32012-11-19 14:55:58 -0800421}
422
Andy Hungaaa18282023-06-23 19:27:19 -0700423Status TrackHandle::pause() {
Eric Laurent81784c32012-11-19 14:55:58 -0800424 mTrack->pause();
Ytai Ben-Tsvibdc293a2020-11-02 17:01:38 -0800425 return Status::ok();
Eric Laurent81784c32012-11-19 14:55:58 -0800426}
427
Andy Hungaaa18282023-06-23 19:27:19 -0700428Status TrackHandle::attachAuxEffect(int32_t effectId,
Ytai Ben-Tsvibdc293a2020-11-02 17:01:38 -0800429 int32_t* _aidl_return) {
430 *_aidl_return = mTrack->attachAuxEffect(effectId);
431 return Status::ok();
Eric Laurent81784c32012-11-19 14:55:58 -0800432}
433
Andy Hungaaa18282023-06-23 19:27:19 -0700434Status TrackHandle::setParameters(const std::string& keyValuePairs,
Ytai Ben-Tsvibdc293a2020-11-02 17:01:38 -0800435 int32_t* _aidl_return) {
436 *_aidl_return = mTrack->setParameters(String8(keyValuePairs.c_str()));
437 return Status::ok();
Glenn Kasten3dcd00d2013-07-17 10:10:23 -0700438}
439
Andy Hungaaa18282023-06-23 19:27:19 -0700440Status TrackHandle::selectPresentation(int32_t presentationId, int32_t programId,
Ytai Ben-Tsvibdc293a2020-11-02 17:01:38 -0800441 int32_t* _aidl_return) {
442 *_aidl_return = mTrack->selectPresentation(presentationId, programId);
443 return Status::ok();
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800444}
445
Andy Hungaaa18282023-06-23 19:27:19 -0700446Status TrackHandle::getTimestamp(media::AudioTimestampInternal* timestamp,
Ytai Ben-Tsvibdc293a2020-11-02 17:01:38 -0800447 int32_t* _aidl_return) {
448 AudioTimestamp legacy;
449 *_aidl_return = mTrack->getTimestamp(legacy);
450 if (*_aidl_return != OK) {
451 return Status::ok();
452 }
Dorin Drimusbbddde02023-11-13 15:01:33 +0000453
454 // restrict position modulo INT_MAX to avoid integer sanitization abort
455 legacy.mPosition &= INT_MAX;
456
Andy Hung973638a2020-12-08 20:47:45 -0800457 *timestamp = legacy2aidl_AudioTimestamp_AudioTimestampInternal(legacy).value();
Ytai Ben-Tsvibdc293a2020-11-02 17:01:38 -0800458 return Status::ok();
Andy Hung9fc8b5c2017-01-24 13:36:48 -0800459}
460
Andy Hungaaa18282023-06-23 19:27:19 -0700461Status TrackHandle::signal() {
Ytai Ben-Tsvibdc293a2020-11-02 17:01:38 -0800462 mTrack->signal();
463 return Status::ok();
Andy Hung9fc8b5c2017-01-24 13:36:48 -0800464}
465
Andy Hungaaa18282023-06-23 19:27:19 -0700466Status TrackHandle::applyVolumeShaper(
Ytai Ben-Tsvibdc293a2020-11-02 17:01:38 -0800467 const media::VolumeShaperConfiguration& configuration,
468 const media::VolumeShaperOperation& operation,
469 int32_t* _aidl_return) {
470 sp<VolumeShaper::Configuration> conf = new VolumeShaper::Configuration();
471 *_aidl_return = conf->readFromParcelable(configuration);
472 if (*_aidl_return != OK) {
473 return Status::ok();
474 }
475
476 sp<VolumeShaper::Operation> op = new VolumeShaper::Operation();
477 *_aidl_return = op->readFromParcelable(operation);
478 if (*_aidl_return != OK) {
479 return Status::ok();
480 }
481
482 *_aidl_return = mTrack->applyVolumeShaper(conf, op);
483 return Status::ok();
Glenn Kasten53cec222013-08-29 09:01:02 -0700484}
485
Andy Hungaaa18282023-06-23 19:27:19 -0700486Status TrackHandle::getVolumeShaperState(
Ytai Ben-Tsvibdc293a2020-11-02 17:01:38 -0800487 int32_t id,
488 std::optional<media::VolumeShaperState>* _aidl_return) {
489 sp<VolumeShaper::State> legacy = mTrack->getVolumeShaperState(id);
490 if (legacy == nullptr) {
491 _aidl_return->reset();
492 return Status::ok();
493 }
494 media::VolumeShaperState aidl;
495 legacy->writeToParcelable(&aidl);
496 *_aidl_return = aidl;
497 return Status::ok();
Eric Laurent81784c32012-11-19 14:55:58 -0800498}
499
Andy Hungaaa18282023-06-23 19:27:19 -0700500Status TrackHandle::getDualMonoMode(
Mikhail Naganova77d5552022-12-18 02:48:14 +0000501 media::audio::common::AudioDualMonoMode* _aidl_return)
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800502{
503 audio_dual_mono_mode_t mode = AUDIO_DUAL_MONO_MODE_OFF;
504 const status_t status = mTrack->getDualMonoMode(&mode)
505 ?: AudioValidator::validateDualMonoMode(mode);
506 if (status == OK) {
507 *_aidl_return = VALUE_OR_RETURN_BINDER_STATUS(
508 legacy2aidl_audio_dual_mono_mode_t_AudioDualMonoMode(mode));
509 }
510 return binderStatusFromStatusT(status);
511}
512
Andy Hungaaa18282023-06-23 19:27:19 -0700513Status TrackHandle::setDualMonoMode(
Mikhail Naganova77d5552022-12-18 02:48:14 +0000514 media::audio::common::AudioDualMonoMode mode)
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800515{
516 const auto localMonoMode = VALUE_OR_RETURN_BINDER_STATUS(
517 aidl2legacy_AudioDualMonoMode_audio_dual_mono_mode_t(mode));
518 return binderStatusFromStatusT(AudioValidator::validateDualMonoMode(localMonoMode)
519 ?: mTrack->setDualMonoMode(localMonoMode));
520}
521
Andy Hungaaa18282023-06-23 19:27:19 -0700522Status TrackHandle::getAudioDescriptionMixLevel(float* _aidl_return)
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800523{
524 float leveldB = -std::numeric_limits<float>::infinity();
525 const status_t status = mTrack->getAudioDescriptionMixLevel(&leveldB)
526 ?: AudioValidator::validateAudioDescriptionMixLevel(leveldB);
527 if (status == OK) *_aidl_return = leveldB;
528 return binderStatusFromStatusT(status);
529}
530
Andy Hungaaa18282023-06-23 19:27:19 -0700531Status TrackHandle::setAudioDescriptionMixLevel(float leveldB)
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800532{
533 return binderStatusFromStatusT(AudioValidator::validateAudioDescriptionMixLevel(leveldB)
534 ?: mTrack->setAudioDescriptionMixLevel(leveldB));
535}
536
Andy Hungaaa18282023-06-23 19:27:19 -0700537Status TrackHandle::getPlaybackRateParameters(
Mikhail Naganova77d5552022-12-18 02:48:14 +0000538 media::audio::common::AudioPlaybackRate* _aidl_return)
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800539{
540 audio_playback_rate_t localPlaybackRate{};
541 status_t status = mTrack->getPlaybackRateParameters(&localPlaybackRate)
542 ?: AudioValidator::validatePlaybackRate(localPlaybackRate);
543 if (status == NO_ERROR) {
544 *_aidl_return = VALUE_OR_RETURN_BINDER_STATUS(
545 legacy2aidl_audio_playback_rate_t_AudioPlaybackRate(localPlaybackRate));
546 }
547 return binderStatusFromStatusT(status);
548}
549
Andy Hungaaa18282023-06-23 19:27:19 -0700550Status TrackHandle::setPlaybackRateParameters(
Mikhail Naganova77d5552022-12-18 02:48:14 +0000551 const media::audio::common::AudioPlaybackRate& playbackRate)
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800552{
553 const audio_playback_rate_t localPlaybackRate = VALUE_OR_RETURN_BINDER_STATUS(
554 aidl2legacy_AudioPlaybackRate_audio_playback_rate_t(playbackRate));
555 return binderStatusFromStatusT(AudioValidator::validatePlaybackRate(localPlaybackRate)
556 ?: mTrack->setPlaybackRateParameters(localPlaybackRate));
557}
558
Eric Laurent81784c32012-11-19 14:55:58 -0800559// ----------------------------------------------------------------------------
Jean-Michel Trivi74e01fa2019-02-25 12:18:09 -0800560// AppOp for audio playback
561// -------------------------------
Mikhail Naganovf7e3a3a2019-04-22 16:43:26 -0700562
563// static
Andy Hung3ff4b552023-06-26 19:20:57 -0700564sp<OpPlayAudioMonitor> OpPlayAudioMonitor::createIfNeeded(
Andy Hung44f27182023-07-06 20:56:16 -0700565 IAfThreadBase* thread,
Svet Ganov33761132021-05-13 22:51:08 +0000566 const AttributionSourceState& attributionSource, const audio_attributes_t& attr, int id,
Philip P. Moltmannbda45752020-07-17 16:41:18 -0700567 audio_stream_type_t streamType)
Jean-Michel Trivi74e01fa2019-02-25 12:18:09 -0800568{
Vlad Popa103be862023-07-10 20:27:41 -0700569 Vector<String16> packages;
570 const uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid));
Colin Crossb8a9dbb2020-08-27 04:12:26 +0000571 getPackagesForUid(uid, packages);
Eric Laurent9066ad32019-05-20 14:40:10 -0700572 if (isServiceUid(uid)) {
Eric Laurent9066ad32019-05-20 14:40:10 -0700573 if (packages.isEmpty()) {
Shunkai Yaoaf7990a2023-08-18 02:24:01 +0000574 ALOGW("OpPlayAudio: not muting track:%d usage:%d for service UID %d", id, attr.usage,
Eric Laurent9066ad32019-05-20 14:40:10 -0700575 uid);
576 return nullptr;
577 }
Jean-Michel Trivi74e01fa2019-02-25 12:18:09 -0800578 }
579 // stream type has been filtered by audio policy to indicate whether it can be muted
580 if (streamType == AUDIO_STREAM_ENFORCED_AUDIBLE) {
Eric Laurent2dab0302019-05-08 18:15:55 -0700581 ALOGD("OpPlayAudio: not muting track:%d usage:%d ENFORCED_AUDIBLE", id, attr.usage);
Mikhail Naganovf7e3a3a2019-04-22 16:43:26 -0700582 return nullptr;
Jean-Michel Trivi74e01fa2019-02-25 12:18:09 -0800583 }
Eric Laurent2dab0302019-05-08 18:15:55 -0700584 if ((attr.flags & AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY)
585 == AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY) {
586 ALOGD("OpPlayAudio: not muting track:%d flags %#x have FLAG_BYPASS_INTERRUPTION_POLICY",
587 id, attr.flags);
588 return nullptr;
589 }
Vlad Popa103be862023-07-10 20:27:41 -0700590 return sp<OpPlayAudioMonitor>::make(thread, attributionSource, attr.usage, id, uid);
Mikhail Naganovf7e3a3a2019-04-22 16:43:26 -0700591}
592
Andy Hung44f27182023-07-06 20:56:16 -0700593OpPlayAudioMonitor::OpPlayAudioMonitor(IAfThreadBase* thread,
594 const AttributionSourceState& attributionSource,
595 audio_usage_t usage, int id, uid_t uid)
596 : mThread(wp<IAfThreadBase>::fromExisting(thread)),
Vlad Popa103be862023-07-10 20:27:41 -0700597 mHasOpPlayAudio(true),
Vlad Popa103be862023-07-10 20:27:41 -0700598 mUsage((int32_t)usage),
599 mId(id),
600 mUid(uid),
601 mPackageName(VALUE_OR_FATAL(aidl2legacy_string_view_String16(
602 attributionSource.packageName.value_or("")))) {}
Jean-Michel Trivi74e01fa2019-02-25 12:18:09 -0800603
Andy Hung3ff4b552023-06-26 19:20:57 -0700604OpPlayAudioMonitor::~OpPlayAudioMonitor()
Jean-Michel Trivi74e01fa2019-02-25 12:18:09 -0800605{
606 if (mOpCallback != 0) {
607 mAppOpsManager.stopWatchingMode(mOpCallback);
608 }
609 mOpCallback.clear();
610}
611
Andy Hung3ff4b552023-06-26 19:20:57 -0700612void OpPlayAudioMonitor::onFirstRef()
Mikhail Naganovf7e3a3a2019-04-22 16:43:26 -0700613{
Vlad Popad2152122023-08-02 18:36:04 -0700614 // make sure not to broadcast the initial state since it is not needed and could
615 // cause a deadlock since this method can be called with the mThread->mLock held
616 checkPlayAudioForUsage(/*doBroadcast=*/false);
Shunkai Yaoaf7990a2023-08-18 02:24:01 +0000617 if (mPackageName.size()) {
Mikhail Naganovf7e3a3a2019-04-22 16:43:26 -0700618 mOpCallback = new PlayAudioOpCallback(this);
Shunkai Yaoaf7990a2023-08-18 02:24:01 +0000619 mAppOpsManager.startWatchingMode(AppOpsManager::OP_PLAY_AUDIO, mPackageName, mOpCallback);
620 } else {
621 ALOGW("Skipping OpPlayAudioMonitor due to null package name");
Mikhail Naganovf7e3a3a2019-04-22 16:43:26 -0700622 }
623}
624
Andy Hung3ff4b552023-06-26 19:20:57 -0700625bool OpPlayAudioMonitor::hasOpPlayAudio() const {
Jean-Michel Trivi74e01fa2019-02-25 12:18:09 -0800626 return mHasOpPlayAudio.load();
627}
628
Jean-Michel Trividdf87ef2019-08-20 15:42:04 -0700629// Note this method is never called (and never to be) for audio server / patch record track
Jean-Michel Trivi74e01fa2019-02-25 12:18:09 -0800630// - not called from constructor due to check on UID,
631// - not called from PlayAudioOpCallback because the callback is not installed in this case
Shunkai Yaoaf7990a2023-08-18 02:24:01 +0000632void OpPlayAudioMonitor::checkPlayAudioForUsage(bool doBroadcast) {
633 const bool hasAppOps =
634 mPackageName.size() &&
635 mAppOpsManager.checkAudioOpNoThrow(AppOpsManager::OP_PLAY_AUDIO, mUsage, mUid,
636 mPackageName) == AppOpsManager::MODE_ALLOWED;
Vlad Popa103be862023-07-10 20:27:41 -0700637
638 bool shouldChange = !hasAppOps; // check if we need to update.
639 if (mHasOpPlayAudio.compare_exchange_strong(shouldChange, hasAppOps)) {
Shunkai Yaoaf7990a2023-08-18 02:24:01 +0000640 ALOGI("OpPlayAudio: track:%d package:%s usage:%d %smuted", mId,
Tomasz Wasilczykb61c7212023-09-08 17:32:11 +0000641 String8(mPackageName).c_str(), mUsage, hasAppOps ? "not " : "");
Vlad Popad2152122023-08-02 18:36:04 -0700642 if (doBroadcast) {
643 auto thread = mThread.promote();
Andy Hung71742ab2023-07-07 13:47:37 -0700644 if (thread != nullptr && thread->type() == IAfThreadBase::OFFLOAD) {
Vlad Popad2152122023-08-02 18:36:04 -0700645 // Wake up Thread if offloaded, otherwise it may be several seconds for update.
Andy Hung87e82412023-08-29 14:26:09 -0700646 audio_utils::lock_guard _l(thread->mutex());
Vlad Popad2152122023-08-02 18:36:04 -0700647 thread->broadcast_l();
648 }
Vlad Popa103be862023-07-10 20:27:41 -0700649 }
Jean-Michel Trivi74e01fa2019-02-25 12:18:09 -0800650 }
651}
652
Andy Hung3ff4b552023-06-26 19:20:57 -0700653OpPlayAudioMonitor::PlayAudioOpCallback::PlayAudioOpCallback(
Jean-Michel Trivi74e01fa2019-02-25 12:18:09 -0800654 const wp<OpPlayAudioMonitor>& monitor) : mMonitor(monitor)
655{ }
656
Andy Hung3ff4b552023-06-26 19:20:57 -0700657void OpPlayAudioMonitor::PlayAudioOpCallback::opChanged(int32_t op,
Jean-Michel Trivi74e01fa2019-02-25 12:18:09 -0800658 const String16& packageName) {
Jean-Michel Trivi74e01fa2019-02-25 12:18:09 -0800659 if (op != AppOpsManager::OP_PLAY_AUDIO) {
660 return;
661 }
Shunkai Yaoaf7990a2023-08-18 02:24:01 +0000662
Tomasz Wasilczykb61c7212023-09-08 17:32:11 +0000663 ALOGI("%s OP_PLAY_AUDIO callback received for %s", __func__, String8(packageName).c_str());
Jean-Michel Trivi74e01fa2019-02-25 12:18:09 -0800664 sp<OpPlayAudioMonitor> monitor = mMonitor.promote();
665 if (monitor != NULL) {
Vlad Popad2152122023-08-02 18:36:04 -0700666 monitor->checkPlayAudioForUsage(/*doBroadcast=*/true);
Jean-Michel Trivi74e01fa2019-02-25 12:18:09 -0800667 }
668}
669
Eric Laurent9066ad32019-05-20 14:40:10 -0700670// static
Andy Hung3ff4b552023-06-26 19:20:57 -0700671void OpPlayAudioMonitor::getPackagesForUid(
Eric Laurent9066ad32019-05-20 14:40:10 -0700672 uid_t uid, Vector<String16>& packages)
673{
674 PermissionController permissionController;
675 permissionController.getPackagesForUid(uid, packages);
676}
677
Jean-Michel Trivi74e01fa2019-02-25 12:18:09 -0800678// ----------------------------------------------------------------------------
Andy Hung9d84af52018-09-12 18:03:44 -0700679#undef LOG_TAG
680#define LOG_TAG "AF::Track"
Eric Laurent81784c32012-11-19 14:55:58 -0800681
Andy Hung3ff4b552023-06-26 19:20:57 -0700682/* static */
Andy Hung44f27182023-07-06 20:56:16 -0700683sp<IAfTrack> IAfTrack::create(
684 IAfPlaybackThread* thread,
Andy Hung3ff4b552023-06-26 19:20:57 -0700685 const sp<Client>& client,
686 audio_stream_type_t streamType,
687 const audio_attributes_t& attr,
688 uint32_t sampleRate,
689 audio_format_t format,
690 audio_channel_mask_t channelMask,
691 size_t frameCount,
692 void *buffer,
693 size_t bufferSize,
694 const sp<IMemory>& sharedBuffer,
695 audio_session_t sessionId,
696 pid_t creatorPid,
697 const AttributionSourceState& attributionSource,
698 audio_output_flags_t flags,
699 track_type type,
700 audio_port_handle_t portId,
701 /** default behaviour is to start when there are as many frames
702 * ready as possible (aka. Buffer is full). */
703 size_t frameCountToBeReady,
704 float speed,
705 bool isSpatialized,
706 bool isBitPerfect) {
Andy Hung44f27182023-07-06 20:56:16 -0700707 return sp<Track>::make(thread,
Andy Hung3ff4b552023-06-26 19:20:57 -0700708 client,
709 streamType,
710 attr,
711 sampleRate,
712 format,
713 channelMask,
714 frameCount,
715 buffer,
716 bufferSize,
717 sharedBuffer,
718 sessionId,
719 creatorPid,
720 attributionSource,
721 flags,
722 type,
723 portId,
724 frameCountToBeReady,
725 speed,
726 isSpatialized,
727 isBitPerfect);
728}
729
Eric Laurent81784c32012-11-19 14:55:58 -0800730// Track constructor must be called with AudioFlinger::mLock and ThreadBase::mLock held
Andy Hung3ff4b552023-06-26 19:20:57 -0700731Track::Track(
Andy Hung44f27182023-07-06 20:56:16 -0700732 IAfPlaybackThread* thread,
Eric Laurent81784c32012-11-19 14:55:58 -0800733 const sp<Client>& client,
734 audio_stream_type_t streamType,
Kevin Rocard1f564ac2018-03-29 13:53:10 -0700735 const audio_attributes_t& attr,
Eric Laurent81784c32012-11-19 14:55:58 -0800736 uint32_t sampleRate,
737 audio_format_t format,
738 audio_channel_mask_t channelMask,
739 size_t frameCount,
Eric Laurent83b88082014-06-20 18:31:16 -0700740 void *buffer,
Andy Hung8fe68032017-06-05 16:17:51 -0700741 size_t bufferSize,
Eric Laurent81784c32012-11-19 14:55:58 -0800742 const sp<IMemory>& sharedBuffer,
Glenn Kastend848eb42016-03-08 13:42:11 -0800743 audio_session_t sessionId,
Eric Laurent09f1ed22019-04-24 17:45:17 -0700744 pid_t creatorPid,
Svet Ganov33761132021-05-13 22:51:08 +0000745 const AttributionSourceState& attributionSource,
Eric Laurent05067782016-06-01 18:27:28 -0700746 audio_output_flags_t flags,
Eric Laurent20b9ef02016-12-05 11:03:16 -0800747 track_type type,
Kevin Rocard01c7d9e2019-09-18 11:24:52 +0100748 audio_port_handle_t portId,
jiabinf042b9b2021-05-07 23:46:28 +0000749 size_t frameCountToBeReady,
Eric Laurentb0a7bc92022-04-05 15:06:08 +0200750 float speed,
jiabinc658e452022-10-21 20:52:21 +0000751 bool isSpatialized,
752 bool isBitPerfect)
Kevin Rocard1f564ac2018-03-29 13:53:10 -0700753 : TrackBase(thread, client, attr, sampleRate, format, channelMask, frameCount,
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -0700754 // TODO: Using unsecurePointer() has some associated security pitfalls
755 // (see declaration for details).
756 // Either document why it is safe in this case or address the
757 // issue (e.g. by copying).
758 (sharedBuffer != 0) ? sharedBuffer->unsecurePointer() : buffer,
Andy Hung8fe68032017-06-05 16:17:51 -0700759 (sharedBuffer != 0) ? sharedBuffer->size() : bufferSize,
Philip P. Moltmannbda45752020-07-17 16:41:18 -0700760 sessionId, creatorPid,
Svet Ganov33761132021-05-13 22:51:08 +0000761 VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid)), true /*isOut*/,
Eric Laurent83b88082014-06-20 18:31:16 -0700762 (type == TYPE_PATCH) ? ( buffer == NULL ? ALLOC_LOCAL : ALLOC_NONE) : ALLOC_CBLK,
Andy Hungb68f5eb2019-12-03 16:49:17 -0800763 type,
764 portId,
765 std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK) + std::to_string(portId)),
Andy Hung3ff4b552023-06-26 19:20:57 -0700766 mFillingStatus(FS_INVALID),
Eric Laurent81784c32012-11-19 14:55:58 -0800767 // mRetryCount initialized later when needed
768 mSharedBuffer(sharedBuffer),
769 mStreamType(streamType),
rago94a1ee82017-07-21 15:11:02 -0700770 mMainBuffer(thread->sinkBuffer()),
Eric Laurent81784c32012-11-19 14:55:58 -0800771 mAuxBuffer(NULL),
772 mAuxEffectId(0), mHasVolumeController(false),
Andy Hunge10393e2015-06-12 13:59:33 -0700773 mFrameMap(16 /* sink-frame-to-track-frame map memory */),
Ivan Lozano8cf3a072017-08-09 09:01:33 -0700774 mVolumeHandler(new media::VolumeHandler(sampleRate)),
Vlad Popa103be862023-07-10 20:27:41 -0700775 mOpPlayAudioMonitor(OpPlayAudioMonitor::createIfNeeded(thread, attributionSource, attr, id(),
Philip P. Moltmannbda45752020-07-17 16:41:18 -0700776 streamType)),
Andy Hunge10393e2015-06-12 13:59:33 -0700777 // mSinkTimestamp
Eric Laurent81784c32012-11-19 14:55:58 -0800778 mFastIndex(-1),
Glenn Kasten5736c352012-12-04 12:12:34 -0800779 mCachedVolume(1.0),
Kevin Rocard12381092018-04-11 09:19:59 -0700780 /* The track might not play immediately after being active, similarly as if its volume was 0.
781 * When the track starts playing, its volume will be computed. */
782 mFinalVolume(0.f),
Haynes Mathew George7844f672014-01-15 12:32:55 -0800783 mResumeToStopping(false),
Eric Laurent05067782016-06-01 18:27:28 -0700784 mFlushHwPending(false),
jiabinf042b9b2021-05-07 23:46:28 +0000785 mFlags(flags),
Eric Laurentb0a7bc92022-04-05 15:06:08 +0200786 mSpeed(speed),
jiabinc658e452022-10-21 20:52:21 +0000787 mIsSpatialized(isSpatialized),
788 mIsBitPerfect(isBitPerfect)
Eric Laurent81784c32012-11-19 14:55:58 -0800789{
Eric Laurent83b88082014-06-20 18:31:16 -0700790 // client == 0 implies sharedBuffer == 0
791 ALOG_ASSERT(!(client == 0 && sharedBuffer != 0));
792
Andy Hung9d84af52018-09-12 18:03:44 -0700793 ALOGV_IF(sharedBuffer != 0, "%s(%d): sharedBuffer: %p, size: %zu",
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -0700794 __func__, mId, sharedBuffer->unsecurePointer(), sharedBuffer->size());
Eric Laurent83b88082014-06-20 18:31:16 -0700795
Glenn Kasten3ef14ef2014-03-13 15:08:51 -0700796 if (mCblk == NULL) {
797 return;
Eric Laurent81784c32012-11-19 14:55:58 -0800798 }
Glenn Kasten3ef14ef2014-03-13 15:08:51 -0700799
Svet Ganov33761132021-05-13 22:51:08 +0000800 uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid));
Andy Hung689e82c2019-08-21 17:53:17 -0700801 if (!thread->isTrackAllowed_l(channelMask, format, sessionId, uid)) {
802 ALOGE("%s(%d): no more tracks available", __func__, mId);
803 releaseCblk(); // this makes the track invalid.
804 return;
805 }
806
Glenn Kasten3ef14ef2014-03-13 15:08:51 -0700807 if (sharedBuffer == 0) {
808 mAudioTrackServerProxy = new AudioTrackServerProxy(mCblk, mBuffer, frameCount,
Eric Laurent83b88082014-06-20 18:31:16 -0700809 mFrameSize, !isExternalTrack(), sampleRate);
Glenn Kasten3ef14ef2014-03-13 15:08:51 -0700810 } else {
811 mAudioTrackServerProxy = new StaticAudioTrackServerProxy(mCblk, mBuffer, frameCount,
Kevin Rocard36862032019-10-10 10:52:19 +0100812 mFrameSize, sampleRate);
Glenn Kasten3ef14ef2014-03-13 15:08:51 -0700813 }
814 mServerProxy = mAudioTrackServerProxy;
Andy Hung3c7f47a2021-03-16 17:30:09 -0700815 mServerProxy->setStartThresholdInFrames(frameCountToBeReady); // update the Cblk value
Glenn Kasten3ef14ef2014-03-13 15:08:51 -0700816
Glenn Kasten3ef14ef2014-03-13 15:08:51 -0700817 // only allocate a fast track index if we were able to allocate a normal track name
Eric Laurent05067782016-06-01 18:27:28 -0700818 if (flags & AUDIO_OUTPUT_FLAG_FAST) {
Andy Hunga5427822015-09-11 16:15:35 -0700819 // FIXME: Not calling framesReadyIsCalledByMultipleThreads() exposes a potential
820 // race with setSyncEvent(). However, if we call it, we cannot properly start
821 // static fast tracks (SoundPool) immediately after stopping.
822 //mAudioTrackServerProxy->framesReadyIsCalledByMultipleThreads();
Andy Hung44f27182023-07-06 20:56:16 -0700823 ALOG_ASSERT(thread->fastTrackAvailMask_l() != 0);
824 const int i = __builtin_ctz(thread->fastTrackAvailMask_l());
Glenn Kastendc2c50b2016-04-21 08:13:14 -0700825 ALOG_ASSERT(0 < i && i < (int)FastMixerState::sMaxFastTracks);
Glenn Kasten3ef14ef2014-03-13 15:08:51 -0700826 // FIXME This is too eager. We allocate a fast track index before the
827 // fast track becomes active. Since fast tracks are a scarce resource,
828 // this means we are potentially denying other more important fast tracks from
829 // being created. It would be better to allocate the index dynamically.
830 mFastIndex = i;
Andy Hung44f27182023-07-06 20:56:16 -0700831 thread->fastTrackAvailMask_l() &= ~(1 << i);
Glenn Kasten3ef14ef2014-03-13 15:08:51 -0700832 }
Andy Hung8946a282018-04-19 20:04:56 -0700833
Dean Wheatley7b036912020-06-18 16:22:11 +1000834 mServerLatencySupported = checkServerLatencySupported(format, flags);
Andy Hung8946a282018-04-19 20:04:56 -0700835#ifdef TEE_SINK
836 mTee.setId(std::string("_") + std::to_string(mThreadIoHandle)
Kevin Rocard51f0e982019-02-01 19:19:11 -0800837 + "_" + std::to_string(mId) + "_T");
Andy Hung8946a282018-04-19 20:04:56 -0700838#endif
jiabin57303cc2018-12-18 15:45:57 -0800839
jiabineb3bda02020-06-30 14:07:03 -0700840 if (thread->supportsHapticPlayback()) {
841 // If the track is attached to haptic playback thread, it is potentially to have
842 // HapticGenerator effect, which will generate haptic data, on the track. In that case,
843 // external vibration is always created for all tracks attached to haptic playback thread.
jiabin57303cc2018-12-18 15:45:57 -0800844 mAudioVibrationController = new AudioVibrationController(this);
Svet Ganov33761132021-05-13 22:51:08 +0000845 std::string packageName = attributionSource.packageName.has_value() ?
846 attributionSource.packageName.value() : "";
jiabin57303cc2018-12-18 15:45:57 -0800847 mExternalVibration = new os::ExternalVibration(
Philip P. Moltmannbda45752020-07-17 16:41:18 -0700848 mUid, packageName, mAttr, mAudioVibrationController);
jiabin57303cc2018-12-18 15:45:57 -0800849 }
Andy Hungb68f5eb2019-12-03 16:49:17 -0800850
851 // Once this item is logged by the server, the client can add properties.
Andy Hunga629bd12020-06-05 16:03:53 -0700852 const char * const traits = sharedBuffer == 0 ? "" : "static";
Andy Hung5837c7f2021-02-25 10:48:24 -0800853 mTrackMetrics.logConstructor(creatorPid, uid, id(), traits, streamType);
Eric Laurent81784c32012-11-19 14:55:58 -0800854}
855
Andy Hung3ff4b552023-06-26 19:20:57 -0700856Track::~Track()
Eric Laurent81784c32012-11-19 14:55:58 -0800857{
Andy Hung9d84af52018-09-12 18:03:44 -0700858 ALOGV("%s(%d)", __func__, mId);
Glenn Kasten0c72b242013-09-11 09:14:16 -0700859
860 // The destructor would clear mSharedBuffer,
861 // but it will not push the decremented reference count,
862 // leaving the client's IMemory dangling indefinitely.
863 // This prevents that leak.
864 if (mSharedBuffer != 0) {
865 mSharedBuffer.clear();
Glenn Kasten0c72b242013-09-11 09:14:16 -0700866 }
Eric Laurent81784c32012-11-19 14:55:58 -0800867}
868
Andy Hung3ff4b552023-06-26 19:20:57 -0700869status_t Track::initCheck() const
Glenn Kasten03003332013-08-06 15:40:54 -0700870{
871 status_t status = TrackBase::initCheck();
Andy Hungc0691382018-09-12 18:01:57 -0700872 if (status == NO_ERROR && mCblk == nullptr) {
Glenn Kasten03003332013-08-06 15:40:54 -0700873 status = NO_MEMORY;
874 }
875 return status;
876}
877
Andy Hung3ff4b552023-06-26 19:20:57 -0700878void Track::destroy()
Eric Laurent81784c32012-11-19 14:55:58 -0800879{
880 // NOTE: destroyTrack_l() can remove a strong reference to this Track
881 // by removing it from mTracks vector, so there is a risk that this Tracks's
882 // destructor is called. As the destructor needs to lock mLock,
883 // we must acquire a strong reference on this Track before locking mLock
884 // here so that the destructor is called only when exiting this function.
885 // On the other hand, as long as Track::destroy() is only called by
886 // TrackHandle destructor, the TrackHandle still holds a strong ref on
887 // this Track with its member mTrack.
888 sp<Track> keep(this);
889 { // scope for mLock
Eric Laurentaaa44472014-09-12 17:41:50 -0700890 bool wasActive = false;
Andy Hung44f27182023-07-06 20:56:16 -0700891 const sp<IAfThreadBase> thread = mThread.promote();
Eric Laurent81784c32012-11-19 14:55:58 -0800892 if (thread != 0) {
Andy Hunga7187712023-12-05 17:28:17 -0800893 audio_utils::unique_lock ul(thread->mutex());
894 thread->waitWhileThreadBusy_l(ul);
895
Andy Hung44f27182023-07-06 20:56:16 -0700896 auto* const playbackThread = thread->asIAfPlaybackThread().get();
Eric Laurentaaa44472014-09-12 17:41:50 -0700897 wasActive = playbackThread->destroyTrack_l(this);
jiabin6e506fc2023-06-27 18:22:35 +0000898 forEachTeePatchTrack_l([](const auto& patchTrack) { patchTrack->destroy(); });
Eric Laurentaaa44472014-09-12 17:41:50 -0700899 }
900 if (isExternalTrack() && !wasActive) {
Andy Hunga7187712023-12-05 17:28:17 -0800901 // If the track is not active, the TrackHandle is responsible for
902 // releasing the port id, not the ThreadBase::threadLoop().
903 // At this point, there is no concurrency issue as the track is going away.
Eric Laurentd7fe0862018-07-14 16:48:01 -0700904 AudioSystem::releaseOutput(mPortId);
Eric Laurent81784c32012-11-19 14:55:58 -0800905 }
906 }
907}
908
Andy Hung3ff4b552023-06-26 19:20:57 -0700909void Track::appendDumpHeader(String8& result) const
Eric Laurent81784c32012-11-19 14:55:58 -0800910{
Eric Laurent973db022018-11-20 14:54:31 -0800911 result.appendFormat("Type Id Active Client Session Port Id S Flags "
Kevin Rocard5f2136e2018-05-11 22:03:00 -0700912 " Format Chn mask SRate "
913 "ST Usg CT "
914 " G db L dB R dB VS dB "
jiabin5eaf0962022-12-20 20:11:38 +0000915 " Server FrmCnt FrmRdy F Underruns Flushed BitPerfect"
Kevin Rocard5f2136e2018-05-11 22:03:00 -0700916 "%s\n",
917 isServerLatencySupported() ? " Latency" : "");
Eric Laurent81784c32012-11-19 14:55:58 -0800918}
919
Andy Hung3ff4b552023-06-26 19:20:57 -0700920void Track::appendDump(String8& result, bool active) const
Eric Laurent81784c32012-11-19 14:55:58 -0800921{
Andy Hung2c6c3bb2017-06-16 14:01:45 -0700922 char trackType;
923 switch (mType) {
924 case TYPE_DEFAULT:
925 case TYPE_OUTPUT:
Andy Hungf6ab58d2018-05-25 12:50:39 -0700926 if (isStatic()) {
Andy Hung2c6c3bb2017-06-16 14:01:45 -0700927 trackType = 'S'; // static
928 } else {
929 trackType = ' '; // normal
Eric Laurentbfb1b832013-01-07 09:53:42 -0800930 }
Andy Hung2c6c3bb2017-06-16 14:01:45 -0700931 break;
932 case TYPE_PATCH:
933 trackType = 'P';
934 break;
935 default:
936 trackType = '?';
Eric Laurent81784c32012-11-19 14:55:58 -0800937 }
Andy Hung2c6c3bb2017-06-16 14:01:45 -0700938
939 if (isFastTrack()) {
Andy Hungc0691382018-09-12 18:01:57 -0700940 result.appendFormat("F%d %c %6d", mFastIndex, trackType, mId);
Andy Hung2c6c3bb2017-06-16 14:01:45 -0700941 } else {
Andy Hungc0691382018-09-12 18:01:57 -0700942 result.appendFormat(" %c %6d", trackType, mId);
Andy Hung2c6c3bb2017-06-16 14:01:45 -0700943 }
944
Eric Laurent81784c32012-11-19 14:55:58 -0800945 char nowInUnderrun;
946 switch (mObservedUnderruns.mBitFields.mMostRecent) {
947 case UNDERRUN_FULL:
948 nowInUnderrun = ' ';
949 break;
950 case UNDERRUN_PARTIAL:
951 nowInUnderrun = '<';
952 break;
953 case UNDERRUN_EMPTY:
954 nowInUnderrun = '*';
955 break;
956 default:
957 nowInUnderrun = '?';
958 break;
959 }
Andy Hungda540db2017-04-20 14:06:17 -0700960
Andy Hung2c6c3bb2017-06-16 14:01:45 -0700961 char fillingStatus;
Andy Hung3ff4b552023-06-26 19:20:57 -0700962 switch (mFillingStatus) {
Andy Hung2c6c3bb2017-06-16 14:01:45 -0700963 case FS_INVALID:
964 fillingStatus = 'I';
965 break;
966 case FS_FILLING:
967 fillingStatus = 'f';
968 break;
969 case FS_FILLED:
970 fillingStatus = 'F';
971 break;
972 case FS_ACTIVE:
973 fillingStatus = 'A';
974 break;
975 default:
976 fillingStatus = '?';
977 break;
978 }
979
980 // clip framesReadySafe to max representation in dump
981 const size_t framesReadySafe =
982 std::min(mAudioTrackServerProxy->framesReadySafe(), (size_t)99999999);
983
984 // obtain volumes
985 const gain_minifloat_packed_t vlr = mAudioTrackServerProxy->getVolumeLR();
986 const std::pair<float /* volume */, bool /* active */> vsVolume =
987 mVolumeHandler->getLastVolume();
988
989 // Our effective frame count is obtained by ServerProxy::getBufferSizeInFrames()
990 // as it may be reduced by the application.
991 const size_t bufferSizeInFrames = (size_t)mAudioTrackServerProxy->getBufferSizeInFrames();
992 // Check whether the buffer size has been modified by the app.
993 const char modifiedBufferChar = bufferSizeInFrames < mFrameCount
994 ? 'r' /* buffer reduced */: bufferSizeInFrames > mFrameCount
995 ? 'e' /* error */ : ' ' /* identical */;
996
Eric Laurent973db022018-11-20 14:54:31 -0800997 result.appendFormat("%7s %6u %7u %7u %2s 0x%03X "
Kevin Rocard5f2136e2018-05-11 22:03:00 -0700998 "%08X %08X %6u "
999 "%2u %3x %2x "
1000 "%5.2g %5.2g %5.2g %5.2g%c "
jiabin5eaf0962022-12-20 20:11:38 +00001001 "%08X %6zu%c %6zu %c %9u%c %7u %10s",
Marco Nelissenb2208842014-02-07 14:00:50 -08001002 active ? "yes" : "no",
Andy Hung4ef19fa2018-05-15 19:35:29 -07001003 (mClient == 0) ? getpid() : mClient->pid(),
Andy Hung2c6c3bb2017-06-16 14:01:45 -07001004 mSessionId,
Eric Laurent973db022018-11-20 14:54:31 -08001005 mPortId,
Andy Hunge2e830f2019-12-03 12:54:46 -08001006 getTrackStateAsCodedString(),
Andy Hung2c6c3bb2017-06-16 14:01:45 -07001007 mCblk->mFlags,
1008
Eric Laurent81784c32012-11-19 14:55:58 -08001009 mFormat,
1010 mChannelMask,
Andy Hungcef2daa2018-06-01 15:31:49 -07001011 sampleRate(),
Andy Hung2c6c3bb2017-06-16 14:01:45 -07001012
1013 mStreamType,
Kevin Rocard5f2136e2018-05-11 22:03:00 -07001014 mAttr.usage,
1015 mAttr.content_type,
1016
1017 20.0 * log10(mFinalVolume),
Glenn Kastenc56f3422014-03-21 17:53:17 -07001018 20.0 * log10(float_from_gain(gain_minifloat_unpack_left(vlr))),
1019 20.0 * log10(float_from_gain(gain_minifloat_unpack_right(vlr))),
Andy Hungda540db2017-04-20 14:06:17 -07001020 20.0 * log10(vsVolume.first), // VolumeShaper(s) total volume
1021 vsVolume.second ? 'A' : ' ', // if any VolumeShapers active
Andy Hung2c6c3bb2017-06-16 14:01:45 -07001022
Glenn Kastenf20e1d82013-07-12 09:45:18 -07001023 mCblk->mServer,
Andy Hung2c6c3bb2017-06-16 14:01:45 -07001024 bufferSizeInFrames,
1025 modifiedBufferChar,
1026 framesReadySafe,
1027 fillingStatus,
Glenn Kasten82aaf942013-07-17 16:05:07 -07001028 mAudioTrackServerProxy->getUnderrunFrames(),
Andy Hung2148bf02016-11-28 19:01:02 -08001029 nowInUnderrun,
jiabin5eaf0962022-12-20 20:11:38 +00001030 (unsigned)mAudioTrackServerProxy->framesFlushed() % 10000000,
1031 isBitPerfect() ? "true" : "false"
Andy Hung2c6c3bb2017-06-16 14:01:45 -07001032 );
Andy Hungcef2daa2018-06-01 15:31:49 -07001033
1034 if (isServerLatencySupported()) {
1035 double latencyMs;
1036 bool fromTrack;
1037 if (getTrackLatencyMs(&latencyMs, &fromTrack) == OK) {
1038 // Show latency in msec, followed by 't' if from track timestamp (the most accurate)
1039 // or 'k' if estimated from kernel because track frames haven't been presented yet.
1040 result.appendFormat(" %7.2lf %c", latencyMs, fromTrack ? 't' : 'k');
Andy Hungf6ab58d2018-05-25 12:50:39 -07001041 } else {
Andy Hungcef2daa2018-06-01 15:31:49 -07001042 result.appendFormat("%10s", mCblk->mServer != 0 ? "unavail" : "new");
Andy Hungf6ab58d2018-05-25 12:50:39 -07001043 }
1044 }
1045 result.append("\n");
Eric Laurent81784c32012-11-19 14:55:58 -08001046}
1047
Andy Hung3ff4b552023-06-26 19:20:57 -07001048uint32_t Track::sampleRate() const {
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001049 return mAudioTrackServerProxy->getSampleRate();
1050}
1051
Eric Laurent81784c32012-11-19 14:55:58 -08001052// AudioBufferProvider interface
Andy Hung3ff4b552023-06-26 19:20:57 -07001053status_t Track::getNextBuffer(AudioBufferProvider::Buffer* buffer)
Eric Laurent81784c32012-11-19 14:55:58 -08001054{
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001055 ServerProxy::Buffer buf;
1056 size_t desiredFrames = buffer->frameCount;
1057 buf.mFrameCount = desiredFrames;
1058 status_t status = mServerProxy->obtainBuffer(&buf);
1059 buffer->frameCount = buf.mFrameCount;
1060 buffer->raw = buf.mRaw;
Andy Hungfc629172020-06-22 10:06:23 -07001061 if (buf.mFrameCount == 0 && !isStopping() && !isStopped() && !isPaused() && !isOffloaded()) {
Andy Hung9d84af52018-09-12 18:03:44 -07001062 ALOGV("%s(%d): underrun, framesReady(%zu) < framesDesired(%zd), state: %d",
Andy Hung959b5b82021-09-24 10:46:20 -07001063 __func__, mId, buf.mFrameCount, desiredFrames, (int)mState);
Glenn Kasten82aaf942013-07-17 16:05:07 -07001064 mAudioTrackServerProxy->tallyUnderrunFrames(desiredFrames);
Phil Burk2812d9e2016-01-04 10:34:30 -08001065 } else {
1066 mAudioTrackServerProxy->tallyUnderrunFrames(0);
Eric Laurent81784c32012-11-19 14:55:58 -08001067 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001068 return status;
Eric Laurent81784c32012-11-19 14:55:58 -08001069}
1070
Andy Hung3ff4b552023-06-26 19:20:57 -07001071void Track::releaseBuffer(AudioBufferProvider::Buffer* buffer)
Kevin Rocard153f92d2018-12-18 18:33:28 -08001072{
1073 interceptBuffer(*buffer);
1074 TrackBase::releaseBuffer(buffer);
1075}
1076
1077// TODO: compensate for time shift between HW modules.
Andy Hung3ff4b552023-06-26 19:20:57 -07001078void Track::interceptBuffer(
Kevin Rocarda134b002019-02-07 18:05:31 -08001079 const AudioBufferProvider::Buffer& sourceBuffer) {
Kevin Rocard6057fa22019-02-08 14:08:07 -08001080 auto start = std::chrono::steady_clock::now();
Kevin Rocarda134b002019-02-07 18:05:31 -08001081 const size_t frameCount = sourceBuffer.frameCount;
Kevin Rocardd83b08a2019-02-27 15:05:54 -08001082 if (frameCount == 0) {
1083 return; // No audio to intercept.
1084 // Additionally PatchProxyBufferProvider::obtainBuffer (called by PathTrack::getNextBuffer)
1085 // does not allow 0 frame size request contrary to getNextBuffer
1086 }
Jiabin Huang98b8d452024-01-04 18:42:55 +00001087 TeePatches teePatches;
1088 if (mTeePatchesRWLock.tryReadLock() == NO_ERROR) {
1089 // Cache a copy of tee patches in case it is updated while using.
1090 teePatches = mTeePatches;
1091 mTeePatchesRWLock.unlock();
1092 }
1093 for (auto& teePatch : teePatches) {
Andy Hung3ff4b552023-06-26 19:20:57 -07001094 IAfPatchRecord* patchRecord = teePatch.patchRecord.get();
Mikhail Naganov8296c252019-09-25 14:59:54 -07001095 const size_t framesWritten = patchRecord->writeFrames(
1096 sourceBuffer.i8, frameCount, mFrameSize);
1097 const size_t framesLeft = frameCount - framesWritten;
Kevin Rocarda134b002019-02-07 18:05:31 -08001098 ALOGW_IF(framesLeft != 0, "%s(%d) PatchRecord %d can not provide big enough "
Andy Hung3ff4b552023-06-26 19:20:57 -07001099 "buffer %zu/%zu, dropping %zu frames", __func__, mId, patchRecord->id(),
Kevin Rocarda134b002019-02-07 18:05:31 -08001100 framesWritten, frameCount, framesLeft);
Kevin Rocard153f92d2018-12-18 18:33:28 -08001101 }
Kevin Rocard6057fa22019-02-08 14:08:07 -08001102 auto spent = ceil<std::chrono::microseconds>(std::chrono::steady_clock::now() - start);
1103 using namespace std::chrono_literals;
1104 // Average is ~20us per track, this should virtually never be logged (Logging takes >200us)
Kevin Rocard01c7d9e2019-09-18 11:24:52 +01001105 ALOGD_IF(spent > 500us, "%s: took %lldus to intercept %zu tracks", __func__,
Jiabin Huang98b8d452024-01-04 18:42:55 +00001106 spent.count(), teePatches.size());
Kevin Rocard153f92d2018-12-18 18:33:28 -08001107}
1108
Glenn Kasten6466c9e2013-08-23 10:54:07 -07001109// ExtendedAudioBufferProvider interface
1110
Andy Hung27876c02014-09-09 18:07:55 -07001111// framesReady() may return an approximation of the number of frames if called
1112// from a different thread than the one calling Proxy->obtainBuffer() and
1113// Proxy->releaseBuffer(). Also note there is no mutual exclusion in the
1114// AudioTrackServerProxy so be especially careful calling with FastTracks.
Andy Hung3ff4b552023-06-26 19:20:57 -07001115size_t Track::framesReady() const {
Andy Hung27876c02014-09-09 18:07:55 -07001116 if (mSharedBuffer != 0 && (isStopped() || isStopping())) {
1117 // Static tracks return zero frames immediately upon stopping (for FastTracks).
1118 // The remainder of the buffer is not drained.
1119 return 0;
1120 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001121 return mAudioTrackServerProxy->framesReady();
Eric Laurent81784c32012-11-19 14:55:58 -08001122}
1123
Andy Hung3ff4b552023-06-26 19:20:57 -07001124int64_t Track::framesReleased() const
Glenn Kasten6466c9e2013-08-23 10:54:07 -07001125{
1126 return mAudioTrackServerProxy->framesReleased();
1127}
1128
Andy Hung3ff4b552023-06-26 19:20:57 -07001129void Track::onTimestamp(const ExtendedTimestamp &timestamp)
Andy Hung6ae58432016-02-16 18:32:24 -08001130{
1131 // This call comes from a FastTrack and should be kept lockless.
1132 // The server side frames are already translated to client frames.
Andy Hung818e7a32016-02-16 18:08:07 -08001133 mAudioTrackServerProxy->setTimestamp(timestamp);
Andy Hung6ae58432016-02-16 18:32:24 -08001134
Andy Hung818e7a32016-02-16 18:08:07 -08001135 // We do not set drained here, as FastTrack timestamp may not go to very last frame.
Andy Hungcef2daa2018-06-01 15:31:49 -07001136
1137 // Compute latency.
1138 // TODO: Consider whether the server latency may be passed in by FastMixer
1139 // as a constant for all active FastTracks.
1140 const double latencyMs = timestamp.getOutputServerLatencyMs(sampleRate());
1141 mServerLatencyFromTrack.store(true);
1142 mServerLatencyMs.store(latencyMs);
Andy Hung6ae58432016-02-16 18:32:24 -08001143}
1144
Eric Laurent81784c32012-11-19 14:55:58 -08001145// Don't call for fast tracks; the framesReady() could result in priority inversion
Andy Hung3ff4b552023-06-26 19:20:57 -07001146bool Track::isReady() const {
1147 if (mFillingStatus != FS_FILLING || isStopped() || isPausing()) {
Krishnankutty Kolathappilly8d6c2922014-02-04 16:23:42 -08001148 return true;
1149 }
1150
Eric Laurent16498512014-03-17 17:22:08 -07001151 if (isStopping()) {
1152 if (framesReady() > 0) {
Andy Hung3ff4b552023-06-26 19:20:57 -07001153 mFillingStatus = FS_FILLED;
Eric Laurent16498512014-03-17 17:22:08 -07001154 }
Eric Laurent81784c32012-11-19 14:55:58 -08001155 return true;
1156 }
1157
Kevin Rocard01c7d9e2019-09-18 11:24:52 +01001158 size_t bufferSizeInFrames = mServerProxy->getBufferSizeInFrames();
Andy Hung3c7f47a2021-03-16 17:30:09 -07001159 // Note: mServerProxy->getStartThresholdInFrames() is clamped.
1160 const size_t startThresholdInFrames = mServerProxy->getStartThresholdInFrames();
1161 const size_t framesToBeReady = std::clamp( // clamp again to validate client values.
1162 std::min(startThresholdInFrames, bufferSizeInFrames), size_t(1), mFrameCount);
Kevin Rocard01c7d9e2019-09-18 11:24:52 +01001163
1164 if (framesReady() >= framesToBeReady || (mCblk->mFlags & CBLK_FORCEREADY)) {
1165 ALOGV("%s(%d): consider track ready with %zu/%zu, target was %zu)",
1166 __func__, mId, framesReady(), bufferSizeInFrames, framesToBeReady);
Andy Hung3ff4b552023-06-26 19:20:57 -07001167 mFillingStatus = FS_FILLED;
Glenn Kasten96f60d82013-07-12 10:21:18 -07001168 android_atomic_and(~CBLK_FORCEREADY, &mCblk->mFlags);
Eric Laurent81784c32012-11-19 14:55:58 -08001169 return true;
1170 }
1171 return false;
1172}
1173
Andy Hung3ff4b552023-06-26 19:20:57 -07001174status_t Track::start(AudioSystem::sync_event_t event __unused,
Glenn Kastend848eb42016-03-08 13:42:11 -08001175 audio_session_t triggerSession __unused)
Eric Laurent81784c32012-11-19 14:55:58 -08001176{
1177 status_t status = NO_ERROR;
Andy Hungc0691382018-09-12 18:01:57 -07001178 ALOGV("%s(%d): calling pid %d session %d",
1179 __func__, mId, IPCThreadState::self()->getCallingPid(), mSessionId);
Eric Laurent81784c32012-11-19 14:55:58 -08001180
Andy Hung44f27182023-07-06 20:56:16 -07001181 const sp<IAfThreadBase> thread = mThread.promote();
Eric Laurent81784c32012-11-19 14:55:58 -08001182 if (thread != 0) {
Eric Laurent813e2a72013-08-31 12:59:48 -07001183 if (isOffloaded()) {
Andy Hung2ac52f12023-08-28 18:36:53 -07001184 audio_utils::lock_guard _laf(thread->afThreadCallback()->mutex());
Andy Hung94dfbb42023-09-06 19:41:47 -07001185 const bool nonOffloadableGlobalEffectEnabled =
1186 thread->afThreadCallback()->isNonOffloadableGlobalEffectEnabled_l();
Andy Hung87e82412023-08-29 14:26:09 -07001187 audio_utils::lock_guard _lth(thread->mutex());
Andy Hungbd72c542023-06-20 18:56:17 -07001188 sp<IAfEffectChain> ec = thread->getEffectChain_l(mSessionId);
Andy Hung94dfbb42023-09-06 19:41:47 -07001189 if (nonOffloadableGlobalEffectEnabled ||
Eric Laurent5baf2af2013-09-12 17:37:00 -07001190 (ec != 0 && ec->isNonOffloadableEnabled())) {
Eric Laurent813e2a72013-08-31 12:59:48 -07001191 invalidate();
1192 return PERMISSION_DENIED;
1193 }
1194 }
Andy Hunga7187712023-12-05 17:28:17 -08001195 audio_utils::unique_lock ul(thread->mutex());
1196 thread->waitWhileThreadBusy_l(ul);
1197
Eric Laurent81784c32012-11-19 14:55:58 -08001198 track_state state = mState;
1199 // here the track could be either new, or restarted
1200 // in both cases "unstop" the track
Eric Laurentbfb1b832013-01-07 09:53:42 -08001201
Krishnankutty Kolathappilly8d6c2922014-02-04 16:23:42 -08001202 // initial state-stopping. next state-pausing.
1203 // What if resume is called ?
1204
Zhou Song1ed46a22020-08-17 15:36:56 +08001205 if (state == FLUSHED) {
1206 // avoid underrun glitches when starting after flush
1207 reset();
1208 }
1209
kuowei.li576f1362021-05-11 18:02:32 +08001210 // clear mPauseHwPending because of pause (and possibly flush) during underrun.
1211 mPauseHwPending = false;
Krishnankutty Kolathappilly8d6c2922014-02-04 16:23:42 -08001212 if (state == PAUSED || state == PAUSING) {
Eric Laurentbfb1b832013-01-07 09:53:42 -08001213 if (mResumeToStopping) {
1214 // happened we need to resume to STOPPING_1
1215 mState = TrackBase::STOPPING_1;
Andy Hungc0691382018-09-12 18:01:57 -07001216 ALOGV("%s(%d): PAUSED => STOPPING_1 on thread %d",
1217 __func__, mId, (int)mThreadIoHandle);
Eric Laurentbfb1b832013-01-07 09:53:42 -08001218 } else {
1219 mState = TrackBase::RESUMING;
Andy Hungc0691382018-09-12 18:01:57 -07001220 ALOGV("%s(%d): PAUSED => RESUMING on thread %d",
1221 __func__, mId, (int)mThreadIoHandle);
Eric Laurentbfb1b832013-01-07 09:53:42 -08001222 }
Eric Laurent81784c32012-11-19 14:55:58 -08001223 } else {
1224 mState = TrackBase::ACTIVE;
Andy Hungc0691382018-09-12 18:01:57 -07001225 ALOGV("%s(%d): ? => ACTIVE on thread %d",
1226 __func__, mId, (int)mThreadIoHandle);
Eric Laurent81784c32012-11-19 14:55:58 -08001227 }
1228
Andy Hung44f27182023-07-06 20:56:16 -07001229 auto* const playbackThread = thread->asIAfPlaybackThread().get();
yucliu91503922022-07-20 17:40:39 -07001230
1231 // states to reset position info for pcm tracks
1232 if (audio_is_linear_pcm(mFormat)
Andy Hunge10393e2015-06-12 13:59:33 -07001233 && (state == IDLE || state == STOPPED || state == FLUSHED)) {
1234 mFrameMap.reset();
yucliu91503922022-07-20 17:40:39 -07001235
1236 if (!isFastTrack() && (isDirect() || isOffloaded())) {
1237 // Start point of track -> sink frame map. If the HAL returns a
1238 // frame position smaller than the first written frame in
1239 // updateTrackFrameInfo, the timestamp can be interpolated
1240 // instead of using a larger value.
1241 mFrameMap.push(mAudioTrackServerProxy->framesReleased(),
1242 playbackThread->framesWritten());
1243 }
Andy Hunge10393e2015-06-12 13:59:33 -07001244 }
Haynes Mathew George240934b2015-03-11 18:25:50 -07001245 if (isFastTrack()) {
1246 // refresh fast track underruns on start because that field is never cleared
1247 // by the fast mixer; furthermore, the same track can be recycled, i.e. start
1248 // after stop.
1249 mObservedUnderruns = playbackThread->getFastTrackUnderruns(mFastIndex);
1250 }
Eric Laurentbfb1b832013-01-07 09:53:42 -08001251 status = playbackThread->addTrack_l(this);
jiabina84c3d32022-12-02 18:59:55 +00001252 if (status == INVALID_OPERATION || status == PERMISSION_DENIED || status == DEAD_OBJECT) {
Eric Laurent81784c32012-11-19 14:55:58 -08001253 triggerEvents(AudioSystem::SYNC_EVENT_PRESENTATION_COMPLETE);
Eric Laurentbfb1b832013-01-07 09:53:42 -08001254 // restore previous state if start was rejected by policy manager
jiabina84c3d32022-12-02 18:59:55 +00001255 if (status == PERMISSION_DENIED || status == DEAD_OBJECT) {
Eric Laurentbfb1b832013-01-07 09:53:42 -08001256 mState = state;
1257 }
1258 }
Andy Hung1d3556d2018-03-29 16:30:14 -07001259
Andy Hungb68f5eb2019-12-03 16:49:17 -08001260 // Audio timing metrics are computed a few mix cycles after starting.
1261 {
1262 mLogStartCountdown = LOG_START_COUNTDOWN;
1263 mLogStartTimeNs = systemTime();
1264 mLogStartFrames = mAudioTrackServerProxy->getTimestamp()
Andy Hung62921122020-05-18 10:47:31 -07001265 .mPosition[ExtendedTimestamp::LOCATION_KERNEL];
1266 mLogLatencyMs = 0.;
Andy Hungb68f5eb2019-12-03 16:49:17 -08001267 }
Andy Hungcb6cc752022-05-19 19:24:51 -07001268 mLogForceVolumeUpdate = true; // at least one volume logged for metrics when starting.
Andy Hungb68f5eb2019-12-03 16:49:17 -08001269
Andy Hung1d3556d2018-03-29 16:30:14 -07001270 if (status == NO_ERROR || status == ALREADY_EXISTS) {
1271 // for streaming tracks, remove the buffer read stop limit.
1272 mAudioTrackServerProxy->start();
1273 }
1274
Eric Laurentbfb1b832013-01-07 09:53:42 -08001275 // track was already in the active list, not a problem
1276 if (status == ALREADY_EXISTS) {
1277 status = NO_ERROR;
Glenn Kasten12022ff2013-10-17 11:32:39 -07001278 } else {
1279 // Acknowledge any pending flush(), so that subsequent new data isn't discarded.
1280 // It is usually unsafe to access the server proxy from a binder thread.
1281 // But in this case we know the mixer thread (whether normal mixer or fast mixer)
1282 // isn't looking at this track yet: we still hold the normal mixer thread lock,
1283 // and for fast tracks the track is not yet in the fast mixer thread's active set.
Andy Hunge6fb82a2015-09-09 14:39:02 -07001284 // For static tracks, this is used to acknowledge change in position or loop.
Eric Laurent564d1442015-09-09 12:26:52 -07001285 ServerProxy::Buffer buffer;
1286 buffer.mFrameCount = 1;
1287 (void) mAudioTrackServerProxy->obtainBuffer(&buffer, true /*ackFlush*/);
Eric Laurent81784c32012-11-19 14:55:58 -08001288 }
jiabin6e506fc2023-06-27 18:22:35 +00001289 if (status == NO_ERROR) {
1290 forEachTeePatchTrack_l([](const auto& patchTrack) { patchTrack->start(); });
1291 }
Eric Laurent81784c32012-11-19 14:55:58 -08001292 } else {
1293 status = BAD_VALUE;
1294 }
Kevin Rocardc43ea142019-01-31 18:17:37 -08001295 if (status == NO_ERROR) {
Jean-Michel Trivi16395ca2022-12-11 22:10:11 +00001296 // send format to AudioManager for playback activity monitoring
Andy Hung2cbc2722023-07-17 17:05:00 -07001297 const sp<IAudioManager> audioManager =
1298 thread->afThreadCallback()->getOrCreateAudioManager();
Jean-Michel Trivi16395ca2022-12-11 22:10:11 +00001299 if (audioManager && mPortId != AUDIO_PORT_HANDLE_NONE) {
1300 std::unique_ptr<os::PersistableBundle> bundle =
1301 std::make_unique<os::PersistableBundle>();
1302 bundle->putBoolean(String16(kExtraPlayerEventSpatializedKey),
1303 isSpatialized());
1304 bundle->putInt(String16(kExtraPlayerEventSampleRateKey), mSampleRate);
1305 bundle->putInt(String16(kExtraPlayerEventChannelMaskKey), mChannelMask);
1306 status_t result = audioManager->portEvent(mPortId,
1307 PLAYER_UPDATE_FORMAT, bundle);
1308 if (result != OK) {
1309 ALOGE("%s: unable to send playback format for port ID %d, status error %d",
1310 __func__, mPortId, result);
1311 }
1312 }
Kevin Rocardc43ea142019-01-31 18:17:37 -08001313 }
Eric Laurent81784c32012-11-19 14:55:58 -08001314 return status;
1315}
1316
Andy Hung3ff4b552023-06-26 19:20:57 -07001317void Track::stop()
Eric Laurent81784c32012-11-19 14:55:58 -08001318{
Andy Hungc0691382018-09-12 18:01:57 -07001319 ALOGV("%s(%d): calling pid %d", __func__, mId, IPCThreadState::self()->getCallingPid());
Andy Hung44f27182023-07-06 20:56:16 -07001320 const sp<IAfThreadBase> thread = mThread.promote();
Eric Laurent81784c32012-11-19 14:55:58 -08001321 if (thread != 0) {
Andy Hunga7187712023-12-05 17:28:17 -08001322 audio_utils::unique_lock ul(thread->mutex());
1323 thread->waitWhileThreadBusy_l(ul);
1324
Eric Laurent81784c32012-11-19 14:55:58 -08001325 track_state state = mState;
1326 if (state == RESUMING || state == ACTIVE || state == PAUSING || state == PAUSED) {
1327 // If the track is not active (PAUSED and buffers full), flush buffers
Andy Hung44f27182023-07-06 20:56:16 -07001328 auto* const playbackThread = thread->asIAfPlaybackThread().get();
1329 if (!playbackThread->isTrackActive(this)) {
Eric Laurent81784c32012-11-19 14:55:58 -08001330 reset();
1331 mState = STOPPED;
François Gaffie1353b292023-11-03 13:09:53 +01001332 } else if (isPatchTrack() || (!isFastTrack() && !isOffloaded() && !isDirect())) {
1333 // for a PatchTrack (whatever fast ot not), do not drain but move directly
1334 // to STOPPED to avoid closing while active.
Eric Laurent81784c32012-11-19 14:55:58 -08001335 mState = STOPPED;
1336 } else {
Eric Laurentbfb1b832013-01-07 09:53:42 -08001337 // For fast tracks prepareTracks_l() will set state to STOPPING_2
1338 // presentation is complete
1339 // For an offloaded track this starts a drain and state will
1340 // move to STOPPING_2 when drain completes and then STOPPED
Eric Laurent81784c32012-11-19 14:55:58 -08001341 mState = STOPPING_1;
Eric Laurente93cc032016-05-05 10:15:10 -07001342 if (isOffloaded()) {
Andy Hung44f27182023-07-06 20:56:16 -07001343 mRetryCount = IAfPlaybackThread::kMaxTrackStopRetriesOffload;
Eric Laurente93cc032016-05-05 10:15:10 -07001344 }
Eric Laurent81784c32012-11-19 14:55:58 -08001345 }
Eric Laurentb369caf2015-03-30 20:51:47 -07001346 playbackThread->broadcast_l();
Andy Hungc0691382018-09-12 18:01:57 -07001347 ALOGV("%s(%d): not stopping/stopped => stopping/stopped on thread %d",
1348 __func__, mId, (int)mThreadIoHandle);
Eric Laurent81784c32012-11-19 14:55:58 -08001349 }
jiabin6e506fc2023-06-27 18:22:35 +00001350 forEachTeePatchTrack_l([](const auto& patchTrack) { patchTrack->stop(); });
Eric Laurent81784c32012-11-19 14:55:58 -08001351 }
1352}
1353
Andy Hung3ff4b552023-06-26 19:20:57 -07001354void Track::pause()
Eric Laurent81784c32012-11-19 14:55:58 -08001355{
Andy Hungc0691382018-09-12 18:01:57 -07001356 ALOGV("%s(%d): calling pid %d", __func__, mId, IPCThreadState::self()->getCallingPid());
Andy Hung44f27182023-07-06 20:56:16 -07001357 const sp<IAfThreadBase> thread = mThread.promote();
Eric Laurent81784c32012-11-19 14:55:58 -08001358 if (thread != 0) {
Andy Hunga7187712023-12-05 17:28:17 -08001359 audio_utils::unique_lock ul(thread->mutex());
1360 thread->waitWhileThreadBusy_l(ul);
1361
Andy Hung44f27182023-07-06 20:56:16 -07001362 auto* const playbackThread = thread->asIAfPlaybackThread().get();
Eric Laurentbfb1b832013-01-07 09:53:42 -08001363 switch (mState) {
1364 case STOPPING_1:
1365 case STOPPING_2:
1366 if (!isOffloaded()) {
1367 /* nothing to do if track is not offloaded */
1368 break;
1369 }
1370
1371 // Offloaded track was draining, we need to carry on draining when resumed
1372 mResumeToStopping = true;
Chih-Hung Hsieh2b487032018-09-13 14:16:02 -07001373 FALLTHROUGH_INTENDED;
Eric Laurentbfb1b832013-01-07 09:53:42 -08001374 case ACTIVE:
1375 case RESUMING:
Eric Laurent81784c32012-11-19 14:55:58 -08001376 mState = PAUSING;
Andy Hungc0691382018-09-12 18:01:57 -07001377 ALOGV("%s(%d): ACTIVE/RESUMING => PAUSING on thread %d",
1378 __func__, mId, (int)mThreadIoHandle);
Kuowei Li23666472021-01-20 10:23:25 +08001379 if (isOffloadedOrDirect()) {
1380 mPauseHwPending = true;
1381 }
Eric Laurentede6c3b2013-09-19 14:37:46 -07001382 playbackThread->broadcast_l();
Eric Laurentbfb1b832013-01-07 09:53:42 -08001383 break;
Eric Laurent81784c32012-11-19 14:55:58 -08001384
Eric Laurentbfb1b832013-01-07 09:53:42 -08001385 default:
1386 break;
Eric Laurent81784c32012-11-19 14:55:58 -08001387 }
jiabin6e506fc2023-06-27 18:22:35 +00001388 // Pausing the TeePatch to avoid a glitch on underrun, at the cost of buffered audio loss.
1389 forEachTeePatchTrack_l([](const auto& patchTrack) { patchTrack->pause(); });
Eric Laurent81784c32012-11-19 14:55:58 -08001390 }
1391}
1392
Andy Hung3ff4b552023-06-26 19:20:57 -07001393void Track::flush()
Eric Laurent81784c32012-11-19 14:55:58 -08001394{
Andy Hungc0691382018-09-12 18:01:57 -07001395 ALOGV("%s(%d)", __func__, mId);
Andy Hung44f27182023-07-06 20:56:16 -07001396 const sp<IAfThreadBase> thread = mThread.promote();
Eric Laurent81784c32012-11-19 14:55:58 -08001397 if (thread != 0) {
Andy Hunga7187712023-12-05 17:28:17 -08001398 audio_utils::unique_lock ul(thread->mutex());
1399 thread->waitWhileThreadBusy_l(ul);
1400
Andy Hung44f27182023-07-06 20:56:16 -07001401 auto* const playbackThread = thread->asIAfPlaybackThread().get();
Eric Laurentbfb1b832013-01-07 09:53:42 -08001402
Phil Burk4bb650b2016-09-09 12:11:17 -07001403 // Flush the ring buffer now if the track is not active in the PlaybackThread.
1404 // Otherwise the flush would not be done until the track is resumed.
1405 // Requires FastTrack removal be BLOCK_UNTIL_ACKED
Andy Hung44f27182023-07-06 20:56:16 -07001406 if (!playbackThread->isTrackActive(this)) {
Phil Burk4bb650b2016-09-09 12:11:17 -07001407 (void)mServerProxy->flushBufferIfNeeded();
1408 }
1409
Eric Laurentbfb1b832013-01-07 09:53:42 -08001410 if (isOffloaded()) {
1411 // If offloaded we allow flush during any state except terminated
1412 // and keep the track active to avoid problems if user is seeking
1413 // rapidly and underlying hardware has a significant delay handling
1414 // a pause
1415 if (isTerminated()) {
1416 return;
1417 }
1418
Andy Hung9d84af52018-09-12 18:03:44 -07001419 ALOGV("%s(%d): offload flush", __func__, mId);
Eric Laurent81784c32012-11-19 14:55:58 -08001420 reset();
Eric Laurentbfb1b832013-01-07 09:53:42 -08001421
1422 if (mState == STOPPING_1 || mState == STOPPING_2) {
Andy Hung9d84af52018-09-12 18:03:44 -07001423 ALOGV("%s(%d): flushed in STOPPING_1 or 2 state, change state to ACTIVE",
1424 __func__, mId);
Eric Laurentbfb1b832013-01-07 09:53:42 -08001425 mState = ACTIVE;
1426 }
1427
Haynes Mathew George7844f672014-01-15 12:32:55 -08001428 mFlushHwPending = true;
Eric Laurentbfb1b832013-01-07 09:53:42 -08001429 mResumeToStopping = false;
1430 } else {
1431 if (mState != STOPPING_1 && mState != STOPPING_2 && mState != STOPPED &&
1432 mState != PAUSED && mState != PAUSING && mState != IDLE && mState != FLUSHED) {
1433 return;
1434 }
1435 // No point remaining in PAUSED state after a flush => go to
1436 // FLUSHED state
1437 mState = FLUSHED;
1438 // do not reset the track if it is still in the process of being stopped or paused.
1439 // this will be done by prepareTracks_l() when the track is stopped.
1440 // prepareTracks_l() will see mState == FLUSHED, then
1441 // remove from active track list, reset(), and trigger presentation complete
Eric Laurentd1f69b02014-12-15 14:33:13 -08001442 if (isDirect()) {
1443 mFlushHwPending = true;
1444 }
Andy Hung44f27182023-07-06 20:56:16 -07001445 if (!playbackThread->isTrackActive(this)) {
Eric Laurentbfb1b832013-01-07 09:53:42 -08001446 reset();
1447 }
Eric Laurent81784c32012-11-19 14:55:58 -08001448 }
Eric Laurentbfb1b832013-01-07 09:53:42 -08001449 // Prevent flush being lost if the track is flushed and then resumed
1450 // before mixer thread can run. This is important when offloading
1451 // because the hardware buffer could hold a large amount of audio
Eric Laurentede6c3b2013-09-19 14:37:46 -07001452 playbackThread->broadcast_l();
jiabin6e506fc2023-06-27 18:22:35 +00001453 // Flush the Tee to avoid on resume playing old data and glitching on the transition to
1454 // new data
1455 forEachTeePatchTrack_l([](const auto& patchTrack) { patchTrack->flush(); });
Eric Laurent81784c32012-11-19 14:55:58 -08001456 }
1457}
1458
Haynes Mathew George7844f672014-01-15 12:32:55 -08001459// must be called with thread lock held
Andy Hung3ff4b552023-06-26 19:20:57 -07001460void Track::flushAck()
Haynes Mathew George7844f672014-01-15 12:32:55 -08001461{
Andy Hung71ba4b32022-10-06 12:09:49 -07001462 if (!isOffloaded() && !isDirect()) {
Haynes Mathew George7844f672014-01-15 12:32:55 -08001463 return;
Andy Hung71ba4b32022-10-06 12:09:49 -07001464 }
Haynes Mathew George7844f672014-01-15 12:32:55 -08001465
Phil Burk4bb650b2016-09-09 12:11:17 -07001466 // Clear the client ring buffer so that the app can prime the buffer while paused.
1467 // Otherwise it might not get cleared until playback is resumed and obtainBuffer() is called.
1468 mServerProxy->flushBufferIfNeeded();
1469
Haynes Mathew George7844f672014-01-15 12:32:55 -08001470 mFlushHwPending = false;
1471}
1472
Andy Hung3ff4b552023-06-26 19:20:57 -07001473void Track::pauseAck()
Kuowei Li23666472021-01-20 10:23:25 +08001474{
1475 mPauseHwPending = false;
1476}
1477
Andy Hung3ff4b552023-06-26 19:20:57 -07001478void Track::reset()
Eric Laurent81784c32012-11-19 14:55:58 -08001479{
1480 // Do not reset twice to avoid discarding data written just after a flush and before
1481 // the audioflinger thread detects the track is stopped.
1482 if (!mResetDone) {
Eric Laurent81784c32012-11-19 14:55:58 -08001483 // Force underrun condition to avoid false underrun callback until first data is
1484 // written to buffer
Glenn Kasten96f60d82013-07-12 10:21:18 -07001485 android_atomic_and(~CBLK_FORCEREADY, &mCblk->mFlags);
Andy Hung3ff4b552023-06-26 19:20:57 -07001486 mFillingStatus = FS_FILLING;
Eric Laurent81784c32012-11-19 14:55:58 -08001487 mResetDone = true;
1488 if (mState == FLUSHED) {
1489 mState = IDLE;
1490 }
1491 }
1492}
1493
Andy Hung3ff4b552023-06-26 19:20:57 -07001494status_t Track::setParameters(const String8& keyValuePairs)
Eric Laurentbfb1b832013-01-07 09:53:42 -08001495{
Andy Hung44f27182023-07-06 20:56:16 -07001496 const sp<IAfThreadBase> thread = mThread.promote();
Eric Laurentbfb1b832013-01-07 09:53:42 -08001497 if (thread == 0) {
Andy Hung9d84af52018-09-12 18:03:44 -07001498 ALOGE("%s(%d): thread is dead", __func__, mId);
Eric Laurentbfb1b832013-01-07 09:53:42 -08001499 return FAILED_TRANSACTION;
Andy Hung44f27182023-07-06 20:56:16 -07001500 } else if (thread->type() == IAfThreadBase::DIRECT
1501 || thread->type() == IAfThreadBase::OFFLOAD) {
Eric Laurentbfb1b832013-01-07 09:53:42 -08001502 return thread->setParameters(keyValuePairs);
1503 } else {
1504 return PERMISSION_DENIED;
1505 }
1506}
1507
Andy Hung3ff4b552023-06-26 19:20:57 -07001508status_t Track::selectPresentation(int presentationId,
Mikhail Naganovac917ac2018-11-28 14:03:52 -08001509 int programId) {
Andy Hung44f27182023-07-06 20:56:16 -07001510 const sp<IAfThreadBase> thread = mThread.promote();
Mikhail Naganovac917ac2018-11-28 14:03:52 -08001511 if (thread == 0) {
1512 ALOGE("thread is dead");
1513 return FAILED_TRANSACTION;
Andy Hung44f27182023-07-06 20:56:16 -07001514 } else if (thread->type() == IAfThreadBase::DIRECT
1515 || thread->type() == IAfThreadBase::OFFLOAD) {
1516 auto directOutputThread = thread->asIAfDirectOutputThread().get();
Mikhail Naganovac917ac2018-11-28 14:03:52 -08001517 return directOutputThread->selectPresentation(presentationId, programId);
1518 }
1519 return INVALID_OPERATION;
1520}
1521
Andy Hung3ff4b552023-06-26 19:20:57 -07001522VolumeShaper::Status Track::applyVolumeShaper(
Andy Hung9fc8b5c2017-01-24 13:36:48 -08001523 const sp<VolumeShaper::Configuration>& configuration,
1524 const sp<VolumeShaper::Operation>& operation)
1525{
Andy Hungee86cee2022-12-13 19:19:53 -08001526 VolumeShaper::Status status = mVolumeHandler->applyVolumeShaper(configuration, operation);
Andy Hung10cbff12017-02-21 17:30:14 -08001527
1528 if (isOffloadedOrDirect()) {
1529 // Signal thread to fetch new volume.
Andy Hung44f27182023-07-06 20:56:16 -07001530 const sp<IAfThreadBase> thread = mThread.promote();
Andy Hung10cbff12017-02-21 17:30:14 -08001531 if (thread != 0) {
Andy Hung87e82412023-08-29 14:26:09 -07001532 audio_utils::lock_guard _l(thread->mutex());
Andy Hung10cbff12017-02-21 17:30:14 -08001533 thread->broadcast_l();
1534 }
1535 }
1536 return status;
Andy Hung9fc8b5c2017-01-24 13:36:48 -08001537}
1538
Andy Hung3ff4b552023-06-26 19:20:57 -07001539sp<VolumeShaper::State> Track::getVolumeShaperState(int id) const
Andy Hung9fc8b5c2017-01-24 13:36:48 -08001540{
1541 // Note: We don't check if Thread exists.
1542
1543 // mVolumeHandler is thread safe.
1544 return mVolumeHandler->getVolumeShaperState(id);
1545}
1546
Andy Hung3ff4b552023-06-26 19:20:57 -07001547void Track::setFinalVolume(float volumeLeft, float volumeRight)
Kevin Rocard12381092018-04-11 09:19:59 -07001548{
jiabin76d94692022-12-15 21:51:21 +00001549 mFinalVolumeLeft = volumeLeft;
1550 mFinalVolumeRight = volumeRight;
1551 const float volume = (volumeLeft + volumeRight) * 0.5f;
Kevin Rocard12381092018-04-11 09:19:59 -07001552 if (mFinalVolume != volume) { // Compare to an epsilon if too many meaningless updates
1553 mFinalVolume = volume;
1554 setMetadataHasChanged();
Andy Hungcb6cc752022-05-19 19:24:51 -07001555 mLogForceVolumeUpdate = true;
1556 }
1557 if (mLogForceVolumeUpdate) {
1558 mLogForceVolumeUpdate = false;
1559 mTrackMetrics.logVolume(mFinalVolume);
Kevin Rocard12381092018-04-11 09:19:59 -07001560 }
1561}
1562
Andy Hung3ff4b552023-06-26 19:20:57 -07001563void Track::copyMetadataTo(MetadataInserter& backInserter) const
Kevin Rocard12381092018-04-11 09:19:59 -07001564{
Eric Laurent49e39282022-06-24 18:42:45 +02001565 // Do not forward metadata for PatchTrack with unspecified stream type
1566 if (mStreamType == AUDIO_STREAM_PATCH) {
1567 return;
1568 }
1569
Eric Laurent94579172020-11-20 18:41:04 +01001570 playback_track_metadata_v7_t metadata;
1571 metadata.base = {
Kevin Rocard12381092018-04-11 09:19:59 -07001572 .usage = mAttr.usage,
1573 .content_type = mAttr.content_type,
1574 .gain = mFinalVolume,
1575 };
Eric Laurentfdf99502021-11-26 19:05:02 +01001576
1577 // When attributes are undefined, derive default values from stream type.
1578 // See AudioAttributes.java, usageForStreamType() and Builder.setInternalLegacyStreamType()
1579 if (mAttr.usage == AUDIO_USAGE_UNKNOWN) {
1580 switch (mStreamType) {
1581 case AUDIO_STREAM_VOICE_CALL:
1582 metadata.base.usage = AUDIO_USAGE_VOICE_COMMUNICATION;
1583 metadata.base.content_type = AUDIO_CONTENT_TYPE_SPEECH;
1584 break;
1585 case AUDIO_STREAM_SYSTEM:
1586 metadata.base.usage = AUDIO_USAGE_ASSISTANCE_SONIFICATION;
1587 metadata.base.content_type = AUDIO_CONTENT_TYPE_SONIFICATION;
1588 break;
1589 case AUDIO_STREAM_RING:
1590 metadata.base.usage = AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE;
1591 metadata.base.content_type = AUDIO_CONTENT_TYPE_SONIFICATION;
1592 break;
1593 case AUDIO_STREAM_MUSIC:
1594 metadata.base.usage = AUDIO_USAGE_MEDIA;
1595 metadata.base.content_type = AUDIO_CONTENT_TYPE_MUSIC;
1596 break;
1597 case AUDIO_STREAM_ALARM:
1598 metadata.base.usage = AUDIO_USAGE_ALARM;
1599 metadata.base.content_type = AUDIO_CONTENT_TYPE_SONIFICATION;
1600 break;
1601 case AUDIO_STREAM_NOTIFICATION:
1602 metadata.base.usage = AUDIO_USAGE_NOTIFICATION;
1603 metadata.base.content_type = AUDIO_CONTENT_TYPE_SONIFICATION;
1604 break;
1605 case AUDIO_STREAM_DTMF:
1606 metadata.base.usage = AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING;
1607 metadata.base.content_type = AUDIO_CONTENT_TYPE_SONIFICATION;
1608 break;
1609 case AUDIO_STREAM_ACCESSIBILITY:
1610 metadata.base.usage = AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY;
1611 metadata.base.content_type = AUDIO_CONTENT_TYPE_SPEECH;
1612 break;
1613 case AUDIO_STREAM_ASSISTANT:
1614 metadata.base.usage = AUDIO_USAGE_ASSISTANT;
1615 metadata.base.content_type = AUDIO_CONTENT_TYPE_SPEECH;
1616 break;
1617 case AUDIO_STREAM_REROUTING:
1618 metadata.base.usage = AUDIO_USAGE_VIRTUAL_SOURCE;
1619 // unknown content type
1620 break;
1621 case AUDIO_STREAM_CALL_ASSISTANT:
1622 metadata.base.usage = AUDIO_USAGE_CALL_ASSISTANT;
1623 metadata.base.content_type = AUDIO_CONTENT_TYPE_SPEECH;
1624 break;
1625 default:
1626 break;
1627 }
1628 }
1629
Eric Laurent78b07302022-10-07 16:20:34 +02001630 metadata.channel_mask = mChannelMask;
Eric Laurent94579172020-11-20 18:41:04 +01001631 strncpy(metadata.tags, mAttr.tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE);
1632 *backInserter++ = metadata;
Kevin Rocard12381092018-04-11 09:19:59 -07001633}
1634
jiabin6e506fc2023-06-27 18:22:35 +00001635void Track::updateTeePatches_l() {
Jiabin Huangfb476842022-12-06 03:18:10 +00001636 if (mTeePatchesToUpdate.has_value()) {
jiabin6e506fc2023-06-27 18:22:35 +00001637 forEachTeePatchTrack_l([](const auto& patchTrack) { patchTrack->destroy(); });
Jiabin Huang98b8d452024-01-04 18:42:55 +00001638 {
1639 RWLock::AutoWLock writeLock(mTeePatchesRWLock);
1640 mTeePatches = std::move(mTeePatchesToUpdate.value());
1641 }
Jiabin Huangfb476842022-12-06 03:18:10 +00001642 if (mState == TrackBase::ACTIVE || mState == TrackBase::RESUMING ||
1643 mState == TrackBase::STOPPING_1) {
jiabin6e506fc2023-06-27 18:22:35 +00001644 forEachTeePatchTrack_l([](const auto& patchTrack) { patchTrack->start(); });
Jiabin Huangfb476842022-12-06 03:18:10 +00001645 }
1646 mTeePatchesToUpdate.reset();
jiabinf042b9b2021-05-07 23:46:28 +00001647 }
Kevin Rocard153f92d2018-12-18 18:33:28 -08001648}
1649
jiabin6e506fc2023-06-27 18:22:35 +00001650void Track::setTeePatchesToUpdate_l(TeePatches teePatchesToUpdate) {
Jiabin Huangfb476842022-12-06 03:18:10 +00001651 ALOGW_IF(mTeePatchesToUpdate.has_value(),
1652 "%s, existing tee patches to update will be ignored", __func__);
1653 mTeePatchesToUpdate = std::move(teePatchesToUpdate);
1654}
1655
Vlad Popae8d99472022-06-30 16:02:48 +02001656// must be called with player thread lock held
Andy Hung3ff4b552023-06-26 19:20:57 -07001657void Track::processMuteEvent_l(const sp<
Vlad Popae8d99472022-06-30 16:02:48 +02001658 IAudioManager>& audioManager, mute_state_t muteState)
1659{
1660 if (mMuteState == muteState) {
1661 // mute state did not change, do nothing
1662 return;
1663 }
1664
1665 status_t result = UNKNOWN_ERROR;
1666 if (audioManager && mPortId != AUDIO_PORT_HANDLE_NONE) {
1667 if (mMuteEventExtras == nullptr) {
1668 mMuteEventExtras = std::make_unique<os::PersistableBundle>();
1669 }
Shunkai Yaoaf7990a2023-08-18 02:24:01 +00001670 mMuteEventExtras->putInt(String16(kExtraPlayerEventMuteKey), static_cast<int>(muteState));
Vlad Popae8d99472022-06-30 16:02:48 +02001671
Shunkai Yaoaf7990a2023-08-18 02:24:01 +00001672 result = audioManager->portEvent(mPortId, PLAYER_UPDATE_MUTED, mMuteEventExtras);
Vlad Popae8d99472022-06-30 16:02:48 +02001673 }
1674
1675 if (result == OK) {
Shunkai Yaoaf7990a2023-08-18 02:24:01 +00001676 ALOGI("%s(%d): processed mute state for port ID %d from %d to %d", __func__, id(), mPortId,
Andy Hung6fb26892024-02-20 16:32:57 -08001677 static_cast<int>(mMuteState), static_cast<int>(muteState));
Vlad Popae8d99472022-06-30 16:02:48 +02001678 mMuteState = muteState;
1679 } else {
Shunkai Yaoaf7990a2023-08-18 02:24:01 +00001680 ALOGW("%s(%d): cannot process mute state for port ID %d, status error %d", __func__, id(),
1681 mPortId, result);
Andy Hung818e7a32016-02-16 18:08:07 -08001682 }
Glenn Kastenfe346c72013-08-30 13:28:22 -07001683}
Glenn Kasten573d80a2013-08-26 09:36:23 -07001684
Andy Hung3ff4b552023-06-26 19:20:57 -07001685status_t Track::getTimestamp(AudioTimestamp& timestamp)
Eric Laurent81784c32012-11-19 14:55:58 -08001686{
1687 if (!isOffloaded() && !isDirect()) {
Glenn Kasten573d80a2013-08-26 09:36:23 -07001688 return INVALID_OPERATION; // normal tracks handled through SSQ
1689 }
Andy Hung44f27182023-07-06 20:56:16 -07001690 const sp<IAfThreadBase> thread = mThread.promote();
Glenn Kasten573d80a2013-08-26 09:36:23 -07001691 if (thread == 0) {
Glenn Kastenfe346c72013-08-30 13:28:22 -07001692 return INVALID_OPERATION;
Glenn Kasten573d80a2013-08-26 09:36:23 -07001693 }
Phil Burk6140c792015-03-19 14:30:21 -07001694
Andy Hung87e82412023-08-29 14:26:09 -07001695 audio_utils::lock_guard _l(thread->mutex());
Andy Hung44f27182023-07-06 20:56:16 -07001696 auto* const playbackThread = thread->asIAfPlaybackThread().get();
Andy Hung818e7a32016-02-16 18:08:07 -08001697 return playbackThread->getTimestamp_l(timestamp);
Glenn Kasten573d80a2013-08-26 09:36:23 -07001698}
1699
Andy Hung3ff4b552023-06-26 19:20:57 -07001700status_t Track::attachAuxEffect(int EffectId)
Eric Laurent81784c32012-11-19 14:55:58 -08001701{
Andy Hung44f27182023-07-06 20:56:16 -07001702 const sp<IAfThreadBase> thread = mThread.promote();
Eric Laurent6c796322019-04-09 14:13:17 -07001703 if (thread == nullptr) {
1704 return DEAD_OBJECT;
1705 }
Eric Laurent81784c32012-11-19 14:55:58 -08001706
Andy Hung44f27182023-07-06 20:56:16 -07001707 auto dstThread = thread->asIAfPlaybackThread();
Andy Hung3ff4b552023-06-26 19:20:57 -07001708 // srcThread is initialized by call to moveAuxEffectToIo()
Andy Hung44f27182023-07-06 20:56:16 -07001709 sp<IAfPlaybackThread> srcThread;
Andy Hungfa2f4f32023-07-17 12:40:43 -07001710 const auto& af = mClient->afClientCallback();
Eric Laurent6c796322019-04-09 14:13:17 -07001711 status_t status = af->moveAuxEffectToIo(EffectId, dstThread, &srcThread);
Eric Laurent81784c32012-11-19 14:55:58 -08001712
Eric Laurent6c796322019-04-09 14:13:17 -07001713 if (EffectId != 0 && status == NO_ERROR) {
1714 status = dstThread->attachAuxEffect(this, EffectId);
1715 if (status == NO_ERROR) {
1716 AudioSystem::moveEffectsToIo(std::vector<int>(EffectId), dstThread->id());
Eric Laurent81784c32012-11-19 14:55:58 -08001717 }
Eric Laurent6c796322019-04-09 14:13:17 -07001718 }
1719
1720 if (status != NO_ERROR && srcThread != nullptr) {
1721 af->moveAuxEffectToIo(EffectId, srcThread, &dstThread);
Eric Laurent81784c32012-11-19 14:55:58 -08001722 }
1723 return status;
1724}
1725
Andy Hung3ff4b552023-06-26 19:20:57 -07001726void Track::setAuxBuffer(int EffectId, int32_t *buffer)
Eric Laurent81784c32012-11-19 14:55:58 -08001727{
1728 mAuxEffectId = EffectId;
1729 mAuxBuffer = buffer;
1730}
1731
Andy Hung59de4262021-06-14 10:53:54 -07001732// presentationComplete verified by frames, used by Mixed tracks.
Andy Hung3ff4b552023-06-26 19:20:57 -07001733bool Track::presentationComplete(
Andy Hung818e7a32016-02-16 18:08:07 -08001734 int64_t framesWritten, size_t audioHalFrames)
Eric Laurent81784c32012-11-19 14:55:58 -08001735{
Andy Hung818e7a32016-02-16 18:08:07 -08001736 // TODO: improve this based on FrameMap if it exists, to ensure full drain.
1737 // This assists in proper timestamp computation as well as wakelock management.
1738
Eric Laurent81784c32012-11-19 14:55:58 -08001739 // a track is considered presented when the total number of frames written to audio HAL
1740 // corresponds to the number of frames written when presentationComplete() is called for the
1741 // first time (mPresentationCompleteFrames == 0) plus the buffer filling status at that time.
Eric Laurentbfb1b832013-01-07 09:53:42 -08001742 // For an offloaded track the HAL+h/w delay is variable so a HAL drain() is used
1743 // to detect when all frames have been played. In this case framesWritten isn't
1744 // useful because it doesn't always reflect whether there is data in the h/w
1745 // buffers, particularly if a track has been paused and resumed during draining
Andy Hung9d84af52018-09-12 18:03:44 -07001746 ALOGV("%s(%d): presentationComplete() mPresentationCompleteFrames %lld framesWritten %lld",
1747 __func__, mId,
Andy Hung818e7a32016-02-16 18:08:07 -08001748 (long long)mPresentationCompleteFrames, (long long)framesWritten);
Eric Laurent81784c32012-11-19 14:55:58 -08001749 if (mPresentationCompleteFrames == 0) {
1750 mPresentationCompleteFrames = framesWritten + audioHalFrames;
Andy Hung59de4262021-06-14 10:53:54 -07001751 ALOGV("%s(%d): set:"
Andy Hung9d84af52018-09-12 18:03:44 -07001752 " mPresentationCompleteFrames %lld audioHalFrames %zu",
1753 __func__, mId,
Andy Hung818e7a32016-02-16 18:08:07 -08001754 (long long)mPresentationCompleteFrames, audioHalFrames);
Eric Laurent81784c32012-11-19 14:55:58 -08001755 }
Eric Laurentbfb1b832013-01-07 09:53:42 -08001756
Andy Hungc54b1ff2016-02-23 14:07:07 -08001757 bool complete;
Andy Hung59de4262021-06-14 10:53:54 -07001758 if (isFastTrack()) { // does not go through linear map
Glenn Kastenc42e9b42016-03-21 11:35:03 -07001759 complete = framesWritten >= (int64_t) mPresentationCompleteFrames;
Andy Hung59de4262021-06-14 10:53:54 -07001760 ALOGV("%s(%d): %s framesWritten:%lld mPresentationCompleteFrames:%lld",
1761 __func__, mId, (complete ? "complete" : "waiting"),
1762 (long long) framesWritten, (long long) mPresentationCompleteFrames);
Andy Hungc54b1ff2016-02-23 14:07:07 -08001763 } else { // Normal tracks, OutputTracks, and PatchTracks
Glenn Kastenc42e9b42016-03-21 11:35:03 -07001764 complete = framesWritten >= (int64_t) mPresentationCompleteFrames
Andy Hungc54b1ff2016-02-23 14:07:07 -08001765 && mAudioTrackServerProxy->isDrained();
1766 }
1767
1768 if (complete) {
Andy Hung59de4262021-06-14 10:53:54 -07001769 notifyPresentationComplete();
Eric Laurent81784c32012-11-19 14:55:58 -08001770 return true;
1771 }
1772 return false;
1773}
1774
Andy Hung59de4262021-06-14 10:53:54 -07001775// presentationComplete checked by time, used by DirectTracks.
Andy Hung3ff4b552023-06-26 19:20:57 -07001776bool Track::presentationComplete(uint32_t latencyMs)
Andy Hung59de4262021-06-14 10:53:54 -07001777{
1778 // For Offloaded or Direct tracks.
1779
1780 // For a direct track, we incorporated time based testing for presentationComplete.
1781
1782 // For an offloaded track the HAL+h/w delay is variable so a HAL drain() is used
1783 // to detect when all frames have been played. In this case latencyMs isn't
1784 // useful because it doesn't always reflect whether there is data in the h/w
1785 // buffers, particularly if a track has been paused and resumed during draining
1786
1787 constexpr float MIN_SPEED = 0.125f; // min speed scaling allowed for timely response.
1788 if (mPresentationCompleteTimeNs == 0) {
1789 mPresentationCompleteTimeNs = systemTime() + latencyMs * 1e6 / fmax(mSpeed, MIN_SPEED);
1790 ALOGV("%s(%d): set: latencyMs %u mPresentationCompleteTimeNs:%lld",
1791 __func__, mId, latencyMs, (long long) mPresentationCompleteTimeNs);
1792 }
1793
1794 bool complete;
1795 if (isOffloaded()) {
1796 complete = true;
1797 } else { // Direct
1798 complete = systemTime() >= mPresentationCompleteTimeNs;
1799 ALOGV("%s(%d): %s", __func__, mId, (complete ? "complete" : "waiting"));
1800 }
1801 if (complete) {
1802 notifyPresentationComplete();
1803 return true;
1804 }
1805 return false;
1806}
1807
Andy Hung3ff4b552023-06-26 19:20:57 -07001808void Track::notifyPresentationComplete()
Andy Hung59de4262021-06-14 10:53:54 -07001809{
1810 // This only triggers once. TODO: should we enforce this?
1811 triggerEvents(AudioSystem::SYNC_EVENT_PRESENTATION_COMPLETE);
1812 mAudioTrackServerProxy->setStreamEndDone();
1813}
1814
Andy Hung3ff4b552023-06-26 19:20:57 -07001815void Track::triggerEvents(AudioSystem::sync_event_t type)
Eric Laurent81784c32012-11-19 14:55:58 -08001816{
Andy Hung068e08e2023-05-15 19:02:55 -07001817 for (auto it = mSyncEvents.begin(); it != mSyncEvents.end();) {
1818 if ((*it)->type() == type) {
Andy Hung93bb5732023-05-04 21:16:34 -07001819 ALOGV("%s: triggering SyncEvent type %d", __func__, type);
Andy Hung068e08e2023-05-15 19:02:55 -07001820 (*it)->trigger();
1821 it = mSyncEvents.erase(it);
Ivan Lozano5ec161b2017-12-06 10:00:28 -08001822 } else {
Andy Hung068e08e2023-05-15 19:02:55 -07001823 ++it;
Eric Laurent81784c32012-11-19 14:55:58 -08001824 }
1825 }
1826}
1827
1828// implement VolumeBufferProvider interface
1829
Andy Hung3ff4b552023-06-26 19:20:57 -07001830gain_minifloat_packed_t Track::getVolumeLR() const
Eric Laurent81784c32012-11-19 14:55:58 -08001831{
1832 // called by FastMixer, so not allowed to take any locks, block, or do I/O including logs
1833 ALOG_ASSERT(isFastTrack() && (mCblk != NULL));
Glenn Kastenc56f3422014-03-21 17:53:17 -07001834 gain_minifloat_packed_t vlr = mAudioTrackServerProxy->getVolumeLR();
1835 float vl = float_from_gain(gain_minifloat_unpack_left(vlr));
1836 float vr = float_from_gain(gain_minifloat_unpack_right(vlr));
Eric Laurent81784c32012-11-19 14:55:58 -08001837 // track volumes come from shared memory, so can't be trusted and must be clamped
Glenn Kastenc56f3422014-03-21 17:53:17 -07001838 if (vl > GAIN_FLOAT_UNITY) {
1839 vl = GAIN_FLOAT_UNITY;
Eric Laurent81784c32012-11-19 14:55:58 -08001840 }
Glenn Kastenc56f3422014-03-21 17:53:17 -07001841 if (vr > GAIN_FLOAT_UNITY) {
1842 vr = GAIN_FLOAT_UNITY;
Eric Laurent81784c32012-11-19 14:55:58 -08001843 }
1844 // now apply the cached master volume and stream type volume;
1845 // this is trusted but lacks any synchronization or barrier so may be stale
1846 float v = mCachedVolume;
1847 vl *= v;
1848 vr *= v;
Glenn Kastenc56f3422014-03-21 17:53:17 -07001849 // re-combine into packed minifloat
1850 vlr = gain_minifloat_pack(gain_from_float(vl), gain_from_float(vr));
Eric Laurent81784c32012-11-19 14:55:58 -08001851 // FIXME look at mute, pause, and stop flags
1852 return vlr;
1853}
1854
Andy Hung3ff4b552023-06-26 19:20:57 -07001855status_t Track::setSyncEvent(
Andy Hung068e08e2023-05-15 19:02:55 -07001856 const sp<audioflinger::SyncEvent>& event)
Eric Laurent81784c32012-11-19 14:55:58 -08001857{
Eric Laurentbfb1b832013-01-07 09:53:42 -08001858 if (isTerminated() || mState == PAUSED ||
Eric Laurent81784c32012-11-19 14:55:58 -08001859 ((framesReady() == 0) && ((mSharedBuffer != 0) ||
1860 (mState == STOPPED)))) {
Andy Hung9d84af52018-09-12 18:03:44 -07001861 ALOGW("%s(%d): in invalid state %d on session %d %s mode, framesReady %zu",
1862 __func__, mId,
Andy Hung959b5b82021-09-24 10:46:20 -07001863 (int)mState, mSessionId, (mSharedBuffer != 0) ? "static" : "stream", framesReady());
Eric Laurent81784c32012-11-19 14:55:58 -08001864 event->cancel();
1865 return INVALID_OPERATION;
1866 }
1867 (void) TrackBase::setSyncEvent(event);
1868 return NO_ERROR;
1869}
1870
Andy Hung3ff4b552023-06-26 19:20:57 -07001871void Track::invalidate()
Glenn Kasten5736c352012-12-04 12:12:34 -08001872{
Eric Laurent6acd1d42017-01-04 14:23:29 -08001873 TrackBase::invalidate();
Eric Laurent4d231dc2016-03-11 18:38:23 -08001874 signalClientFlag(CBLK_INVALID);
Eric Laurent4d231dc2016-03-11 18:38:23 -08001875}
1876
Andy Hung3ff4b552023-06-26 19:20:57 -07001877void Track::disable()
Eric Laurent4d231dc2016-03-11 18:38:23 -08001878{
Kevin Rocard01c7d9e2019-09-18 11:24:52 +01001879 // TODO(b/142394888): the filling status should also be reset to filling
Eric Laurent4d231dc2016-03-11 18:38:23 -08001880 signalClientFlag(CBLK_DISABLED);
1881}
1882
Andy Hung3ff4b552023-06-26 19:20:57 -07001883void Track::signalClientFlag(int32_t flag)
Eric Laurent4d231dc2016-03-11 18:38:23 -08001884{
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001885 // FIXME should use proxy, and needs work
1886 audio_track_cblk_t* cblk = mCblk;
Eric Laurent4d231dc2016-03-11 18:38:23 -08001887 android_atomic_or(flag, &cblk->mFlags);
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001888 android_atomic_release_store(0x40000000, &cblk->mFutex);
1889 // client is not in server, so FUTEX_WAKE is needed instead of FUTEX_WAKE_PRIVATE
Elliott Hughesee499292014-05-21 17:55:51 -07001890 (void) syscall(__NR_futex, &cblk->mFutex, FUTEX_WAKE, INT_MAX);
Glenn Kasten5736c352012-12-04 12:12:34 -08001891}
1892
Andy Hung3ff4b552023-06-26 19:20:57 -07001893void Track::signal()
Eric Laurent59fe0102013-09-27 18:48:26 -07001894{
Andy Hung44f27182023-07-06 20:56:16 -07001895 const sp<IAfThreadBase> thread = mThread.promote();
Eric Laurent59fe0102013-09-27 18:48:26 -07001896 if (thread != 0) {
Andy Hung44f27182023-07-06 20:56:16 -07001897 auto* const t = thread->asIAfPlaybackThread().get();
Andy Hung87e82412023-08-29 14:26:09 -07001898 audio_utils::lock_guard _l(t->mutex());
Eric Laurent59fe0102013-09-27 18:48:26 -07001899 t->broadcast_l();
1900 }
1901}
1902
Andy Hung3ff4b552023-06-26 19:20:57 -07001903status_t Track::getDualMonoMode(audio_dual_mono_mode_t* mode) const
Kuowei Lid4adbdb2020-08-13 14:44:25 +08001904{
1905 status_t status = INVALID_OPERATION;
1906 if (isOffloadedOrDirect()) {
Andy Hung44f27182023-07-06 20:56:16 -07001907 const sp<IAfThreadBase> thread = mThread.promote();
Kuowei Lid4adbdb2020-08-13 14:44:25 +08001908 if (thread != nullptr) {
Andy Hung44f27182023-07-06 20:56:16 -07001909 auto* const t = thread->asIAfPlaybackThread().get();
Andy Hung87e82412023-08-29 14:26:09 -07001910 audio_utils::lock_guard _l(t->mutex());
Andy Hung44f27182023-07-06 20:56:16 -07001911 status = t->getOutput_l()->stream->getDualMonoMode(mode);
Kuowei Lid4adbdb2020-08-13 14:44:25 +08001912 ALOGD_IF((status == NO_ERROR) && (mDualMonoMode != *mode),
1913 "%s: mode %d inconsistent", __func__, mDualMonoMode);
1914 }
1915 }
1916 return status;
1917}
1918
Andy Hung3ff4b552023-06-26 19:20:57 -07001919status_t Track::setDualMonoMode(audio_dual_mono_mode_t mode)
Kuowei Lid4adbdb2020-08-13 14:44:25 +08001920{
1921 status_t status = INVALID_OPERATION;
1922 if (isOffloadedOrDirect()) {
Andy Hung44f27182023-07-06 20:56:16 -07001923 const sp<IAfThreadBase> thread = mThread.promote();
Kuowei Lid4adbdb2020-08-13 14:44:25 +08001924 if (thread != nullptr) {
Andy Hung44f27182023-07-06 20:56:16 -07001925 auto* const t = thread->asIAfPlaybackThread().get();
Andy Hung87e82412023-08-29 14:26:09 -07001926 audio_utils::lock_guard lock(t->mutex());
Andy Hung44f27182023-07-06 20:56:16 -07001927 status = t->getOutput_l()->stream->setDualMonoMode(mode);
Kuowei Lid4adbdb2020-08-13 14:44:25 +08001928 if (status == NO_ERROR) {
1929 mDualMonoMode = mode;
1930 }
1931 }
1932 }
1933 return status;
1934}
1935
Andy Hung3ff4b552023-06-26 19:20:57 -07001936status_t Track::getAudioDescriptionMixLevel(float* leveldB) const
Kuowei Lid4adbdb2020-08-13 14:44:25 +08001937{
1938 status_t status = INVALID_OPERATION;
1939 if (isOffloadedOrDirect()) {
Andy Hung44f27182023-07-06 20:56:16 -07001940 sp<IAfThreadBase> thread = mThread.promote();
Kuowei Lid4adbdb2020-08-13 14:44:25 +08001941 if (thread != nullptr) {
Andy Hung44f27182023-07-06 20:56:16 -07001942 auto* const t = thread->asIAfPlaybackThread().get();
Andy Hung87e82412023-08-29 14:26:09 -07001943 audio_utils::lock_guard lock(t->mutex());
Andy Hung44f27182023-07-06 20:56:16 -07001944 status = t->getOutput_l()->stream->getAudioDescriptionMixLevel(leveldB);
Kuowei Lid4adbdb2020-08-13 14:44:25 +08001945 ALOGD_IF((status == NO_ERROR) && (mAudioDescriptionMixLevel != *leveldB),
1946 "%s: level %.3f inconsistent", __func__, mAudioDescriptionMixLevel);
1947 }
1948 }
1949 return status;
1950}
1951
Andy Hung3ff4b552023-06-26 19:20:57 -07001952status_t Track::setAudioDescriptionMixLevel(float leveldB)
Kuowei Lid4adbdb2020-08-13 14:44:25 +08001953{
1954 status_t status = INVALID_OPERATION;
1955 if (isOffloadedOrDirect()) {
Andy Hung44f27182023-07-06 20:56:16 -07001956 const sp<IAfThreadBase> thread = mThread.promote();
Kuowei Lid4adbdb2020-08-13 14:44:25 +08001957 if (thread != nullptr) {
Andy Hung44f27182023-07-06 20:56:16 -07001958 auto* const t = thread->asIAfPlaybackThread().get();
Andy Hung87e82412023-08-29 14:26:09 -07001959 audio_utils::lock_guard lock(t->mutex());
Andy Hung44f27182023-07-06 20:56:16 -07001960 status = t->getOutput_l()->stream->setAudioDescriptionMixLevel(leveldB);
Kuowei Lid4adbdb2020-08-13 14:44:25 +08001961 if (status == NO_ERROR) {
1962 mAudioDescriptionMixLevel = leveldB;
1963 }
1964 }
1965 }
1966 return status;
1967}
1968
Andy Hung3ff4b552023-06-26 19:20:57 -07001969status_t Track::getPlaybackRateParameters(
Andy Hung02a6c4e2023-06-23 19:27:19 -07001970 audio_playback_rate_t* playbackRate) const
Kuowei Lid4adbdb2020-08-13 14:44:25 +08001971{
1972 status_t status = INVALID_OPERATION;
1973 if (isOffloadedOrDirect()) {
Andy Hung44f27182023-07-06 20:56:16 -07001974 const sp<IAfThreadBase> thread = mThread.promote();
Kuowei Lid4adbdb2020-08-13 14:44:25 +08001975 if (thread != nullptr) {
Andy Hung44f27182023-07-06 20:56:16 -07001976 auto* const t = thread->asIAfPlaybackThread().get();
Andy Hung87e82412023-08-29 14:26:09 -07001977 audio_utils::lock_guard lock(t->mutex());
Andy Hung44f27182023-07-06 20:56:16 -07001978 status = t->getOutput_l()->stream->getPlaybackRateParameters(playbackRate);
Kuowei Lid4adbdb2020-08-13 14:44:25 +08001979 ALOGD_IF((status == NO_ERROR) &&
1980 !isAudioPlaybackRateEqual(mPlaybackRateParameters, *playbackRate),
1981 "%s: playbackRate inconsistent", __func__);
1982 }
1983 }
1984 return status;
1985}
1986
Andy Hung3ff4b552023-06-26 19:20:57 -07001987status_t Track::setPlaybackRateParameters(
Kuowei Lid4adbdb2020-08-13 14:44:25 +08001988 const audio_playback_rate_t& playbackRate)
1989{
1990 status_t status = INVALID_OPERATION;
1991 if (isOffloadedOrDirect()) {
Andy Hung44f27182023-07-06 20:56:16 -07001992 const sp<IAfThreadBase> thread = mThread.promote();
Kuowei Lid4adbdb2020-08-13 14:44:25 +08001993 if (thread != nullptr) {
Andy Hung44f27182023-07-06 20:56:16 -07001994 auto* const t = thread->asIAfPlaybackThread().get();
Andy Hung87e82412023-08-29 14:26:09 -07001995 audio_utils::lock_guard lock(t->mutex());
Andy Hung44f27182023-07-06 20:56:16 -07001996 status = t->getOutput_l()->stream->setPlaybackRateParameters(playbackRate);
Kuowei Lid4adbdb2020-08-13 14:44:25 +08001997 if (status == NO_ERROR) {
1998 mPlaybackRateParameters = playbackRate;
1999 }
2000 }
2001 }
2002 return status;
2003}
2004
Krishnankutty Kolathappilly8d6c2922014-02-04 16:23:42 -08002005//To be called with thread lock held
Andy Hung3ff4b552023-06-26 19:20:57 -07002006bool Track::isResumePending() const {
Andy Hung71ba4b32022-10-06 12:09:49 -07002007 if (mState == RESUMING) {
Krishnankutty Kolathappilly8d6c2922014-02-04 16:23:42 -08002008 return true;
Andy Hung71ba4b32022-10-06 12:09:49 -07002009 }
Krishnankutty Kolathappilly8d6c2922014-02-04 16:23:42 -08002010 /* Resume is pending if track was stopping before pause was called */
2011 if (mState == STOPPING_1 &&
Andy Hung71ba4b32022-10-06 12:09:49 -07002012 mResumeToStopping) {
Krishnankutty Kolathappilly8d6c2922014-02-04 16:23:42 -08002013 return true;
Andy Hung71ba4b32022-10-06 12:09:49 -07002014 }
Krishnankutty Kolathappilly8d6c2922014-02-04 16:23:42 -08002015
2016 return false;
2017}
2018
2019//To be called with thread lock held
Andy Hung3ff4b552023-06-26 19:20:57 -07002020void Track::resumeAck() {
Andy Hung71ba4b32022-10-06 12:09:49 -07002021 if (mState == RESUMING) {
Krishnankutty Kolathappilly8d6c2922014-02-04 16:23:42 -08002022 mState = ACTIVE;
Andy Hung71ba4b32022-10-06 12:09:49 -07002023 }
Haynes Mathew George2d3ca682014-03-07 13:43:49 -08002024
Krishnankutty Kolathappilly8d6c2922014-02-04 16:23:42 -08002025 // Other possibility of pending resume is stopping_1 state
2026 // Do not update the state from stopping as this prevents
Haynes Mathew George2d3ca682014-03-07 13:43:49 -08002027 // drain being called.
2028 if (mState == STOPPING_1) {
2029 mResumeToStopping = false;
2030 }
Krishnankutty Kolathappilly8d6c2922014-02-04 16:23:42 -08002031}
Andy Hunge10393e2015-06-12 13:59:33 -07002032
2033//To be called with thread lock held
Andy Hung3ff4b552023-06-26 19:20:57 -07002034void Track::updateTrackFrameInfo(
Andy Hung818e7a32016-02-16 18:08:07 -08002035 int64_t trackFramesReleased, int64_t sinkFramesWritten,
Andy Hungcef2daa2018-06-01 15:31:49 -07002036 uint32_t halSampleRate, const ExtendedTimestamp &timeStamp) {
Andy Hung30282562018-08-08 18:27:03 -07002037 // Make the kernel frametime available.
2038 const FrameTime ft{
2039 timeStamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL],
2040 timeStamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL]};
2041 // ALOGD("FrameTime: %lld %lld", (long long)ft.frames, (long long)ft.timeNs);
2042 mKernelFrameTime.store(ft);
2043 if (!audio_is_linear_pcm(mFormat)) {
2044 return;
2045 }
2046
Andy Hung818e7a32016-02-16 18:08:07 -08002047 //update frame map
Andy Hunge10393e2015-06-12 13:59:33 -07002048 mFrameMap.push(trackFramesReleased, sinkFramesWritten);
Andy Hung818e7a32016-02-16 18:08:07 -08002049
2050 // adjust server times and set drained state.
2051 //
2052 // Our timestamps are only updated when the track is on the Thread active list.
2053 // We need to ensure that tracks are not removed before full drain.
2054 ExtendedTimestamp local = timeStamp;
Andy Hungcef2daa2018-06-01 15:31:49 -07002055 bool drained = true; // default assume drained, if no server info found
Andy Hung818e7a32016-02-16 18:08:07 -08002056 bool checked = false;
2057 for (int i = ExtendedTimestamp::LOCATION_MAX - 1;
2058 i >= ExtendedTimestamp::LOCATION_SERVER; --i) {
2059 // Lookup the track frame corresponding to the sink frame position.
2060 if (local.mTimeNs[i] > 0) {
2061 local.mPosition[i] = mFrameMap.findX(local.mPosition[i]);
2062 // check drain state from the latest stage in the pipeline.
Andy Hung6d7b1192016-05-07 22:59:48 -07002063 if (!checked && i <= ExtendedTimestamp::LOCATION_KERNEL) {
Andy Hungcef2daa2018-06-01 15:31:49 -07002064 drained = local.mPosition[i] >= mAudioTrackServerProxy->framesReleased();
Andy Hung818e7a32016-02-16 18:08:07 -08002065 checked = true;
2066 }
2067 }
Andy Hunge10393e2015-06-12 13:59:33 -07002068 }
Andy Hungcef2daa2018-06-01 15:31:49 -07002069
Andy Hung93bb5732023-05-04 21:16:34 -07002070 ALOGV("%s: trackFramesReleased:%lld sinkFramesWritten:%lld setDrained: %d",
2071 __func__, (long long)trackFramesReleased, (long long)sinkFramesWritten, drained);
Andy Hungcef2daa2018-06-01 15:31:49 -07002072 mAudioTrackServerProxy->setDrained(drained);
Andy Hungea2b9c02016-02-12 17:06:53 -08002073 // Set correction for flushed frames that are not accounted for in released.
Andy Hungea2b9c02016-02-12 17:06:53 -08002074 local.mFlushed = mAudioTrackServerProxy->framesFlushed();
Andy Hung818e7a32016-02-16 18:08:07 -08002075 mServerProxy->setTimestamp(local);
Andy Hungcef2daa2018-06-01 15:31:49 -07002076
2077 // Compute latency info.
2078 const bool useTrackTimestamp = !drained;
2079 const double latencyMs = useTrackTimestamp
2080 ? local.getOutputServerLatencyMs(sampleRate())
2081 : timeStamp.getOutputServerLatencyMs(halSampleRate);
2082
2083 mServerLatencyFromTrack.store(useTrackTimestamp);
2084 mServerLatencyMs.store(latencyMs);
Andy Hungb68f5eb2019-12-03 16:49:17 -08002085
Andy Hung62921122020-05-18 10:47:31 -07002086 if (mLogStartCountdown > 0
2087 && local.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] > 0
2088 && local.mPosition[ExtendedTimestamp::LOCATION_KERNEL] > 0)
2089 {
2090 if (mLogStartCountdown > 1) {
2091 --mLogStartCountdown;
2092 } else if (latencyMs < mLogLatencyMs) { // wait for latency to stabilize (dip)
2093 mLogStartCountdown = 0;
Andy Hungb68f5eb2019-12-03 16:49:17 -08002094 // startup is the difference in times for the current timestamp and our start
2095 double startUpMs =
Andy Hung62921122020-05-18 10:47:31 -07002096 (local.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] - mLogStartTimeNs) * 1e-6;
Andy Hungb68f5eb2019-12-03 16:49:17 -08002097 // adjust for frames played.
Andy Hung62921122020-05-18 10:47:31 -07002098 startUpMs -= (local.mPosition[ExtendedTimestamp::LOCATION_KERNEL] - mLogStartFrames)
2099 * 1e3 / mSampleRate;
2100 ALOGV("%s: latencyMs:%lf startUpMs:%lf"
2101 " localTime:%lld startTime:%lld"
2102 " localPosition:%lld startPosition:%lld",
2103 __func__, latencyMs, startUpMs,
2104 (long long)local.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL],
Andy Hungb68f5eb2019-12-03 16:49:17 -08002105 (long long)mLogStartTimeNs,
Andy Hung62921122020-05-18 10:47:31 -07002106 (long long)local.mPosition[ExtendedTimestamp::LOCATION_KERNEL],
Andy Hungb68f5eb2019-12-03 16:49:17 -08002107 (long long)mLogStartFrames);
Andy Hungc2b11cb2020-04-22 09:04:01 -07002108 mTrackMetrics.logLatencyAndStartup(latencyMs, startUpMs);
Andy Hungb68f5eb2019-12-03 16:49:17 -08002109 }
Andy Hung62921122020-05-18 10:47:31 -07002110 mLogLatencyMs = latencyMs;
Andy Hungb68f5eb2019-12-03 16:49:17 -08002111 }
Andy Hunge10393e2015-06-12 13:59:33 -07002112}
2113
Andy Hung3ff4b552023-06-26 19:20:57 -07002114bool Track::AudioVibrationController::setMute(bool muted) {
Andy Hung44f27182023-07-06 20:56:16 -07002115 const sp<IAfThreadBase> thread = mTrack->mThread.promote();
jiabin57303cc2018-12-18 15:45:57 -08002116 if (thread != 0) {
2117 // Lock for updating mHapticPlaybackEnabled.
Andy Hung87e82412023-08-29 14:26:09 -07002118 audio_utils::lock_guard _l(thread->mutex());
Andy Hung44f27182023-07-06 20:56:16 -07002119 auto* const playbackThread = thread->asIAfPlaybackThread().get();
jiabin57303cc2018-12-18 15:45:57 -08002120 if ((mTrack->channelMask() & AUDIO_CHANNEL_HAPTIC_ALL) != AUDIO_CHANNEL_NONE
Andy Hung44f27182023-07-06 20:56:16 -07002121 && playbackThread->hapticChannelCount() > 0) {
SPeak Shenc19aa9e2022-11-11 00:28:50 +08002122 ALOGD("%s, haptic playback was %s for track %d",
2123 __func__, muted ? "muted" : "unmuted", mTrack->id());
SPeak Shen0db56b32022-11-11 00:28:50 +08002124 mTrack->setHapticPlaybackEnabled(!muted);
2125 return true;
jiabin57303cc2018-12-18 15:45:57 -08002126 }
2127 }
SPeak Shen0db56b32022-11-11 00:28:50 +08002128 return false;
2129}
2130
Andy Hung3ff4b552023-06-26 19:20:57 -07002131binder::Status Track::AudioVibrationController::mute(
SPeak Shen0db56b32022-11-11 00:28:50 +08002132 /*out*/ bool *ret) {
2133 *ret = setMute(true);
jiabin57303cc2018-12-18 15:45:57 -08002134 return binder::Status::ok();
2135}
2136
Andy Hung3ff4b552023-06-26 19:20:57 -07002137binder::Status Track::AudioVibrationController::unmute(
jiabin57303cc2018-12-18 15:45:57 -08002138 /*out*/ bool *ret) {
SPeak Shen0db56b32022-11-11 00:28:50 +08002139 *ret = setMute(false);
jiabin57303cc2018-12-18 15:45:57 -08002140 return binder::Status::ok();
2141}
2142
Eric Laurent81784c32012-11-19 14:55:58 -08002143// ----------------------------------------------------------------------------
Andy Hung9d84af52018-09-12 18:03:44 -07002144#undef LOG_TAG
2145#define LOG_TAG "AF::OutputTrack"
Eric Laurent81784c32012-11-19 14:55:58 -08002146
Andy Hung3ff4b552023-06-26 19:20:57 -07002147/* static */
Andy Hung44f27182023-07-06 20:56:16 -07002148sp<IAfOutputTrack> IAfOutputTrack::create(
2149 IAfPlaybackThread* playbackThread,
2150 IAfDuplicatingThread* sourceThread,
Andy Hung3ff4b552023-06-26 19:20:57 -07002151 uint32_t sampleRate,
2152 audio_format_t format,
2153 audio_channel_mask_t channelMask,
2154 size_t frameCount,
2155 const AttributionSourceState& attributionSource) {
2156 return sp<OutputTrack>::make(
Andy Hung44f27182023-07-06 20:56:16 -07002157 playbackThread,
2158 sourceThread,
Andy Hung3ff4b552023-06-26 19:20:57 -07002159 sampleRate,
2160 format,
2161 channelMask,
2162 frameCount,
2163 attributionSource);
2164}
2165
2166OutputTrack::OutputTrack(
Andy Hung44f27182023-07-06 20:56:16 -07002167 IAfPlaybackThread* playbackThread,
2168 IAfDuplicatingThread* sourceThread,
Eric Laurent81784c32012-11-19 14:55:58 -08002169 uint32_t sampleRate,
2170 audio_format_t format,
2171 audio_channel_mask_t channelMask,
Marco Nelissen462fd2f2013-01-14 14:12:05 -08002172 size_t frameCount,
Svet Ganov33761132021-05-13 22:51:08 +00002173 const AttributionSourceState& attributionSource)
Eric Laurent223fd5c2014-11-11 13:43:36 -08002174 : Track(playbackThread, NULL, AUDIO_STREAM_PATCH,
Kevin Rocard1f564ac2018-03-29 13:53:10 -07002175 audio_attributes_t{} /* currently unused for output track */,
Eric Laurent223fd5c2014-11-11 13:43:36 -08002176 sampleRate, format, channelMask, frameCount,
Andy Hung8fe68032017-06-05 16:17:51 -07002177 nullptr /* buffer */, (size_t)0 /* bufferSize */, nullptr /* sharedBuffer */,
Svet Ganov33761132021-05-13 22:51:08 +00002178 AUDIO_SESSION_NONE, getpid(), attributionSource, AUDIO_OUTPUT_FLAG_NONE,
Glenn Kastend848eb42016-03-08 13:42:11 -08002179 TYPE_OUTPUT),
Eric Laurent5bba2f62016-03-18 11:14:14 -07002180 mActive(false), mSourceThread(sourceThread)
Eric Laurent81784c32012-11-19 14:55:58 -08002181{
2182
2183 if (mCblk != NULL) {
Eric Laurent81784c32012-11-19 14:55:58 -08002184 mOutBuffer.frameCount = 0;
Andy Hung44f27182023-07-06 20:56:16 -07002185 playbackThread->addOutputTrack_l(this);
Andy Hung9d84af52018-09-12 18:03:44 -07002186 ALOGV("%s(): mCblk %p, mBuffer %p, "
Glenn Kastenc42e9b42016-03-21 11:35:03 -07002187 "frameCount %zu, mChannelMask 0x%08x",
Andy Hung9d84af52018-09-12 18:03:44 -07002188 __func__, mCblk, mBuffer,
Glenn Kasten74935e42013-12-19 08:56:45 -08002189 frameCount, mChannelMask);
Glenn Kastene3aa6592012-12-04 12:22:46 -08002190 // since client and server are in the same process,
2191 // the buffer has the same virtual address on both sides
Glenn Kasten529c61b2014-07-18 15:31:02 -07002192 mClientProxy = new AudioTrackClientProxy(mCblk, mBuffer, mFrameCount, mFrameSize,
2193 true /*clientInServer*/);
Glenn Kastenc56f3422014-03-21 17:53:17 -07002194 mClientProxy->setVolumeLR(GAIN_MINIFLOAT_PACKED_UNITY);
Eric Laurent8d2d4932013-04-25 12:56:18 -07002195 mClientProxy->setSendLevel(0.0);
2196 mClientProxy->setSampleRate(sampleRate);
Eric Laurent81784c32012-11-19 14:55:58 -08002197 } else {
Andy Hung9d84af52018-09-12 18:03:44 -07002198 ALOGW("%s(%d): Error creating output track on thread %d",
2199 __func__, mId, (int)mThreadIoHandle);
Eric Laurent81784c32012-11-19 14:55:58 -08002200 }
2201}
2202
Andy Hung3ff4b552023-06-26 19:20:57 -07002203OutputTrack::~OutputTrack()
Eric Laurent81784c32012-11-19 14:55:58 -08002204{
2205 clearBufferQueue();
Glenn Kastene3aa6592012-12-04 12:22:46 -08002206 // superclass destructor will now delete the server proxy and shared memory both refer to
Eric Laurent81784c32012-11-19 14:55:58 -08002207}
2208
Andy Hung3ff4b552023-06-26 19:20:57 -07002209status_t OutputTrack::start(AudioSystem::sync_event_t event,
Glenn Kastend848eb42016-03-08 13:42:11 -08002210 audio_session_t triggerSession)
Eric Laurent81784c32012-11-19 14:55:58 -08002211{
2212 status_t status = Track::start(event, triggerSession);
2213 if (status != NO_ERROR) {
2214 return status;
2215 }
2216
2217 mActive = true;
2218 mRetryCount = 127;
2219 return status;
2220}
2221
Andy Hung3ff4b552023-06-26 19:20:57 -07002222void OutputTrack::stop()
Eric Laurent81784c32012-11-19 14:55:58 -08002223{
2224 Track::stop();
2225 clearBufferQueue();
2226 mOutBuffer.frameCount = 0;
2227 mActive = false;
2228}
2229
Andy Hung3ff4b552023-06-26 19:20:57 -07002230ssize_t OutputTrack::write(void* data, uint32_t frames)
Eric Laurent81784c32012-11-19 14:55:58 -08002231{
Eric Laurent19952e12023-04-20 10:08:29 +02002232 if (!mActive && frames != 0) {
Andy Hung44f27182023-07-06 20:56:16 -07002233 const sp<IAfThreadBase> thread = mThread.promote();
Andy Hung4989d312023-06-29 21:19:25 -07002234 if (thread != nullptr && thread->inStandby()) {
Eric Laurent19952e12023-04-20 10:08:29 +02002235 // preload one silent buffer to trigger mixer on start()
2236 ClientProxy::Buffer buf { .mFrameCount = mClientProxy->getStartThresholdInFrames() };
2237 status_t status = mClientProxy->obtainBuffer(&buf);
2238 if (status != NO_ERROR && status != NOT_ENOUGH_DATA && status != WOULD_BLOCK) {
2239 ALOGE("%s(%d): could not obtain buffer on start", __func__, mId);
2240 return 0;
2241 }
2242 memset(buf.mRaw, 0, buf.mFrameCount * mFrameSize);
2243 mClientProxy->releaseBuffer(&buf);
2244
2245 (void) start();
2246
2247 // wait for HAL stream to start before sending actual audio. Doing this on each
2248 // OutputTrack makes that playback start on all output streams is synchronized.
2249 // If another OutputTrack has already started it can underrun but this is OK
2250 // as only silence has been played so far and the retry count is very high on
2251 // OutputTrack.
Andy Hung44f27182023-07-06 20:56:16 -07002252 auto* const pt = thread->asIAfPlaybackThread().get();
Eric Laurent19952e12023-04-20 10:08:29 +02002253 if (!pt->waitForHalStart()) {
2254 ALOGW("%s(%d): timeout waiting for thread to exit standby", __func__, mId);
2255 stop();
2256 return 0;
2257 }
2258
2259 // enqueue the first buffer and exit so that other OutputTracks will also start before
2260 // write() is called again and this buffer actually consumed.
2261 Buffer firstBuffer;
2262 firstBuffer.frameCount = frames;
2263 firstBuffer.raw = data;
2264 queueBuffer(firstBuffer);
2265 return frames;
2266 } else {
2267 (void) start();
2268 }
2269 }
2270
Eric Laurent81784c32012-11-19 14:55:58 -08002271 Buffer *pInBuffer;
2272 Buffer inBuffer;
Eric Laurent81784c32012-11-19 14:55:58 -08002273 inBuffer.frameCount = frames;
Andy Hungc25b84a2015-01-14 19:04:10 -08002274 inBuffer.raw = data;
Eric Laurent81784c32012-11-19 14:55:58 -08002275 uint32_t waitTimeLeftMs = mSourceThread->waitTimeMs();
Eric Laurent81784c32012-11-19 14:55:58 -08002276 while (waitTimeLeftMs) {
2277 // First write pending buffers, then new data
2278 if (mBufferQueue.size()) {
2279 pInBuffer = mBufferQueue.itemAt(0);
2280 } else {
2281 pInBuffer = &inBuffer;
2282 }
2283
2284 if (pInBuffer->frameCount == 0) {
2285 break;
2286 }
2287
2288 if (mOutBuffer.frameCount == 0) {
2289 mOutBuffer.frameCount = pInBuffer->frameCount;
2290 nsecs_t startTime = systemTime();
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002291 status_t status = obtainBuffer(&mOutBuffer, waitTimeLeftMs);
Eric Laurent4d231dc2016-03-11 18:38:23 -08002292 if (status != NO_ERROR && status != NOT_ENOUGH_DATA) {
Andy Hung9d84af52018-09-12 18:03:44 -07002293 ALOGV("%s(%d): thread %d no more output buffers; status %d",
2294 __func__, mId,
2295 (int)mThreadIoHandle, status);
Eric Laurent81784c32012-11-19 14:55:58 -08002296 break;
2297 }
2298 uint32_t waitTimeMs = (uint32_t)ns2ms(systemTime() - startTime);
2299 if (waitTimeLeftMs >= waitTimeMs) {
2300 waitTimeLeftMs -= waitTimeMs;
2301 } else {
2302 waitTimeLeftMs = 0;
2303 }
Eric Laurent4d231dc2016-03-11 18:38:23 -08002304 if (status == NOT_ENOUGH_DATA) {
2305 restartIfDisabled();
2306 continue;
2307 }
Eric Laurent81784c32012-11-19 14:55:58 -08002308 }
2309
2310 uint32_t outFrames = pInBuffer->frameCount > mOutBuffer.frameCount ? mOutBuffer.frameCount :
2311 pInBuffer->frameCount;
Andy Hungc25b84a2015-01-14 19:04:10 -08002312 memcpy(mOutBuffer.raw, pInBuffer->raw, outFrames * mFrameSize);
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002313 Proxy::Buffer buf;
2314 buf.mFrameCount = outFrames;
2315 buf.mRaw = NULL;
2316 mClientProxy->releaseBuffer(&buf);
Eric Laurent4d231dc2016-03-11 18:38:23 -08002317 restartIfDisabled();
Eric Laurent81784c32012-11-19 14:55:58 -08002318 pInBuffer->frameCount -= outFrames;
Andy Hungc25b84a2015-01-14 19:04:10 -08002319 pInBuffer->raw = (int8_t *)pInBuffer->raw + outFrames * mFrameSize;
Eric Laurent81784c32012-11-19 14:55:58 -08002320 mOutBuffer.frameCount -= outFrames;
Andy Hungc25b84a2015-01-14 19:04:10 -08002321 mOutBuffer.raw = (int8_t *)mOutBuffer.raw + outFrames * mFrameSize;
Eric Laurent81784c32012-11-19 14:55:58 -08002322
2323 if (pInBuffer->frameCount == 0) {
2324 if (mBufferQueue.size()) {
2325 mBufferQueue.removeAt(0);
Andy Hungc25b84a2015-01-14 19:04:10 -08002326 free(pInBuffer->mBuffer);
Yunlian Jiang8adc8082017-06-06 15:59:44 -07002327 if (pInBuffer != &inBuffer) {
2328 delete pInBuffer;
2329 }
Andy Hung9d84af52018-09-12 18:03:44 -07002330 ALOGV("%s(%d): thread %d released overflow buffer %zu",
2331 __func__, mId,
2332 (int)mThreadIoHandle, mBufferQueue.size());
Eric Laurent81784c32012-11-19 14:55:58 -08002333 } else {
2334 break;
2335 }
2336 }
2337 }
2338
2339 // If we could not write all frames, allocate a buffer and queue it for next time.
2340 if (inBuffer.frameCount) {
Andy Hung44f27182023-07-06 20:56:16 -07002341 const sp<IAfThreadBase> thread = mThread.promote();
Andy Hung4989d312023-06-29 21:19:25 -07002342 if (thread != nullptr && !thread->inStandby()) {
Eric Laurent19952e12023-04-20 10:08:29 +02002343 queueBuffer(inBuffer);
Eric Laurent81784c32012-11-19 14:55:58 -08002344 }
2345 }
2346
Andy Hungc25b84a2015-01-14 19:04:10 -08002347 // Calling write() with a 0 length buffer means that no more data will be written:
2348 // We rely on stop() to set the appropriate flags to allow the remaining frames to play out.
2349 if (frames == 0 && mBufferQueue.size() == 0 && mActive) {
2350 stop();
Eric Laurent81784c32012-11-19 14:55:58 -08002351 }
2352
Andy Hung1c86ebe2018-05-29 20:29:08 -07002353 return frames - inBuffer.frameCount; // number of frames consumed.
Eric Laurent81784c32012-11-19 14:55:58 -08002354}
2355
Andy Hung3ff4b552023-06-26 19:20:57 -07002356void OutputTrack::queueBuffer(Buffer& inBuffer) {
Eric Laurent19952e12023-04-20 10:08:29 +02002357
2358 if (mBufferQueue.size() < kMaxOverFlowBuffers) {
2359 Buffer *pInBuffer = new Buffer;
2360 const size_t bufferSize = inBuffer.frameCount * mFrameSize;
2361 pInBuffer->mBuffer = malloc(bufferSize);
2362 LOG_ALWAYS_FATAL_IF(pInBuffer->mBuffer == nullptr,
2363 "%s: Unable to malloc size %zu", __func__, bufferSize);
2364 pInBuffer->frameCount = inBuffer.frameCount;
2365 pInBuffer->raw = pInBuffer->mBuffer;
2366 memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * mFrameSize);
2367 mBufferQueue.add(pInBuffer);
2368 ALOGV("%s(%d): thread %d adding overflow buffer %zu", __func__, mId,
2369 (int)mThreadIoHandle, mBufferQueue.size());
2370 // audio data is consumed (stored locally); set frameCount to 0.
2371 inBuffer.frameCount = 0;
2372 } else {
2373 ALOGW("%s(%d): thread %d no more overflow buffers",
2374 __func__, mId, (int)mThreadIoHandle);
2375 // TODO: return error for this.
2376 }
2377}
2378
Andy Hung3ff4b552023-06-26 19:20:57 -07002379void OutputTrack::copyMetadataTo(MetadataInserter& backInserter) const
Kevin Rocard12381092018-04-11 09:19:59 -07002380{
Andy Hung87e82412023-08-29 14:26:09 -07002381 audio_utils::lock_guard lock(trackMetadataMutex());
Kevin Rocard12381092018-04-11 09:19:59 -07002382 backInserter = std::copy(mTrackMetadatas.begin(), mTrackMetadatas.end(), backInserter);
2383}
2384
Andy Hung3ff4b552023-06-26 19:20:57 -07002385void OutputTrack::setMetadatas(const SourceMetadatas& metadatas) {
Kevin Rocard12381092018-04-11 09:19:59 -07002386 {
Andy Hung87e82412023-08-29 14:26:09 -07002387 audio_utils::lock_guard lock(trackMetadataMutex());
Kevin Rocard12381092018-04-11 09:19:59 -07002388 mTrackMetadatas = metadatas;
2389 }
2390 // No need to adjust metadata track volumes as OutputTrack volumes are always 0dBFS.
2391 setMetadataHasChanged();
2392}
2393
Andy Hung3ff4b552023-06-26 19:20:57 -07002394status_t OutputTrack::obtainBuffer(
Eric Laurent81784c32012-11-19 14:55:58 -08002395 AudioBufferProvider::Buffer* buffer, uint32_t waitTimeMs)
2396{
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002397 ClientProxy::Buffer buf;
2398 buf.mFrameCount = buffer->frameCount;
2399 struct timespec timeout;
2400 timeout.tv_sec = waitTimeMs / 1000;
2401 timeout.tv_nsec = (int) (waitTimeMs % 1000) * 1000000;
2402 status_t status = mClientProxy->obtainBuffer(&buf, &timeout);
2403 buffer->frameCount = buf.mFrameCount;
2404 buffer->raw = buf.mRaw;
2405 return status;
Eric Laurent81784c32012-11-19 14:55:58 -08002406}
2407
Andy Hung3ff4b552023-06-26 19:20:57 -07002408void OutputTrack::clearBufferQueue()
Eric Laurent81784c32012-11-19 14:55:58 -08002409{
2410 size_t size = mBufferQueue.size();
2411
2412 for (size_t i = 0; i < size; i++) {
2413 Buffer *pBuffer = mBufferQueue.itemAt(i);
Andy Hungc25b84a2015-01-14 19:04:10 -08002414 free(pBuffer->mBuffer);
Eric Laurent81784c32012-11-19 14:55:58 -08002415 delete pBuffer;
2416 }
2417 mBufferQueue.clear();
2418}
2419
Andy Hung3ff4b552023-06-26 19:20:57 -07002420void OutputTrack::restartIfDisabled()
Eric Laurent4d231dc2016-03-11 18:38:23 -08002421{
2422 int32_t flags = android_atomic_and(~CBLK_DISABLED, &mCblk->mFlags);
2423 if (mActive && (flags & CBLK_DISABLED)) {
2424 start();
2425 }
2426}
Eric Laurent81784c32012-11-19 14:55:58 -08002427
Andy Hung9d84af52018-09-12 18:03:44 -07002428// ----------------------------------------------------------------------------
2429#undef LOG_TAG
2430#define LOG_TAG "AF::PatchTrack"
2431
Andy Hung3ff4b552023-06-26 19:20:57 -07002432/* static */
2433sp<IAfPatchTrack> IAfPatchTrack::create(
Andy Hung44f27182023-07-06 20:56:16 -07002434 IAfPlaybackThread* playbackThread,
Andy Hung3ff4b552023-06-26 19:20:57 -07002435 audio_stream_type_t streamType,
2436 uint32_t sampleRate,
2437 audio_channel_mask_t channelMask,
2438 audio_format_t format,
2439 size_t frameCount,
2440 void* buffer,
2441 size_t bufferSize,
2442 audio_output_flags_t flags,
2443 const Timeout& timeout,
2444 size_t frameCountToBeReady /** Default behaviour is to start
2445 * as soon as possible to have
2446 * the lowest possible latency
2447 * even if it might glitch. */)
2448{
2449 return sp<PatchTrack>::make(
Andy Hung44f27182023-07-06 20:56:16 -07002450 playbackThread,
Andy Hung3ff4b552023-06-26 19:20:57 -07002451 streamType,
2452 sampleRate,
2453 channelMask,
2454 format,
2455 frameCount,
2456 buffer,
2457 bufferSize,
2458 flags,
2459 timeout,
2460 frameCountToBeReady);
2461}
2462
Andy Hung44f27182023-07-06 20:56:16 -07002463PatchTrack::PatchTrack(IAfPlaybackThread* playbackThread,
Eric Laurent3bcf8592015-04-03 12:13:24 -07002464 audio_stream_type_t streamType,
Eric Laurent83b88082014-06-20 18:31:16 -07002465 uint32_t sampleRate,
2466 audio_channel_mask_t channelMask,
2467 audio_format_t format,
2468 size_t frameCount,
2469 void *buffer,
Andy Hung8fe68032017-06-05 16:17:51 -07002470 size_t bufferSize,
Kevin Rocard45986c72018-12-18 18:22:59 -08002471 audio_output_flags_t flags,
Kevin Rocard01c7d9e2019-09-18 11:24:52 +01002472 const Timeout& timeout,
2473 size_t frameCountToBeReady)
Eric Laurent3bcf8592015-04-03 12:13:24 -07002474 : Track(playbackThread, NULL, streamType,
Kevin Rocard1f564ac2018-03-29 13:53:10 -07002475 audio_attributes_t{} /* currently unused for patch track */,
Eric Laurent223fd5c2014-11-11 13:43:36 -08002476 sampleRate, format, channelMask, frameCount,
Andy Hung8fe68032017-06-05 16:17:51 -07002477 buffer, bufferSize, nullptr /* sharedBuffer */,
Svet Ganov33761132021-05-13 22:51:08 +00002478 AUDIO_SESSION_NONE, getpid(), audioServerAttributionSource(getpid()), flags,
Philip P. Moltmannbda45752020-07-17 16:41:18 -07002479 TYPE_PATCH, AUDIO_PORT_HANDLE_NONE, frameCountToBeReady),
gaoxiupei8e3a5682023-07-07 20:30:23 +08002480 PatchTrackBase(mCblk ? new ClientProxy(mCblk, mBuffer, frameCount, mFrameSize, true, true)
2481 : nullptr,
Andy Hung837229a2023-07-14 16:57:01 -07002482 playbackThread, timeout)
Eric Laurent83b88082014-06-20 18:31:16 -07002483{
Andy Hung9d84af52018-09-12 18:03:44 -07002484 ALOGV("%s(%d): sampleRate %d mPeerTimeout %d.%03d sec",
2485 __func__, mId, sampleRate,
Eric Laurent83b88082014-06-20 18:31:16 -07002486 (int)mPeerTimeout.tv_sec,
2487 (int)(mPeerTimeout.tv_nsec / 1000000));
2488}
2489
Andy Hung3ff4b552023-06-26 19:20:57 -07002490PatchTrack::~PatchTrack()
Eric Laurent83b88082014-06-20 18:31:16 -07002491{
Andy Hungabfab202019-03-07 19:45:54 -08002492 ALOGV("%s(%d)", __func__, mId);
Eric Laurent83b88082014-06-20 18:31:16 -07002493}
2494
Andy Hung3ff4b552023-06-26 19:20:57 -07002495size_t PatchTrack::framesReady() const
Mikhail Naganovcaf59942019-09-25 14:05:29 -07002496{
2497 if (mPeerProxy && mPeerProxy->producesBufferOnDemand()) {
2498 return std::numeric_limits<size_t>::max();
2499 } else {
2500 return Track::framesReady();
2501 }
2502}
2503
Andy Hung3ff4b552023-06-26 19:20:57 -07002504status_t PatchTrack::start(AudioSystem::sync_event_t event,
Kevin Rocard5f2136e2018-05-11 22:03:00 -07002505 audio_session_t triggerSession)
Eric Laurent4d231dc2016-03-11 18:38:23 -08002506{
2507 status_t status = Track::start(event, triggerSession);
2508 if (status != NO_ERROR) {
2509 return status;
2510 }
2511 android_atomic_and(~CBLK_DISABLED, &mCblk->mFlags);
2512 return status;
2513}
2514
Eric Laurent83b88082014-06-20 18:31:16 -07002515// AudioBufferProvider interface
Andy Hung3ff4b552023-06-26 19:20:57 -07002516status_t PatchTrack::getNextBuffer(
Glenn Kastend79072e2016-01-06 08:41:20 -08002517 AudioBufferProvider::Buffer* buffer)
Eric Laurent83b88082014-06-20 18:31:16 -07002518{
Andy Hung9d84af52018-09-12 18:03:44 -07002519 ALOG_ASSERT(mPeerProxy != 0, "%s(%d): called without peer proxy", __func__, mId);
Eric Laurent83b88082014-06-20 18:31:16 -07002520 Proxy::Buffer buf;
2521 buf.mFrameCount = buffer->frameCount;
Mikhail Naganov938be412019-09-04 11:38:47 -07002522 if (ATRACE_ENABLED()) {
2523 std::string traceName("PTnReq");
2524 traceName += std::to_string(id());
2525 ATRACE_INT(traceName.c_str(), buf.mFrameCount);
2526 }
Eric Laurent83b88082014-06-20 18:31:16 -07002527 status_t status = mPeerProxy->obtainBuffer(&buf, &mPeerTimeout);
Andy Hung9d84af52018-09-12 18:03:44 -07002528 ALOGV_IF(status != NO_ERROR, "%s(%d): getNextBuffer status %d", __func__, mId, status);
Eric Laurentc2730ba2014-07-20 15:47:07 -07002529 buffer->frameCount = buf.mFrameCount;
Mikhail Naganov938be412019-09-04 11:38:47 -07002530 if (ATRACE_ENABLED()) {
2531 std::string traceName("PTnObt");
2532 traceName += std::to_string(id());
2533 ATRACE_INT(traceName.c_str(), buf.mFrameCount);
2534 }
Eric Laurent83b88082014-06-20 18:31:16 -07002535 if (buf.mFrameCount == 0) {
2536 return WOULD_BLOCK;
2537 }
Glenn Kastend79072e2016-01-06 08:41:20 -08002538 status = Track::getNextBuffer(buffer);
Eric Laurent83b88082014-06-20 18:31:16 -07002539 return status;
2540}
2541
Andy Hung3ff4b552023-06-26 19:20:57 -07002542void PatchTrack::releaseBuffer(AudioBufferProvider::Buffer* buffer)
Eric Laurent83b88082014-06-20 18:31:16 -07002543{
Andy Hung9d84af52018-09-12 18:03:44 -07002544 ALOG_ASSERT(mPeerProxy != 0, "%s(%d): called without peer proxy", __func__, mId);
Eric Laurent83b88082014-06-20 18:31:16 -07002545 Proxy::Buffer buf;
2546 buf.mFrameCount = buffer->frameCount;
2547 buf.mRaw = buffer->raw;
2548 mPeerProxy->releaseBuffer(&buf);
Andy Hung71ba4b32022-10-06 12:09:49 -07002549 TrackBase::releaseBuffer(buffer); // Note: this is the base class.
Eric Laurent83b88082014-06-20 18:31:16 -07002550}
2551
Andy Hung3ff4b552023-06-26 19:20:57 -07002552status_t PatchTrack::obtainBuffer(Proxy::Buffer* buffer,
Eric Laurent83b88082014-06-20 18:31:16 -07002553 const struct timespec *timeOut)
2554{
Eric Laurent4d231dc2016-03-11 18:38:23 -08002555 status_t status = NO_ERROR;
2556 static const int32_t kMaxTries = 5;
2557 int32_t tryCounter = kMaxTries;
Andy Hungf62e1a22018-05-08 18:32:11 -07002558 const size_t originalFrameCount = buffer->mFrameCount;
Eric Laurent4d231dc2016-03-11 18:38:23 -08002559 do {
2560 if (status == NOT_ENOUGH_DATA) {
2561 restartIfDisabled();
Andy Hungf62e1a22018-05-08 18:32:11 -07002562 buffer->mFrameCount = originalFrameCount; // cleared on error, must be restored.
Eric Laurent4d231dc2016-03-11 18:38:23 -08002563 }
2564 status = mProxy->obtainBuffer(buffer, timeOut);
2565 } while ((status == NOT_ENOUGH_DATA) && (tryCounter-- > 0));
2566 return status;
Eric Laurent83b88082014-06-20 18:31:16 -07002567}
2568
Andy Hung3ff4b552023-06-26 19:20:57 -07002569void PatchTrack::releaseBuffer(Proxy::Buffer* buffer)
Eric Laurent83b88082014-06-20 18:31:16 -07002570{
2571 mProxy->releaseBuffer(buffer);
Eric Laurent4d231dc2016-03-11 18:38:23 -08002572 restartIfDisabled();
naoki miyazuf37f9982019-11-28 11:18:18 +09002573
2574 // Check if the PatchTrack has enough data to write once in releaseBuffer().
2575 // If not, prevent an underrun from occurring by moving the track into FS_FILLING;
2576 // this logic avoids glitches when suspending A2DP with AudioPlaybackCapture.
2577 // TODO: perhaps underrun avoidance could be a track property checked in isReady() instead.
Andy Hung3ff4b552023-06-26 19:20:57 -07002578 if (mFillingStatus == FS_ACTIVE
naoki miyazuf37f9982019-11-28 11:18:18 +09002579 && audio_is_linear_pcm(mFormat)
2580 && !isOffloadedOrDirect()) {
Andy Hung44f27182023-07-06 20:56:16 -07002581 if (const sp<IAfThreadBase> thread = mThread.promote();
naoki miyazuf37f9982019-11-28 11:18:18 +09002582 thread != 0) {
Andy Hung44f27182023-07-06 20:56:16 -07002583 auto* const playbackThread = thread->asIAfPlaybackThread().get();
naoki miyazuf37f9982019-11-28 11:18:18 +09002584 const size_t frameCount = playbackThread->frameCount() * sampleRate()
2585 / playbackThread->sampleRate();
2586 if (framesReady() < frameCount) {
2587 ALOGD("%s(%d) Not enough data, wait for buffer to fill", __func__, mId);
Andy Hung3ff4b552023-06-26 19:20:57 -07002588 mFillingStatus = FS_FILLING;
naoki miyazuf37f9982019-11-28 11:18:18 +09002589 }
2590 }
2591 }
Eric Laurent4d231dc2016-03-11 18:38:23 -08002592}
2593
Andy Hung3ff4b552023-06-26 19:20:57 -07002594void PatchTrack::restartIfDisabled()
Eric Laurent4d231dc2016-03-11 18:38:23 -08002595{
Eric Laurent83b88082014-06-20 18:31:16 -07002596 if (android_atomic_and(~CBLK_DISABLED, &mCblk->mFlags) & CBLK_DISABLED) {
Andy Hung9d84af52018-09-12 18:03:44 -07002597 ALOGW("%s(%d): disabled due to previous underrun, restarting", __func__, mId);
Eric Laurent83b88082014-06-20 18:31:16 -07002598 start();
2599 }
Eric Laurent83b88082014-06-20 18:31:16 -07002600}
2601
Eric Laurent81784c32012-11-19 14:55:58 -08002602// ----------------------------------------------------------------------------
2603// Record
2604// ----------------------------------------------------------------------------
Jean-Michel Trividdf87ef2019-08-20 15:42:04 -07002605
2606
Andy Hung9d84af52018-09-12 18:03:44 -07002607#undef LOG_TAG
2608#define LOG_TAG "AF::RecordHandle"
Eric Laurent81784c32012-11-19 14:55:58 -08002609
Andy Hungaaa18282023-06-23 19:27:19 -07002610class RecordHandle : public android::media::BnAudioRecord {
2611public:
Andy Hung02a6c4e2023-06-23 19:27:19 -07002612 explicit RecordHandle(const sp<IAfRecordTrack>& recordTrack);
Andy Hungaaa18282023-06-23 19:27:19 -07002613 ~RecordHandle() override;
2614 binder::Status start(int /*AudioSystem::sync_event_t*/ event,
2615 int /*audio_session_t*/ triggerSession) final;
2616 binder::Status stop() final;
2617 binder::Status getActiveMicrophones(
2618 std::vector<media::MicrophoneInfoFw>* activeMicrophones) final;
2619 binder::Status setPreferredMicrophoneDirection(
2620 int /*audio_microphone_direction_t*/ direction) final;
2621 binder::Status setPreferredMicrophoneFieldDimension(float zoom) final;
2622 binder::Status shareAudioHistory(
2623 const std::string& sharedAudioPackageName, int64_t sharedAudioStartMs) final;
2624
2625private:
Andy Hung02a6c4e2023-06-23 19:27:19 -07002626 const sp<IAfRecordTrack> mRecordTrack;
Andy Hungaaa18282023-06-23 19:27:19 -07002627
2628 // for use from destructor
2629 void stop_nonvirtual();
2630};
2631
2632/* static */
Andy Hung02a6c4e2023-06-23 19:27:19 -07002633sp<media::IAudioRecord> IAfRecordTrack::createIAudioRecordAdapter(
2634 const sp<IAfRecordTrack>& recordTrack) {
Andy Hungaaa18282023-06-23 19:27:19 -07002635 return sp<RecordHandle>::make(recordTrack);
2636}
2637
2638RecordHandle::RecordHandle(
Andy Hung02a6c4e2023-06-23 19:27:19 -07002639 const sp<IAfRecordTrack>& recordTrack)
Eric Laurent81784c32012-11-19 14:55:58 -08002640 : BnAudioRecord(),
2641 mRecordTrack(recordTrack)
2642{
Andy Hung225aef62022-12-06 16:33:20 -08002643 setMinSchedulerPolicy(SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
Eric Laurent81784c32012-11-19 14:55:58 -08002644}
2645
Andy Hungaaa18282023-06-23 19:27:19 -07002646RecordHandle::~RecordHandle() {
Eric Laurent81784c32012-11-19 14:55:58 -08002647 stop_nonvirtual();
2648 mRecordTrack->destroy();
2649}
2650
Andy Hungaaa18282023-06-23 19:27:19 -07002651binder::Status RecordHandle::start(int /*AudioSystem::sync_event_t*/ event,
Ivan Lozanoff6900d2017-08-01 15:47:38 -07002652 int /*audio_session_t*/ triggerSession) {
Andy Hung9d84af52018-09-12 18:03:44 -07002653 ALOGV("%s()", __func__);
Andy Hung1131b6e2020-12-08 20:47:45 -08002654 return binderStatusFromStatusT(
Ivan Lozanoff6900d2017-08-01 15:47:38 -07002655 mRecordTrack->start((AudioSystem::sync_event_t)event, (audio_session_t) triggerSession));
Eric Laurent81784c32012-11-19 14:55:58 -08002656}
2657
Andy Hungaaa18282023-06-23 19:27:19 -07002658binder::Status RecordHandle::stop() {
Eric Laurent81784c32012-11-19 14:55:58 -08002659 stop_nonvirtual();
Ivan Lozanoff6900d2017-08-01 15:47:38 -07002660 return binder::Status::ok();
Eric Laurent81784c32012-11-19 14:55:58 -08002661}
2662
Andy Hungaaa18282023-06-23 19:27:19 -07002663void RecordHandle::stop_nonvirtual() {
Andy Hung9d84af52018-09-12 18:03:44 -07002664 ALOGV("%s()", __func__);
Eric Laurent81784c32012-11-19 14:55:58 -08002665 mRecordTrack->stop();
2666}
2667
Andy Hungaaa18282023-06-23 19:27:19 -07002668binder::Status RecordHandle::getActiveMicrophones(
Mikhail Naganov2a6a3012023-02-13 11:45:03 -08002669 std::vector<media::MicrophoneInfoFw>* activeMicrophones) {
Andy Hung9d84af52018-09-12 18:03:44 -07002670 ALOGV("%s()", __func__);
Mikhail Naganov2a6a3012023-02-13 11:45:03 -08002671 return binderStatusFromStatusT(mRecordTrack->getActiveMicrophones(activeMicrophones));
jiabin653cc0a2018-01-17 17:54:10 -08002672}
2673
Andy Hungaaa18282023-06-23 19:27:19 -07002674binder::Status RecordHandle::setPreferredMicrophoneDirection(
Paul McLean03a6e6a2018-12-04 10:54:13 -07002675 int /*audio_microphone_direction_t*/ direction) {
2676 ALOGV("%s()", __func__);
Andy Hung1131b6e2020-12-08 20:47:45 -08002677 return binderStatusFromStatusT(mRecordTrack->setPreferredMicrophoneDirection(
Paul McLean03a6e6a2018-12-04 10:54:13 -07002678 static_cast<audio_microphone_direction_t>(direction)));
2679}
2680
Andy Hungaaa18282023-06-23 19:27:19 -07002681binder::Status RecordHandle::setPreferredMicrophoneFieldDimension(float zoom) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07002682 ALOGV("%s()", __func__);
Andy Hung1131b6e2020-12-08 20:47:45 -08002683 return binderStatusFromStatusT(mRecordTrack->setPreferredMicrophoneFieldDimension(zoom));
Paul McLean03a6e6a2018-12-04 10:54:13 -07002684}
2685
Andy Hungaaa18282023-06-23 19:27:19 -07002686binder::Status RecordHandle::shareAudioHistory(
Eric Laurentec376dc2021-04-08 20:41:22 +02002687 const std::string& sharedAudioPackageName, int64_t sharedAudioStartMs) {
2688 return binderStatusFromStatusT(
2689 mRecordTrack->shareAudioHistory(sharedAudioPackageName, sharedAudioStartMs));
2690}
2691
Eric Laurent81784c32012-11-19 14:55:58 -08002692// ----------------------------------------------------------------------------
Andy Hung9d84af52018-09-12 18:03:44 -07002693#undef LOG_TAG
2694#define LOG_TAG "AF::RecordTrack"
Eric Laurent81784c32012-11-19 14:55:58 -08002695
Andy Hung3ff4b552023-06-26 19:20:57 -07002696
Andy Hung56126702023-07-14 11:00:08 -07002697/* static */
Andy Hung44f27182023-07-06 20:56:16 -07002698sp<IAfRecordTrack> IAfRecordTrack::create(IAfRecordThread* thread,
Andy Hung3ff4b552023-06-26 19:20:57 -07002699 const sp<Client>& client,
2700 const audio_attributes_t& attr,
2701 uint32_t sampleRate,
2702 audio_format_t format,
2703 audio_channel_mask_t channelMask,
2704 size_t frameCount,
2705 void* buffer,
2706 size_t bufferSize,
2707 audio_session_t sessionId,
2708 pid_t creatorPid,
2709 const AttributionSourceState& attributionSource,
2710 audio_input_flags_t flags,
2711 track_type type,
2712 audio_port_handle_t portId,
2713 int32_t startFrames)
2714{
2715 return sp<RecordTrack>::make(
Andy Hung44f27182023-07-06 20:56:16 -07002716 thread,
Andy Hung3ff4b552023-06-26 19:20:57 -07002717 client,
2718 attr,
2719 sampleRate,
2720 format,
2721 channelMask,
2722 frameCount,
2723 buffer,
2724 bufferSize,
2725 sessionId,
2726 creatorPid,
2727 attributionSource,
2728 flags,
2729 type,
2730 portId,
2731 startFrames);
2732}
2733
Glenn Kasten05997e22014-03-13 15:08:33 -07002734// RecordTrack constructor must be called with AudioFlinger::mLock and ThreadBase::mLock held
Andy Hung3ff4b552023-06-26 19:20:57 -07002735RecordTrack::RecordTrack(
Andy Hung44f27182023-07-06 20:56:16 -07002736 IAfRecordThread* thread,
Eric Laurent81784c32012-11-19 14:55:58 -08002737 const sp<Client>& client,
Kevin Rocard1f564ac2018-03-29 13:53:10 -07002738 const audio_attributes_t& attr,
Eric Laurent81784c32012-11-19 14:55:58 -08002739 uint32_t sampleRate,
2740 audio_format_t format,
2741 audio_channel_mask_t channelMask,
2742 size_t frameCount,
Eric Laurent83b88082014-06-20 18:31:16 -07002743 void *buffer,
Andy Hung8fe68032017-06-05 16:17:51 -07002744 size_t bufferSize,
Glenn Kastend848eb42016-03-08 13:42:11 -08002745 audio_session_t sessionId,
Eric Laurent09f1ed22019-04-24 17:45:17 -07002746 pid_t creatorPid,
Svet Ganov33761132021-05-13 22:51:08 +00002747 const AttributionSourceState& attributionSource,
Eric Laurent05067782016-06-01 18:27:28 -07002748 audio_input_flags_t flags,
Eric Laurent20b9ef02016-12-05 11:03:16 -08002749 track_type type,
Eric Laurentec376dc2021-04-08 20:41:22 +02002750 audio_port_handle_t portId,
Eric Laurent2407ce32021-04-26 14:56:03 +02002751 int32_t startFrames)
Kevin Rocard1f564ac2018-03-29 13:53:10 -07002752 : TrackBase(thread, client, attr, sampleRate, format,
Eric Laurent09f1ed22019-04-24 17:45:17 -07002753 channelMask, frameCount, buffer, bufferSize, sessionId,
Philip P. Moltmannbda45752020-07-17 16:41:18 -07002754 creatorPid,
Svet Ganov33761132021-05-13 22:51:08 +00002755 VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid)),
Philip P. Moltmannbda45752020-07-17 16:41:18 -07002756 false /*isOut*/,
Eric Laurent83b88082014-06-20 18:31:16 -07002757 (type == TYPE_DEFAULT) ?
Eric Laurent05067782016-06-01 18:27:28 -07002758 ((flags & AUDIO_INPUT_FLAG_FAST) ? ALLOC_PIPE : ALLOC_CBLK) :
Eric Laurent83b88082014-06-20 18:31:16 -07002759 ((buffer == NULL) ? ALLOC_LOCAL : ALLOC_NONE),
Andy Hungb68f5eb2019-12-03 16:49:17 -08002760 type, portId,
2761 std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD) + std::to_string(portId)),
Andy Hung97a893e2015-03-29 01:03:07 -07002762 mOverflow(false),
Andy Hung4c6afaf2015-06-12 18:23:35 -07002763 mResamplerBufferProvider(NULL), // initialize in case of early constructor exit
Eric Laurent05067782016-06-01 18:27:28 -07002764 mRecordBufferConverter(NULL),
jiabin9378eb92018-05-02 15:26:35 -07002765 mFlags(flags),
Jean-Michel Trividdf87ef2019-08-20 15:42:04 -07002766 mSilenced(false),
Eric Laurent2407ce32021-04-26 14:56:03 +02002767 mStartFrames(startFrames)
Eric Laurent81784c32012-11-19 14:55:58 -08002768{
Glenn Kasten3ef14ef2014-03-13 15:08:51 -07002769 if (mCblk == NULL) {
2770 return;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002771 }
Glenn Kasten6dd62fb2013-12-05 16:35:58 -08002772
Mikhail Naganov7c6ae982018-06-14 12:33:38 -07002773 if (!isDirect()) {
2774 mRecordBufferConverter = new RecordBufferConverter(
Andy Hung44f27182023-07-06 20:56:16 -07002775 thread->channelMask(), thread->format(), thread->sampleRate(),
Mikhail Naganov7c6ae982018-06-14 12:33:38 -07002776 channelMask, format, sampleRate);
2777 // Check if the RecordBufferConverter construction was successful.
2778 // If not, don't continue with construction.
2779 //
2780 // NOTE: It would be extremely rare that the record track cannot be created
2781 // for the current device, but a pending or future device change would make
2782 // the record track configuration valid.
2783 if (mRecordBufferConverter->initCheck() != NO_ERROR) {
Andy Hung9d84af52018-09-12 18:03:44 -07002784 ALOGE("%s(%d): RecordTrack unable to create record buffer converter", __func__, mId);
Mikhail Naganov7c6ae982018-06-14 12:33:38 -07002785 return;
2786 }
Andy Hung97a893e2015-03-29 01:03:07 -07002787 }
2788
Andy Hung6ae58432016-02-16 18:32:24 -08002789 mServerProxy = new AudioRecordServerProxy(mCblk, mBuffer, frameCount,
Andy Hung3f0c9022016-01-15 17:49:46 -08002790 mFrameSize, !isExternalTrack());
Andy Hung3f0c9022016-01-15 17:49:46 -08002791
Andy Hung97a893e2015-03-29 01:03:07 -07002792 mResamplerBufferProvider = new ResamplerBufferProvider(this);
Glenn Kastenc263ca02014-06-04 20:31:46 -07002793
Eric Laurent05067782016-06-01 18:27:28 -07002794 if (flags & AUDIO_INPUT_FLAG_FAST) {
Andy Hung44f27182023-07-06 20:56:16 -07002795 ALOG_ASSERT(thread->fastTrackAvailable());
2796 thread->setFastTrackAvailable(false);
Andy Hung000adb52018-06-01 15:43:26 -07002797 } else {
2798 // TODO: only Normal Record has timestamps (Fast Record does not).
Andy Hung5d3d9562018-10-04 19:27:26 -07002799 mServerLatencySupported = checkServerLatencySupported(mFormat, flags);
Glenn Kastenc263ca02014-06-04 20:31:46 -07002800 }
Andy Hung8946a282018-04-19 20:04:56 -07002801#ifdef TEE_SINK
2802 mTee.setId(std::string("_") + std::to_string(mThreadIoHandle)
2803 + "_" + std::to_string(mId)
2804 + "_R");
2805#endif
Andy Hungb68f5eb2019-12-03 16:49:17 -08002806
2807 // Once this item is logged by the server, the client can add properties.
Andy Hung94235282021-03-24 15:50:14 -07002808 mTrackMetrics.logConstructor(creatorPid, uid(), id());
Eric Laurent81784c32012-11-19 14:55:58 -08002809}
2810
Andy Hung3ff4b552023-06-26 19:20:57 -07002811RecordTrack::~RecordTrack()
Eric Laurent81784c32012-11-19 14:55:58 -08002812{
Andy Hung9d84af52018-09-12 18:03:44 -07002813 ALOGV("%s()", __func__);
Andy Hung97a893e2015-03-29 01:03:07 -07002814 delete mRecordBufferConverter;
Glenn Kasten6dd62fb2013-12-05 16:35:58 -08002815 delete mResamplerBufferProvider;
Eric Laurent81784c32012-11-19 14:55:58 -08002816}
2817
Andy Hung3ff4b552023-06-26 19:20:57 -07002818status_t RecordTrack::initCheck() const
Andy Hung97a893e2015-03-29 01:03:07 -07002819{
2820 status_t status = TrackBase::initCheck();
2821 if (status == NO_ERROR && mServerProxy == 0) {
2822 status = BAD_VALUE;
2823 }
2824 return status;
2825}
2826
Eric Laurent81784c32012-11-19 14:55:58 -08002827// AudioBufferProvider interface
Andy Hung3ff4b552023-06-26 19:20:57 -07002828status_t RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer)
Eric Laurent81784c32012-11-19 14:55:58 -08002829{
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002830 ServerProxy::Buffer buf;
2831 buf.mFrameCount = buffer->frameCount;
2832 status_t status = mServerProxy->obtainBuffer(&buf);
2833 buffer->frameCount = buf.mFrameCount;
2834 buffer->raw = buf.mRaw;
2835 if (buf.mFrameCount == 0) {
2836 // FIXME also wake futex so that overrun is noticed more quickly
Glenn Kasten96f60d82013-07-12 10:21:18 -07002837 (void) android_atomic_or(CBLK_OVERRUN, &mCblk->mFlags);
Eric Laurent81784c32012-11-19 14:55:58 -08002838 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002839 return status;
Eric Laurent81784c32012-11-19 14:55:58 -08002840}
2841
Andy Hung3ff4b552023-06-26 19:20:57 -07002842status_t RecordTrack::start(AudioSystem::sync_event_t event,
Glenn Kastend848eb42016-03-08 13:42:11 -08002843 audio_session_t triggerSession)
Eric Laurent81784c32012-11-19 14:55:58 -08002844{
Andy Hung44f27182023-07-06 20:56:16 -07002845 const sp<IAfThreadBase> thread = mThread.promote();
Eric Laurent81784c32012-11-19 14:55:58 -08002846 if (thread != 0) {
Andy Hung44f27182023-07-06 20:56:16 -07002847 auto* const recordThread = thread->asIAfRecordThread().get();
Eric Laurent81784c32012-11-19 14:55:58 -08002848 return recordThread->start(this, event, triggerSession);
2849 } else {
Eric Laurentd52a28c2020-08-21 17:10:39 -07002850 ALOGW("%s track %d: thread was destroyed", __func__, portId());
2851 return DEAD_OBJECT;
Eric Laurent81784c32012-11-19 14:55:58 -08002852 }
2853}
2854
Andy Hung3ff4b552023-06-26 19:20:57 -07002855void RecordTrack::stop()
Eric Laurent81784c32012-11-19 14:55:58 -08002856{
Andy Hung44f27182023-07-06 20:56:16 -07002857 const sp<IAfThreadBase> thread = mThread.promote();
Eric Laurent81784c32012-11-19 14:55:58 -08002858 if (thread != 0) {
Andy Hung44f27182023-07-06 20:56:16 -07002859 auto* const recordThread = thread->asIAfRecordThread().get();
Eric Laurent83b88082014-06-20 18:31:16 -07002860 if (recordThread->stop(this) && isExternalTrack()) {
Eric Laurentfee19762018-01-29 18:44:13 -08002861 AudioSystem::stopInput(mPortId);
Eric Laurent81784c32012-11-19 14:55:58 -08002862 }
2863 }
2864}
2865
Andy Hung3ff4b552023-06-26 19:20:57 -07002866void RecordTrack::destroy()
Eric Laurent81784c32012-11-19 14:55:58 -08002867{
Andy Hung3ff4b552023-06-26 19:20:57 -07002868 // see comments at Track::destroy()
Eric Laurent81784c32012-11-19 14:55:58 -08002869 sp<RecordTrack> keep(this);
2870 {
Andy Hungce685402018-10-05 17:23:27 -07002871 track_state priorState = mState;
Andy Hung44f27182023-07-06 20:56:16 -07002872 const sp<IAfThreadBase> thread = mThread.promote();
Eric Laurent81784c32012-11-19 14:55:58 -08002873 if (thread != 0) {
Andy Hung87e82412023-08-29 14:26:09 -07002874 audio_utils::lock_guard _l(thread->mutex());
Andy Hung44f27182023-07-06 20:56:16 -07002875 auto* const recordThread = thread->asIAfRecordThread().get();
Andy Hungce685402018-10-05 17:23:27 -07002876 priorState = mState;
Eric Laurentec376dc2021-04-08 20:41:22 +02002877 if (!mSharedAudioPackageName.empty()) {
Eric Laurent92d0a322021-07-16 15:32:33 +02002878 recordThread->resetAudioHistory_l();
Eric Laurentec376dc2021-04-08 20:41:22 +02002879 }
Andy Hungce685402018-10-05 17:23:27 -07002880 recordThread->destroyTrack_l(this); // move mState to STOPPED, terminate
2881 }
2882 // APM portid/client management done outside of lock.
2883 // NOTE: if thread doesn't exist, the input descriptor probably doesn't either.
2884 if (isExternalTrack()) {
2885 switch (priorState) {
2886 case ACTIVE: // invalidated while still active
2887 case STARTING_2: // invalidated/start-aborted after startInput successfully called
2888 case PAUSING: // invalidated while in the middle of stop() pausing (still active)
2889 AudioSystem::stopInput(mPortId);
2890 break;
2891
2892 case STARTING_1: // invalidated/start-aborted and startInput not successful
2893 case PAUSED: // OK, not active
2894 case IDLE: // OK, not active
2895 break;
2896
2897 case STOPPED: // unexpected (destroyed)
2898 default:
2899 LOG_ALWAYS_FATAL("%s(%d): invalid prior state: %d", __func__, mId, priorState);
2900 }
2901 AudioSystem::releaseInput(mPortId);
Eric Laurent81784c32012-11-19 14:55:58 -08002902 }
2903 }
2904}
2905
Andy Hung3ff4b552023-06-26 19:20:57 -07002906void RecordTrack::invalidate()
Eric Laurent9a54bc22013-09-09 09:08:44 -07002907{
Eric Laurent6acd1d42017-01-04 14:23:29 -08002908 TrackBase::invalidate();
Eric Laurent9a54bc22013-09-09 09:08:44 -07002909 // FIXME should use proxy, and needs work
2910 audio_track_cblk_t* cblk = mCblk;
2911 android_atomic_or(CBLK_INVALID, &cblk->mFlags);
2912 android_atomic_release_store(0x40000000, &cblk->mFutex);
2913 // client is not in server, so FUTEX_WAKE is needed instead of FUTEX_WAKE_PRIVATE
Elliott Hughesee499292014-05-21 17:55:51 -07002914 (void) syscall(__NR_futex, &cblk->mFutex, FUTEX_WAKE, INT_MAX);
Eric Laurent9a54bc22013-09-09 09:08:44 -07002915}
2916
Eric Laurent81784c32012-11-19 14:55:58 -08002917
Andy Hung3ff4b552023-06-26 19:20:57 -07002918void RecordTrack::appendDumpHeader(String8& result) const
Eric Laurent81784c32012-11-19 14:55:58 -08002919{
Eric Laurent973db022018-11-20 14:54:31 -08002920 result.appendFormat("Active Id Client Session Port Id S Flags "
Andy Hung9d84af52018-09-12 18:03:44 -07002921 " Format Chn mask SRate Source "
Kevin Rocard5f2136e2018-05-11 22:03:00 -07002922 " Server FrmCnt FrmRdy Sil%s\n",
2923 isServerLatencySupported() ? " Latency" : "");
Eric Laurent81784c32012-11-19 14:55:58 -08002924}
2925
Andy Hung3ff4b552023-06-26 19:20:57 -07002926void RecordTrack::appendDump(String8& result, bool active) const
Eric Laurent81784c32012-11-19 14:55:58 -08002927{
Eric Laurent973db022018-11-20 14:54:31 -08002928 result.appendFormat("%c%5s %6d %6u %7u %7u %2s 0x%03X "
Kevin Rocard5f2136e2018-05-11 22:03:00 -07002929 "%08X %08X %6u %6X "
Andy Hung000adb52018-06-01 15:43:26 -07002930 "%08X %6zu %6zu %3c",
Andy Hung2c6c3bb2017-06-16 14:01:45 -07002931 isFastTrack() ? 'F' : ' ',
Marco Nelissenb2208842014-02-07 14:00:50 -08002932 active ? "yes" : "no",
Andy Hung9d84af52018-09-12 18:03:44 -07002933 mId,
Andy Hung4ef19fa2018-05-15 19:35:29 -07002934 (mClient == 0) ? getpid() : mClient->pid(),
Andy Hung2c6c3bb2017-06-16 14:01:45 -07002935 mSessionId,
Eric Laurent973db022018-11-20 14:54:31 -08002936 mPortId,
Andy Hunge2e830f2019-12-03 12:54:46 -08002937 getTrackStateAsCodedString(),
Andy Hung2c6c3bb2017-06-16 14:01:45 -07002938 mCblk->mFlags,
2939
Eric Laurent81784c32012-11-19 14:55:58 -08002940 mFormat,
2941 mChannelMask,
Andy Hung2c6c3bb2017-06-16 14:01:45 -07002942 mSampleRate,
Kevin Rocard5f2136e2018-05-11 22:03:00 -07002943 mAttr.source,
Glenn Kasten6dd62fb2013-12-05 16:35:58 -08002944
Andy Hung2c6c3bb2017-06-16 14:01:45 -07002945 mCblk->mServer,
Jean-Michel Trivi7d665ab2018-04-11 17:26:51 -07002946 mFrameCount,
Andy Hung000adb52018-06-01 15:43:26 -07002947 mServerProxy->framesReadySafe(),
Jean-Michel Trivi7d665ab2018-04-11 17:26:51 -07002948 isSilenced() ? 's' : 'n'
Andy Hung2c6c3bb2017-06-16 14:01:45 -07002949 );
Andy Hung000adb52018-06-01 15:43:26 -07002950 if (isServerLatencySupported()) {
2951 double latencyMs;
2952 bool fromTrack;
2953 if (getTrackLatencyMs(&latencyMs, &fromTrack) == OK) {
2954 // Show latency in msec, followed by 't' if from track timestamp (the most accurate)
2955 // or 'k' if estimated from kernel (usually for debugging).
2956 result.appendFormat(" %7.2lf %c", latencyMs, fromTrack ? 't' : 'k');
2957 } else {
2958 result.appendFormat("%10s", mCblk->mServer != 0 ? "unavail" : "new");
2959 }
2960 }
2961 result.append("\n");
Eric Laurent81784c32012-11-19 14:55:58 -08002962}
2963
Andy Hung93bb5732023-05-04 21:16:34 -07002964// This is invoked by SyncEvent callback.
Andy Hung3ff4b552023-06-26 19:20:57 -07002965void RecordTrack::handleSyncStartEvent(
Andy Hung068e08e2023-05-15 19:02:55 -07002966 const sp<audioflinger::SyncEvent>& event)
Glenn Kasten25f4aa82014-02-07 10:50:43 -08002967{
Andy Hung93bb5732023-05-04 21:16:34 -07002968 size_t framesToDrop = 0;
Andy Hung44f27182023-07-06 20:56:16 -07002969 const sp<IAfThreadBase> threadBase = mThread.promote();
Andy Hung93bb5732023-05-04 21:16:34 -07002970 if (threadBase != 0) {
2971 // TODO: use actual buffer filling status instead of 2 buffers when info is available
2972 // from audio HAL
Andy Hung44f27182023-07-06 20:56:16 -07002973 framesToDrop = threadBase->frameCount() * 2;
Glenn Kasten25f4aa82014-02-07 10:50:43 -08002974 }
Andy Hung93bb5732023-05-04 21:16:34 -07002975
2976 mSynchronizedRecordState.onPlaybackFinished(event, framesToDrop);
Glenn Kasten25f4aa82014-02-07 10:50:43 -08002977}
2978
Andy Hung3ff4b552023-06-26 19:20:57 -07002979void RecordTrack::clearSyncStartEvent()
Glenn Kasten25f4aa82014-02-07 10:50:43 -08002980{
Andy Hung93bb5732023-05-04 21:16:34 -07002981 mSynchronizedRecordState.clear();
Glenn Kasten25f4aa82014-02-07 10:50:43 -08002982}
2983
Andy Hung3ff4b552023-06-26 19:20:57 -07002984void RecordTrack::updateTrackFrameInfo(
Andy Hung3f0c9022016-01-15 17:49:46 -08002985 int64_t trackFramesReleased, int64_t sourceFramesRead,
2986 uint32_t halSampleRate, const ExtendedTimestamp &timestamp)
2987{
Andy Hung30282562018-08-08 18:27:03 -07002988 // Make the kernel frametime available.
2989 const FrameTime ft{
2990 timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL],
2991 timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL]};
2992 // ALOGD("FrameTime: %lld %lld", (long long)ft.frames, (long long)ft.timeNs);
2993 mKernelFrameTime.store(ft);
2994 if (!audio_is_linear_pcm(mFormat)) {
Atneya Nair497fff12022-01-18 16:23:04 -05002995 // Stream is direct, return provided timestamp with no conversion
2996 mServerProxy->setTimestamp(timestamp);
Andy Hung30282562018-08-08 18:27:03 -07002997 return;
2998 }
2999
Andy Hung3f0c9022016-01-15 17:49:46 -08003000 ExtendedTimestamp local = timestamp;
3001
3002 // Convert HAL frames to server-side track frames at track sample rate.
3003 // We use trackFramesReleased and sourceFramesRead as an anchor point.
3004 for (int i = ExtendedTimestamp::LOCATION_SERVER; i < ExtendedTimestamp::LOCATION_MAX; ++i) {
3005 if (local.mTimeNs[i] != 0) {
3006 const int64_t relativeServerFrames = local.mPosition[i] - sourceFramesRead;
3007 const int64_t relativeTrackFrames = relativeServerFrames
3008 * mSampleRate / halSampleRate; // TODO: potential computation overflow
3009 local.mPosition[i] = relativeTrackFrames + trackFramesReleased;
3010 }
3011 }
Andy Hung6ae58432016-02-16 18:32:24 -08003012 mServerProxy->setTimestamp(local);
Andy Hung000adb52018-06-01 15:43:26 -07003013
3014 // Compute latency info.
3015 const bool useTrackTimestamp = true; // use track unless debugging.
3016 const double latencyMs = - (useTrackTimestamp
3017 ? local.getOutputServerLatencyMs(sampleRate())
3018 : timestamp.getOutputServerLatencyMs(halSampleRate));
3019
3020 mServerLatencyFromTrack.store(useTrackTimestamp);
3021 mServerLatencyMs.store(latencyMs);
Andy Hung3f0c9022016-01-15 17:49:46 -08003022}
Eric Laurent83b88082014-06-20 18:31:16 -07003023
Andy Hung3ff4b552023-06-26 19:20:57 -07003024status_t RecordTrack::getActiveMicrophones(
Andy Hung02a6c4e2023-06-23 19:27:19 -07003025 std::vector<media::MicrophoneInfoFw>* activeMicrophones) const
jiabin653cc0a2018-01-17 17:54:10 -08003026{
Andy Hung44f27182023-07-06 20:56:16 -07003027 const sp<IAfThreadBase> thread = mThread.promote();
jiabin653cc0a2018-01-17 17:54:10 -08003028 if (thread != 0) {
Andy Hung44f27182023-07-06 20:56:16 -07003029 auto* const recordThread = thread->asIAfRecordThread().get();
jiabin653cc0a2018-01-17 17:54:10 -08003030 return recordThread->getActiveMicrophones(activeMicrophones);
3031 } else {
3032 return BAD_VALUE;
3033 }
3034}
3035
Andy Hung3ff4b552023-06-26 19:20:57 -07003036status_t RecordTrack::setPreferredMicrophoneDirection(
Paul McLean03a6e6a2018-12-04 10:54:13 -07003037 audio_microphone_direction_t direction) {
Andy Hung44f27182023-07-06 20:56:16 -07003038 const sp<IAfThreadBase> thread = mThread.promote();
Paul McLean03a6e6a2018-12-04 10:54:13 -07003039 if (thread != 0) {
Andy Hung44f27182023-07-06 20:56:16 -07003040 auto* const recordThread = thread->asIAfRecordThread().get();
Paul McLean12340082019-03-19 09:35:05 -06003041 return recordThread->setPreferredMicrophoneDirection(direction);
Paul McLean03a6e6a2018-12-04 10:54:13 -07003042 } else {
3043 return BAD_VALUE;
3044 }
3045}
3046
Andy Hung3ff4b552023-06-26 19:20:57 -07003047status_t RecordTrack::setPreferredMicrophoneFieldDimension(float zoom) {
Andy Hung44f27182023-07-06 20:56:16 -07003048 const sp<IAfThreadBase> thread = mThread.promote();
Paul McLean03a6e6a2018-12-04 10:54:13 -07003049 if (thread != 0) {
Andy Hung44f27182023-07-06 20:56:16 -07003050 auto* const recordThread = thread->asIAfRecordThread().get();
Paul McLean12340082019-03-19 09:35:05 -06003051 return recordThread->setPreferredMicrophoneFieldDimension(zoom);
Paul McLean03a6e6a2018-12-04 10:54:13 -07003052 } else {
3053 return BAD_VALUE;
3054 }
3055}
3056
Andy Hung3ff4b552023-06-26 19:20:57 -07003057status_t RecordTrack::shareAudioHistory(
Eric Laurentec376dc2021-04-08 20:41:22 +02003058 const std::string& sharedAudioPackageName, int64_t sharedAudioStartMs) {
3059
3060 const uid_t callingUid = IPCThreadState::self()->getCallingUid();
3061 const pid_t callingPid = IPCThreadState::self()->getCallingPid();
3062 if (callingUid != mUid || callingPid != mCreatorPid) {
3063 return PERMISSION_DENIED;
3064 }
3065
Svet Ganov33761132021-05-13 22:51:08 +00003066 AttributionSourceState attributionSource{};
3067 attributionSource.uid = VALUE_OR_RETURN_STATUS(legacy2aidl_uid_t_int32_t(callingUid));
3068 attributionSource.pid = VALUE_OR_RETURN_STATUS(legacy2aidl_uid_t_int32_t(callingPid));
3069 attributionSource.token = sp<BBinder>::make();
3070 if (!captureHotwordAllowed(attributionSource)) {
Eric Laurentec376dc2021-04-08 20:41:22 +02003071 return PERMISSION_DENIED;
3072 }
3073
Andy Hung44f27182023-07-06 20:56:16 -07003074 const sp<IAfThreadBase> thread = mThread.promote();
Eric Laurentec376dc2021-04-08 20:41:22 +02003075 if (thread != 0) {
Andy Hung44f27182023-07-06 20:56:16 -07003076 auto* const recordThread = thread->asIAfRecordThread().get();
Eric Laurentec376dc2021-04-08 20:41:22 +02003077 status_t status = recordThread->shareAudioHistory(
3078 sharedAudioPackageName, mSessionId, sharedAudioStartMs);
3079 if (status == NO_ERROR) {
3080 mSharedAudioPackageName = sharedAudioPackageName;
3081 }
3082 return status;
3083 } else {
3084 return BAD_VALUE;
3085 }
3086}
3087
Andy Hung3ff4b552023-06-26 19:20:57 -07003088void RecordTrack::copyMetadataTo(MetadataInserter& backInserter) const
Eric Laurent78b07302022-10-07 16:20:34 +02003089{
3090
3091 // Do not forward PatchRecord metadata with unspecified audio source
3092 if (mAttr.source == AUDIO_SOURCE_DEFAULT) {
3093 return;
3094 }
3095
3096 // No track is invalid as this is called after prepareTrack_l in the same critical section
3097 record_track_metadata_v7_t metadata;
3098 metadata.base = {
3099 .source = mAttr.source,
3100 .gain = 1, // capture tracks do not have volumes
3101 };
3102 metadata.channel_mask = mChannelMask;
3103 strncpy(metadata.tags, mAttr.tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE);
3104
3105 *backInserter++ = metadata;
3106}
Eric Laurentec376dc2021-04-08 20:41:22 +02003107
Andy Hung9d84af52018-09-12 18:03:44 -07003108// ----------------------------------------------------------------------------
3109#undef LOG_TAG
3110#define LOG_TAG "AF::PatchRecord"
3111
Andy Hung3ff4b552023-06-26 19:20:57 -07003112/* static */
3113sp<IAfPatchRecord> IAfPatchRecord::create(
Andy Hung44f27182023-07-06 20:56:16 -07003114 IAfRecordThread* recordThread,
Andy Hung3ff4b552023-06-26 19:20:57 -07003115 uint32_t sampleRate,
3116 audio_channel_mask_t channelMask,
3117 audio_format_t format,
3118 size_t frameCount,
3119 void *buffer,
3120 size_t bufferSize,
3121 audio_input_flags_t flags,
3122 const Timeout& timeout,
3123 audio_source_t source)
3124{
3125 return sp<PatchRecord>::make(
Andy Hung44f27182023-07-06 20:56:16 -07003126 recordThread,
Andy Hung3ff4b552023-06-26 19:20:57 -07003127 sampleRate,
3128 channelMask,
3129 format,
3130 frameCount,
3131 buffer,
3132 bufferSize,
3133 flags,
3134 timeout,
3135 source);
3136}
3137
Andy Hung44f27182023-07-06 20:56:16 -07003138PatchRecord::PatchRecord(IAfRecordThread* recordThread,
Eric Laurent83b88082014-06-20 18:31:16 -07003139 uint32_t sampleRate,
3140 audio_channel_mask_t channelMask,
3141 audio_format_t format,
3142 size_t frameCount,
3143 void *buffer,
Andy Hung8fe68032017-06-05 16:17:51 -07003144 size_t bufferSize,
Kevin Rocard45986c72018-12-18 18:22:59 -08003145 audio_input_flags_t flags,
Eric Laurent78b07302022-10-07 16:20:34 +02003146 const Timeout& timeout,
3147 audio_source_t source)
Kevin Rocard1f564ac2018-03-29 13:53:10 -07003148 : RecordTrack(recordThread, NULL,
Eric Laurent78b07302022-10-07 16:20:34 +02003149 audio_attributes_t{ .source = source } ,
Kevin Rocard1f564ac2018-03-29 13:53:10 -07003150 sampleRate, format, channelMask, frameCount,
Philip P. Moltmannbda45752020-07-17 16:41:18 -07003151 buffer, bufferSize, AUDIO_SESSION_NONE, getpid(),
Svet Ganov33761132021-05-13 22:51:08 +00003152 audioServerAttributionSource(getpid()), flags, TYPE_PATCH),
gaoxiupei8e3a5682023-07-07 20:30:23 +08003153 PatchTrackBase(mCblk ? new ClientProxy(mCblk, mBuffer, frameCount, mFrameSize, false, true)
3154 : nullptr,
Andy Hung837229a2023-07-14 16:57:01 -07003155 recordThread, timeout)
Eric Laurent83b88082014-06-20 18:31:16 -07003156{
Andy Hung9d84af52018-09-12 18:03:44 -07003157 ALOGV("%s(%d): sampleRate %d mPeerTimeout %d.%03d sec",
3158 __func__, mId, sampleRate,
Eric Laurent83b88082014-06-20 18:31:16 -07003159 (int)mPeerTimeout.tv_sec,
3160 (int)(mPeerTimeout.tv_nsec / 1000000));
3161}
3162
Andy Hung3ff4b552023-06-26 19:20:57 -07003163PatchRecord::~PatchRecord()
Eric Laurent83b88082014-06-20 18:31:16 -07003164{
Andy Hungabfab202019-03-07 19:45:54 -08003165 ALOGV("%s(%d)", __func__, mId);
Eric Laurent83b88082014-06-20 18:31:16 -07003166}
3167
Mikhail Naganov8296c252019-09-25 14:59:54 -07003168static size_t writeFramesHelper(
3169 AudioBufferProvider* dest, const void* src, size_t frameCount, size_t frameSize)
3170{
3171 AudioBufferProvider::Buffer patchBuffer;
3172 patchBuffer.frameCount = frameCount;
3173 auto status = dest->getNextBuffer(&patchBuffer);
3174 if (status != NO_ERROR) {
3175 ALOGW("%s PathRecord getNextBuffer failed with error %d: %s",
3176 __func__, status, strerror(-status));
3177 return 0;
3178 }
3179 ALOG_ASSERT(patchBuffer.frameCount <= frameCount);
3180 memcpy(patchBuffer.raw, src, patchBuffer.frameCount * frameSize);
3181 size_t framesWritten = patchBuffer.frameCount;
3182 dest->releaseBuffer(&patchBuffer);
3183 return framesWritten;
3184}
3185
3186// static
Andy Hung3ff4b552023-06-26 19:20:57 -07003187size_t PatchRecord::writeFrames(
Mikhail Naganov8296c252019-09-25 14:59:54 -07003188 AudioBufferProvider* dest, const void* src, size_t frameCount, size_t frameSize)
3189{
3190 size_t framesWritten = writeFramesHelper(dest, src, frameCount, frameSize);
3191 // On buffer wrap, the buffer frame count will be less than requested,
3192 // when this happens a second buffer needs to be used to write the leftover audio
3193 const size_t framesLeft = frameCount - framesWritten;
3194 if (framesWritten != 0 && framesLeft != 0) {
3195 framesWritten += writeFramesHelper(dest, (const char*)src + framesWritten * frameSize,
3196 framesLeft, frameSize);
3197 }
3198 return framesWritten;
3199}
3200
Eric Laurent83b88082014-06-20 18:31:16 -07003201// AudioBufferProvider interface
Andy Hung3ff4b552023-06-26 19:20:57 -07003202status_t PatchRecord::getNextBuffer(
Glenn Kastend79072e2016-01-06 08:41:20 -08003203 AudioBufferProvider::Buffer* buffer)
Eric Laurent83b88082014-06-20 18:31:16 -07003204{
Andy Hung9d84af52018-09-12 18:03:44 -07003205 ALOG_ASSERT(mPeerProxy != 0, "%s(%d): called without peer proxy", __func__, mId);
Eric Laurent83b88082014-06-20 18:31:16 -07003206 Proxy::Buffer buf;
3207 buf.mFrameCount = buffer->frameCount;
3208 status_t status = mPeerProxy->obtainBuffer(&buf, &mPeerTimeout);
3209 ALOGV_IF(status != NO_ERROR,
Andy Hung9d84af52018-09-12 18:03:44 -07003210 "%s(%d): mPeerProxy->obtainBuffer status %d", __func__, mId, status);
Eric Laurentc2730ba2014-07-20 15:47:07 -07003211 buffer->frameCount = buf.mFrameCount;
Mikhail Naganov938be412019-09-04 11:38:47 -07003212 if (ATRACE_ENABLED()) {
3213 std::string traceName("PRnObt");
3214 traceName += std::to_string(id());
3215 ATRACE_INT(traceName.c_str(), buf.mFrameCount);
3216 }
Eric Laurent83b88082014-06-20 18:31:16 -07003217 if (buf.mFrameCount == 0) {
3218 return WOULD_BLOCK;
3219 }
Glenn Kastend79072e2016-01-06 08:41:20 -08003220 status = RecordTrack::getNextBuffer(buffer);
Eric Laurent83b88082014-06-20 18:31:16 -07003221 return status;
3222}
3223
Andy Hung3ff4b552023-06-26 19:20:57 -07003224void PatchRecord::releaseBuffer(AudioBufferProvider::Buffer* buffer)
Eric Laurent83b88082014-06-20 18:31:16 -07003225{
Andy Hung9d84af52018-09-12 18:03:44 -07003226 ALOG_ASSERT(mPeerProxy != 0, "%s(%d): called without peer proxy", __func__, mId);
Eric Laurent83b88082014-06-20 18:31:16 -07003227 Proxy::Buffer buf;
3228 buf.mFrameCount = buffer->frameCount;
3229 buf.mRaw = buffer->raw;
3230 mPeerProxy->releaseBuffer(&buf);
3231 TrackBase::releaseBuffer(buffer);
3232}
3233
Andy Hung3ff4b552023-06-26 19:20:57 -07003234status_t PatchRecord::obtainBuffer(Proxy::Buffer* buffer,
Eric Laurent83b88082014-06-20 18:31:16 -07003235 const struct timespec *timeOut)
3236{
3237 return mProxy->obtainBuffer(buffer, timeOut);
3238}
3239
Andy Hung3ff4b552023-06-26 19:20:57 -07003240void PatchRecord::releaseBuffer(Proxy::Buffer* buffer)
Eric Laurent83b88082014-06-20 18:31:16 -07003241{
3242 mProxy->releaseBuffer(buffer);
3243}
3244
Mikhail Naganovcaf59942019-09-25 14:05:29 -07003245#undef LOG_TAG
3246#define LOG_TAG "AF::PthrPatchRecord"
3247
3248static std::unique_ptr<void, decltype(free)*> allocAligned(size_t alignment, size_t size)
3249{
3250 void *ptr = nullptr;
3251 (void)posix_memalign(&ptr, alignment, size);
Andy Hung71ba4b32022-10-06 12:09:49 -07003252 return {ptr, free};
Mikhail Naganovcaf59942019-09-25 14:05:29 -07003253}
3254
Andy Hung3ff4b552023-06-26 19:20:57 -07003255/* static */
3256sp<IAfPatchRecord> IAfPatchRecord::createPassThru(
Andy Hung44f27182023-07-06 20:56:16 -07003257 IAfRecordThread* recordThread,
Andy Hung3ff4b552023-06-26 19:20:57 -07003258 uint32_t sampleRate,
3259 audio_channel_mask_t channelMask,
3260 audio_format_t format,
3261 size_t frameCount,
3262 audio_input_flags_t flags,
3263 audio_source_t source)
3264{
3265 return sp<PassthruPatchRecord>::make(
Andy Hung44f27182023-07-06 20:56:16 -07003266 recordThread,
Andy Hung3ff4b552023-06-26 19:20:57 -07003267 sampleRate,
3268 channelMask,
3269 format,
3270 frameCount,
3271 flags,
3272 source);
3273}
3274
3275PassthruPatchRecord::PassthruPatchRecord(
Andy Hung44f27182023-07-06 20:56:16 -07003276 IAfRecordThread* recordThread,
Mikhail Naganovcaf59942019-09-25 14:05:29 -07003277 uint32_t sampleRate,
3278 audio_channel_mask_t channelMask,
3279 audio_format_t format,
3280 size_t frameCount,
Eric Laurent78b07302022-10-07 16:20:34 +02003281 audio_input_flags_t flags,
3282 audio_source_t source)
Mikhail Naganovcaf59942019-09-25 14:05:29 -07003283 : PatchRecord(recordThread, sampleRate, channelMask, format, frameCount,
Eric Laurent78b07302022-10-07 16:20:34 +02003284 nullptr /*buffer*/, 0 /*bufferSize*/, flags, {} /* timeout */, source),
Mikhail Naganovcaf59942019-09-25 14:05:29 -07003285 mPatchRecordAudioBufferProvider(*this),
3286 mSinkBuffer(allocAligned(32, mFrameCount * mFrameSize)),
3287 mStubBuffer(allocAligned(32, mFrameCount * mFrameSize))
3288{
3289 memset(mStubBuffer.get(), 0, mFrameCount * mFrameSize);
3290}
3291
Andy Hung3ff4b552023-06-26 19:20:57 -07003292sp<StreamInHalInterface> PassthruPatchRecord::obtainStream(
Andy Hung44f27182023-07-06 20:56:16 -07003293 sp<IAfThreadBase>* thread)
Mikhail Naganovcaf59942019-09-25 14:05:29 -07003294{
3295 *thread = mThread.promote();
3296 if (!*thread) return nullptr;
Andy Hung44f27182023-07-06 20:56:16 -07003297 auto* const recordThread = (*thread)->asIAfRecordThread().get();
Andy Hung87e82412023-08-29 14:26:09 -07003298 audio_utils::lock_guard _l(recordThread->mutex());
Andy Hung44f27182023-07-06 20:56:16 -07003299 return recordThread->getInput() ? recordThread->getInput()->stream : nullptr;
Mikhail Naganovcaf59942019-09-25 14:05:29 -07003300}
3301
3302// PatchProxyBufferProvider methods are called on DirectOutputThread
Andy Hung3ff4b552023-06-26 19:20:57 -07003303status_t PassthruPatchRecord::obtainBuffer(
Mikhail Naganovcaf59942019-09-25 14:05:29 -07003304 Proxy::Buffer* buffer, const struct timespec* timeOut)
3305{
3306 if (mUnconsumedFrames) {
3307 buffer->mFrameCount = std::min(buffer->mFrameCount, mUnconsumedFrames);
3308 // mUnconsumedFrames is decreased in releaseBuffer to use actual frame consumption figure.
3309 return PatchRecord::obtainBuffer(buffer, timeOut);
3310 }
3311
3312 // Otherwise, execute a read from HAL and write into the buffer.
3313 nsecs_t startTimeNs = 0;
3314 if (timeOut && (timeOut->tv_sec != 0 || timeOut->tv_nsec != 0) && timeOut->tv_sec != INT_MAX) {
3315 // Will need to correct timeOut by elapsed time.
3316 startTimeNs = systemTime();
3317 }
3318 const size_t framesToRead = std::min(buffer->mFrameCount, mFrameCount);
3319 buffer->mFrameCount = 0;
3320 buffer->mRaw = nullptr;
Andy Hung44f27182023-07-06 20:56:16 -07003321 sp<IAfThreadBase> thread;
Mikhail Naganovcaf59942019-09-25 14:05:29 -07003322 sp<StreamInHalInterface> stream = obtainStream(&thread);
3323 if (!stream) return NO_INIT; // If there is no stream, RecordThread is not reading.
3324
3325 status_t result = NO_ERROR;
Mikhail Naganovcaf59942019-09-25 14:05:29 -07003326 size_t bytesRead = 0;
3327 {
3328 ATRACE_NAME("read");
3329 result = stream->read(mSinkBuffer.get(), framesToRead * mFrameSize, &bytesRead);
3330 if (result != NO_ERROR) goto stream_error;
3331 if (bytesRead == 0) return NO_ERROR;
3332 }
3333
3334 {
Andy Hung094dc762023-08-28 19:12:14 -07003335 audio_utils::lock_guard lock(readMutex());
Mikhail Naganovcaf59942019-09-25 14:05:29 -07003336 mReadBytes += bytesRead;
3337 mReadError = NO_ERROR;
3338 }
3339 mReadCV.notify_one();
3340 // writeFrames handles wraparound and should write all the provided frames.
3341 // If it couldn't, there is something wrong with the client/server buffer of the software patch.
3342 buffer->mFrameCount = writeFrames(
3343 &mPatchRecordAudioBufferProvider,
3344 mSinkBuffer.get(), bytesRead / mFrameSize, mFrameSize);
3345 ALOGW_IF(buffer->mFrameCount < bytesRead / mFrameSize,
3346 "Lost %zu frames obtained from HAL", bytesRead / mFrameSize - buffer->mFrameCount);
3347 mUnconsumedFrames = buffer->mFrameCount;
Mikhail Naganov4de49972019-10-07 09:53:58 -07003348 struct timespec newTimeOut;
Mikhail Naganovcaf59942019-09-25 14:05:29 -07003349 if (startTimeNs) {
Mikhail Naganov4de49972019-10-07 09:53:58 -07003350 // Correct the timeout by elapsed time.
3351 nsecs_t newTimeOutNs = audio_utils_ns_from_timespec(timeOut) - (systemTime() - startTimeNs);
Mikhail Naganovcaf59942019-09-25 14:05:29 -07003352 if (newTimeOutNs < 0) newTimeOutNs = 0;
3353 newTimeOut.tv_sec = newTimeOutNs / NANOS_PER_SECOND;
3354 newTimeOut.tv_nsec = newTimeOutNs - newTimeOut.tv_sec * NANOS_PER_SECOND;
Mikhail Naganov4de49972019-10-07 09:53:58 -07003355 timeOut = &newTimeOut;
Mikhail Naganovcaf59942019-09-25 14:05:29 -07003356 }
Mikhail Naganov4de49972019-10-07 09:53:58 -07003357 return PatchRecord::obtainBuffer(buffer, timeOut);
Mikhail Naganovcaf59942019-09-25 14:05:29 -07003358
3359stream_error:
3360 stream->standby();
3361 {
Andy Hung094dc762023-08-28 19:12:14 -07003362 audio_utils::lock_guard lock(readMutex());
Mikhail Naganovcaf59942019-09-25 14:05:29 -07003363 mReadError = result;
3364 }
3365 mReadCV.notify_one();
3366 return result;
3367}
3368
Andy Hung3ff4b552023-06-26 19:20:57 -07003369void PassthruPatchRecord::releaseBuffer(Proxy::Buffer* buffer)
Mikhail Naganovcaf59942019-09-25 14:05:29 -07003370{
3371 if (buffer->mFrameCount <= mUnconsumedFrames) {
3372 mUnconsumedFrames -= buffer->mFrameCount;
3373 } else {
3374 ALOGW("Write side has consumed more frames than we had: %zu > %zu",
3375 buffer->mFrameCount, mUnconsumedFrames);
3376 mUnconsumedFrames = 0;
3377 }
3378 PatchRecord::releaseBuffer(buffer);
3379}
3380
3381// AudioBufferProvider and Source methods are called on RecordThread
3382// 'read' emulates actual audio data with 0's. This is OK as 'getNextBuffer'
3383// and 'releaseBuffer' are stubbed out and ignore their input.
3384// It's not possible to retrieve actual data here w/o blocking 'obtainBuffer'
3385// until we copy it.
Andy Hung3ff4b552023-06-26 19:20:57 -07003386status_t PassthruPatchRecord::read(
Mikhail Naganovcaf59942019-09-25 14:05:29 -07003387 void* buffer, size_t bytes, size_t* read)
3388{
3389 bytes = std::min(bytes, mFrameCount * mFrameSize);
3390 {
Andy Hung094dc762023-08-28 19:12:14 -07003391 audio_utils::unique_lock lock(readMutex());
Mikhail Naganovcaf59942019-09-25 14:05:29 -07003392 mReadCV.wait(lock, [&]{ return mReadError != NO_ERROR || mReadBytes != 0; });
3393 if (mReadError != NO_ERROR) {
3394 mLastReadFrames = 0;
3395 return mReadError;
3396 }
3397 *read = std::min(bytes, mReadBytes);
3398 mReadBytes -= *read;
3399 }
3400 mLastReadFrames = *read / mFrameSize;
3401 memset(buffer, 0, *read);
3402 return 0;
3403}
3404
Andy Hung3ff4b552023-06-26 19:20:57 -07003405status_t PassthruPatchRecord::getCapturePosition(
Mikhail Naganovcaf59942019-09-25 14:05:29 -07003406 int64_t* frames, int64_t* time)
3407{
Andy Hung44f27182023-07-06 20:56:16 -07003408 sp<IAfThreadBase> thread;
Mikhail Naganovcaf59942019-09-25 14:05:29 -07003409 sp<StreamInHalInterface> stream = obtainStream(&thread);
3410 return stream ? stream->getCapturePosition(frames, time) : NO_INIT;
3411}
3412
Andy Hung3ff4b552023-06-26 19:20:57 -07003413status_t PassthruPatchRecord::standby()
Mikhail Naganovcaf59942019-09-25 14:05:29 -07003414{
3415 // RecordThread issues 'standby' command in two major cases:
3416 // 1. Error on read--this case is handled in 'obtainBuffer'.
3417 // 2. Track is stopping--as PassthruPatchRecord assumes continuous
3418 // output, this can only happen when the software patch
3419 // is being torn down. In this case, the RecordThread
3420 // will terminate and close the HAL stream.
3421 return 0;
3422}
3423
3424// As the buffer gets filled in obtainBuffer, here we only simulate data consumption.
Andy Hung3ff4b552023-06-26 19:20:57 -07003425status_t PassthruPatchRecord::getNextBuffer(
Mikhail Naganovcaf59942019-09-25 14:05:29 -07003426 AudioBufferProvider::Buffer* buffer)
3427{
3428 buffer->frameCount = mLastReadFrames;
3429 buffer->raw = buffer->frameCount != 0 ? mStubBuffer.get() : nullptr;
3430 return NO_ERROR;
3431}
3432
Andy Hung3ff4b552023-06-26 19:20:57 -07003433void PassthruPatchRecord::releaseBuffer(
Mikhail Naganovcaf59942019-09-25 14:05:29 -07003434 AudioBufferProvider::Buffer* buffer)
3435{
3436 buffer->frameCount = 0;
3437 buffer->raw = nullptr;
3438}
3439
Andy Hung9d84af52018-09-12 18:03:44 -07003440// ----------------------------------------------------------------------------
3441#undef LOG_TAG
3442#define LOG_TAG "AF::MmapTrack"
Eric Laurent6acd1d42017-01-04 14:23:29 -08003443
Andy Hung3ff4b552023-06-26 19:20:57 -07003444/* static */
Andy Hung44f27182023-07-06 20:56:16 -07003445sp<IAfMmapTrack> IAfMmapTrack::create(IAfThreadBase* thread,
Andy Hung3ff4b552023-06-26 19:20:57 -07003446 const audio_attributes_t& attr,
3447 uint32_t sampleRate,
3448 audio_format_t format,
3449 audio_channel_mask_t channelMask,
3450 audio_session_t sessionId,
3451 bool isOut,
3452 const android::content::AttributionSourceState& attributionSource,
3453 pid_t creatorPid,
3454 audio_port_handle_t portId)
3455{
3456 return sp<MmapTrack>::make(
Andy Hung44f27182023-07-06 20:56:16 -07003457 thread,
Andy Hung3ff4b552023-06-26 19:20:57 -07003458 attr,
3459 sampleRate,
3460 format,
3461 channelMask,
3462 sessionId,
3463 isOut,
3464 attributionSource,
3465 creatorPid,
3466 portId);
3467}
3468
Andy Hung44f27182023-07-06 20:56:16 -07003469MmapTrack::MmapTrack(IAfThreadBase* thread,
Kevin Rocard1f564ac2018-03-29 13:53:10 -07003470 const audio_attributes_t& attr,
Eric Laurent6acd1d42017-01-04 14:23:29 -08003471 uint32_t sampleRate,
3472 audio_format_t format,
3473 audio_channel_mask_t channelMask,
3474 audio_session_t sessionId,
Kevin Rocard5f2136e2018-05-11 22:03:00 -07003475 bool isOut,
Svet Ganov33761132021-05-13 22:51:08 +00003476 const AttributionSourceState& attributionSource,
Eric Laurent09f1ed22019-04-24 17:45:17 -07003477 pid_t creatorPid,
Eric Laurent6acd1d42017-01-04 14:23:29 -08003478 audio_port_handle_t portId)
Kevin Rocard1f564ac2018-03-29 13:53:10 -07003479 : TrackBase(thread, NULL, attr, sampleRate, format,
Andy Hung8fe68032017-06-05 16:17:51 -07003480 channelMask, (size_t)0 /* frameCount */,
3481 nullptr /* buffer */, (size_t)0 /* bufferSize */,
Philip P. Moltmannbda45752020-07-17 16:41:18 -07003482 sessionId, creatorPid,
Svet Ganov33761132021-05-13 22:51:08 +00003483 VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid)),
Philip P. Moltmannbda45752020-07-17 16:41:18 -07003484 isOut,
Eric Laurent6acd1d42017-01-04 14:23:29 -08003485 ALLOC_NONE,
Andy Hungc2b11cb2020-04-22 09:04:01 -07003486 TYPE_DEFAULT, portId,
3487 std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_MMAP) + std::to_string(portId)),
Svet Ganov33761132021-05-13 22:51:08 +00003488 mPid(VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.pid))),
Philip P. Moltmannbda45752020-07-17 16:41:18 -07003489 mSilenced(false), mSilencedNotified(false)
Eric Laurent6acd1d42017-01-04 14:23:29 -08003490{
Andy Hungc2b11cb2020-04-22 09:04:01 -07003491 // Once this item is logged by the server, the client can add properties.
Andy Hung94235282021-03-24 15:50:14 -07003492 mTrackMetrics.logConstructor(creatorPid, uid(), id());
Eric Laurent6acd1d42017-01-04 14:23:29 -08003493}
3494
Andy Hung3ff4b552023-06-26 19:20:57 -07003495MmapTrack::~MmapTrack()
Eric Laurent6acd1d42017-01-04 14:23:29 -08003496{
3497}
3498
Andy Hung3ff4b552023-06-26 19:20:57 -07003499status_t MmapTrack::initCheck() const
Eric Laurent6acd1d42017-01-04 14:23:29 -08003500{
3501 return NO_ERROR;
3502}
3503
Andy Hung3ff4b552023-06-26 19:20:57 -07003504status_t MmapTrack::start(AudioSystem::sync_event_t event __unused,
Kevin Rocard5f2136e2018-05-11 22:03:00 -07003505 audio_session_t triggerSession __unused)
Eric Laurent6acd1d42017-01-04 14:23:29 -08003506{
3507 return NO_ERROR;
3508}
3509
Andy Hung3ff4b552023-06-26 19:20:57 -07003510void MmapTrack::stop()
Eric Laurent6acd1d42017-01-04 14:23:29 -08003511{
3512}
3513
3514// AudioBufferProvider interface
Andy Hung3ff4b552023-06-26 19:20:57 -07003515status_t MmapTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer)
Eric Laurent6acd1d42017-01-04 14:23:29 -08003516{
3517 buffer->frameCount = 0;
3518 buffer->raw = nullptr;
3519 return INVALID_OPERATION;
3520}
3521
3522// ExtendedAudioBufferProvider interface
Andy Hung3ff4b552023-06-26 19:20:57 -07003523size_t MmapTrack::framesReady() const {
Eric Laurent6acd1d42017-01-04 14:23:29 -08003524 return 0;
3525}
3526
Andy Hung3ff4b552023-06-26 19:20:57 -07003527int64_t MmapTrack::framesReleased() const
Eric Laurent6acd1d42017-01-04 14:23:29 -08003528{
3529 return 0;
3530}
3531
Andy Hung3ff4b552023-06-26 19:20:57 -07003532void MmapTrack::onTimestamp(const ExtendedTimestamp& timestamp __unused)
Eric Laurent6acd1d42017-01-04 14:23:29 -08003533{
3534}
3535
Andy Hung3ff4b552023-06-26 19:20:57 -07003536void MmapTrack::processMuteEvent_l(const sp<IAudioManager>& audioManager, mute_state_t muteState)
Vlad Popaec1788e2022-08-04 11:23:30 +02003537{
3538 if (mMuteState == muteState) {
3539 // mute state did not change, do nothing
3540 return;
3541 }
3542
3543 status_t result = UNKNOWN_ERROR;
3544 if (audioManager && mPortId != AUDIO_PORT_HANDLE_NONE) {
3545 if (mMuteEventExtras == nullptr) {
3546 mMuteEventExtras = std::make_unique<os::PersistableBundle>();
3547 }
3548 mMuteEventExtras->putInt(String16(kExtraPlayerEventMuteKey),
3549 static_cast<int>(muteState));
3550
3551 result = audioManager->portEvent(mPortId,
3552 PLAYER_UPDATE_MUTED,
3553 mMuteEventExtras);
3554 }
3555
3556 if (result == OK) {
Andy Hung6fb26892024-02-20 16:32:57 -08003557 ALOGI("%s(%d): processed mute state for port ID %d from %d to %d", __func__, id(), mPortId,
3558 static_cast<int>(mMuteState), static_cast<int>(muteState));
Vlad Popaec1788e2022-08-04 11:23:30 +02003559 mMuteState = muteState;
3560 } else {
3561 ALOGW("%s(%d): cannot process mute state for port ID %d, status error %d",
3562 __func__,
3563 id(),
3564 mPortId,
3565 result);
3566 }
3567}
3568
Andy Hung3ff4b552023-06-26 19:20:57 -07003569void MmapTrack::appendDumpHeader(String8& result) const
Eric Laurent6acd1d42017-01-04 14:23:29 -08003570{
Eric Laurent973db022018-11-20 14:54:31 -08003571 result.appendFormat("Client Session Port Id Format Chn mask SRate Flags %s\n",
Kevin Rocard5f2136e2018-05-11 22:03:00 -07003572 isOut() ? "Usg CT": "Source");
Eric Laurent6acd1d42017-01-04 14:23:29 -08003573}
3574
Andy Hung3ff4b552023-06-26 19:20:57 -07003575void MmapTrack::appendDump(String8& result, bool active __unused) const
Eric Laurent6acd1d42017-01-04 14:23:29 -08003576{
Eric Laurent973db022018-11-20 14:54:31 -08003577 result.appendFormat("%6u %7u %7u %08X %08X %6u 0x%03X ",
Andy Hung2c6c3bb2017-06-16 14:01:45 -07003578 mPid,
3579 mSessionId,
Eric Laurent973db022018-11-20 14:54:31 -08003580 mPortId,
Eric Laurent6acd1d42017-01-04 14:23:29 -08003581 mFormat,
3582 mChannelMask,
Kevin Rocard5f2136e2018-05-11 22:03:00 -07003583 mSampleRate,
3584 mAttr.flags);
3585 if (isOut()) {
3586 result.appendFormat("%3x %2x", mAttr.usage, mAttr.content_type);
3587 } else {
3588 result.appendFormat("%6x", mAttr.source);
3589 }
3590 result.append("\n");
Eric Laurent6acd1d42017-01-04 14:23:29 -08003591}
3592
Glenn Kasten63238ef2015-03-02 15:50:29 -08003593} // namespace android