blob: cd1a8476ad63c59e49110d48a9956536e680d872 [file] [log] [blame]
Glenn Kasten99e53b82012-01-19 08:59:58 -08001/*
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08002**
3** Copyright 2007, 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
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080018//#define LOG_NDEBUG 0
19#define LOG_TAG "AudioTrack"
20
Mark Salyzyn34fb2962014-06-18 16:30:56 -070021#include <inttypes.h>
Glenn Kastenc56f3422014-03-21 17:53:17 -070022#include <math.h>
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080023#include <sys/resource.h>
Mark Salyzyn34fb2962014-06-18 16:30:56 -070024
Chih-Hung Hsiehffe35582018-09-13 13:59:28 -070025#include <android-base/macros.h>
Andy Hung2b01f002017-07-05 12:01:36 -070026#include <audio_utils/clock.h>
Glenn Kasten9f80dd22012-12-18 15:57:32 -080027#include <audio_utils/primitives.h>
28#include <binder/IPCThreadState.h>
29#include <media/AudioTrack.h>
30#include <utils/Log.h>
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080031#include <private/media/AudioTrackShared.h>
Suren Baghdasaryan7435e7d2018-12-19 17:09:28 -080032#include <processgroup/sched_policy.h>
Glenn Kasten1ab85ec2013-05-31 09:18:43 -070033#include <media/IAudioFlinger.h>
Michael Chana94fbb22018-04-24 14:31:19 +100034#include <media/IAudioPolicyService.h>
Dean Wheatleya70eef72018-01-04 14:23:50 +110035#include <media/AudioParameter.h>
Andy Hungcd044842014-08-07 11:04:34 -070036#include <media/AudioResamplerPublic.h>
Michael Chana94fbb22018-04-24 14:31:19 +100037#include <media/AudioSystem.h>
Ray Essickf27e9872019-12-07 06:28:46 -080038#include <media/MediaMetricsItem.h>
Ray Essicked304702017-12-12 14:00:57 -080039#include <media/TypeConverter.h>
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080040
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +010041#define WAIT_PERIOD_MS 10
42#define WAIT_STREAM_END_TIMEOUT_SEC 120
Andy Hung53c3b5f2014-12-15 16:42:05 -080043static const int kMaxLoopCountNotifications = 32;
Glenn Kasten511754b2012-01-11 09:52:19 -080044
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080045namespace android {
Chia-chi Yeh33005a92010-06-16 06:33:13 +080046// ---------------------------------------------------------------------------
47
Ivan Lozano8cf3a072017-08-09 09:01:33 -070048using media::VolumeShaper;
49
Andy Hunga7f03352015-05-31 21:54:49 -070050// TODO: Move to a separate .h
51
Andy Hung4ede21d2014-12-12 15:37:34 -080052template <typename T>
Andy Hunga7f03352015-05-31 21:54:49 -070053static inline const T &min(const T &x, const T &y) {
Andy Hung4ede21d2014-12-12 15:37:34 -080054 return x < y ? x : y;
55}
56
Andy Hunga7f03352015-05-31 21:54:49 -070057template <typename T>
58static inline const T &max(const T &x, const T &y) {
59 return x > y ? x : y;
60}
61
62static inline nsecs_t framesToNanoseconds(ssize_t frames, uint32_t sampleRate, float speed)
63{
64 return ((double)frames * 1000000000) / ((double)sampleRate * speed);
65}
66
Andy Hung7f1bc8a2014-09-12 14:43:11 -070067static int64_t convertTimespecToUs(const struct timespec &tv)
68{
Chih-Hung Hsieh50fa06c2018-12-11 13:51:36 -080069 return tv.tv_sec * 1000000LL + tv.tv_nsec / 1000;
Andy Hung7f1bc8a2014-09-12 14:43:11 -070070}
71
Andy Hungffa36952017-08-17 10:41:51 -070072// TODO move to audio_utils.
73static inline struct timespec convertNsToTimespec(int64_t ns) {
74 struct timespec tv;
75 tv.tv_sec = static_cast<time_t>(ns / NANOS_PER_SECOND);
Andy Hung06a730b2020-04-09 13:28:31 -070076 tv.tv_nsec = static_cast<int64_t>(ns % NANOS_PER_SECOND);
Andy Hungffa36952017-08-17 10:41:51 -070077 return tv;
78}
79
Andy Hung7f1bc8a2014-09-12 14:43:11 -070080// current monotonic time in microseconds.
81static int64_t getNowUs()
82{
83 struct timespec tv;
84 (void) clock_gettime(CLOCK_MONOTONIC, &tv);
85 return convertTimespecToUs(tv);
86}
87
Andy Hung26145642015-04-15 21:56:53 -070088// FIXME: we don't use the pitch setting in the time stretcher (not working);
89// instead we emulate it using our sample rate converter.
90static const bool kFixPitch = true; // enable pitch fix
91static inline uint32_t adjustSampleRate(uint32_t sampleRate, float pitch)
92{
93 return kFixPitch ? (sampleRate * pitch + 0.5) : sampleRate;
94}
95
96static inline float adjustSpeed(float speed, float pitch)
97{
Ricardo Garcia6c7f0622015-04-30 18:39:16 -070098 return kFixPitch ? speed / max(pitch, AUDIO_TIMESTRETCH_PITCH_MIN_DELTA) : speed;
Andy Hung26145642015-04-15 21:56:53 -070099}
100
101static inline float adjustPitch(float pitch)
102{
103 return kFixPitch ? AUDIO_TIMESTRETCH_PITCH_NORMAL : pitch;
104}
105
Chia-chi Yeh33005a92010-06-16 06:33:13 +0800106// static
107status_t AudioTrack::getMinFrameCount(
Glenn Kastene33054e2012-11-14 12:54:39 -0800108 size_t* frameCount,
Glenn Kastenfff6d712012-01-12 16:38:12 -0800109 audio_stream_type_t streamType,
Chia-chi Yeh33005a92010-06-16 06:33:13 +0800110 uint32_t sampleRate)
111{
Glenn Kastend65d73c2012-06-22 17:21:07 -0700112 if (frameCount == NULL) {
113 return BAD_VALUE;
114 }
Glenn Kasten04cd0182012-06-25 11:49:27 -0700115
Andy Hung0e48d252015-01-26 11:43:15 -0800116 // FIXME handle in server, like createTrack_l(), possible missing info:
Glenn Kastene0fa4672012-04-24 14:35:14 -0700117 // audio_io_handle_t output
118 // audio_format_t format
119 // audio_channel_mask_t channelMask
Andy Hung0e48d252015-01-26 11:43:15 -0800120 // audio_output_flags_t flags (FAST)
Glenn Kasten3b16c762012-11-14 08:44:39 -0800121 uint32_t afSampleRate;
Glenn Kasten66a04672014-01-08 08:53:44 -0800122 status_t status;
123 status = AudioSystem::getOutputSamplingRate(&afSampleRate, streamType);
124 if (status != NO_ERROR) {
Andy Hungfb8ede22018-09-12 19:03:24 -0700125 ALOGE("%s(): Unable to query output sample rate for stream type %d; status %d",
126 __func__, streamType, status);
Glenn Kasten66a04672014-01-08 08:53:44 -0800127 return status;
Chia-chi Yeh33005a92010-06-16 06:33:13 +0800128 }
Glenn Kastene33054e2012-11-14 12:54:39 -0800129 size_t afFrameCount;
Glenn Kasten66a04672014-01-08 08:53:44 -0800130 status = AudioSystem::getOutputFrameCount(&afFrameCount, streamType);
131 if (status != NO_ERROR) {
Andy Hungfb8ede22018-09-12 19:03:24 -0700132 ALOGE("%s(): Unable to query output frame count for stream type %d; status %d",
133 __func__, streamType, status);
Glenn Kasten66a04672014-01-08 08:53:44 -0800134 return status;
Chia-chi Yeh33005a92010-06-16 06:33:13 +0800135 }
136 uint32_t afLatency;
Glenn Kasten66a04672014-01-08 08:53:44 -0800137 status = AudioSystem::getOutputLatency(&afLatency, streamType);
138 if (status != NO_ERROR) {
Andy Hungfb8ede22018-09-12 19:03:24 -0700139 ALOGE("%s(): Unable to query output latency for stream type %d; status %d",
140 __func__, streamType, status);
Glenn Kasten66a04672014-01-08 08:53:44 -0800141 return status;
Chia-chi Yeh33005a92010-06-16 06:33:13 +0800142 }
143
Andy Hung8edb8dc2015-03-26 19:13:55 -0700144 // When called from createTrack, speed is 1.0f (normal speed).
145 // This is rechecked again on setting playback rate (TODO: on setting sample rate, too).
Eric Laurent21da6472017-11-09 16:29:26 -0800146 *frameCount = AudioSystem::calculateMinFrameCount(afLatency, afFrameCount, afSampleRate,
147 sampleRate, 1.0f /*, 0 notificationsPerBufferReq*/);
Chia-chi Yeh33005a92010-06-16 06:33:13 +0800148
Andy Hung0e48d252015-01-26 11:43:15 -0800149 // The formula above should always produce a non-zero value under normal circumstances:
150 // AudioTrack.SAMPLE_RATE_HZ_MIN <= sampleRate <= AudioTrack.SAMPLE_RATE_HZ_MAX.
151 // Return error in the unlikely event that it does not, as that's part of the API contract.
Glenn Kasten66a04672014-01-08 08:53:44 -0800152 if (*frameCount == 0) {
Andy Hungfb8ede22018-09-12 19:03:24 -0700153 ALOGE("%s(): failed for streamType %d, sampleRate %u",
154 __func__, streamType, sampleRate);
Glenn Kasten66a04672014-01-08 08:53:44 -0800155 return BAD_VALUE;
156 }
Andy Hungfb8ede22018-09-12 19:03:24 -0700157 ALOGV("%s(): getMinFrameCount=%zu: afFrameCount=%zu, afSampleRate=%u, afLatency=%u",
158 __func__, *frameCount, afFrameCount, afSampleRate, afLatency);
Chia-chi Yeh33005a92010-06-16 06:33:13 +0800159 return NO_ERROR;
160}
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800161
Michael Chana94fbb22018-04-24 14:31:19 +1000162// static
163bool AudioTrack::isDirectOutputSupported(const audio_config_base_t& config,
164 const audio_attributes_t& attributes) {
165 ALOGV("%s()", __FUNCTION__);
166 const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
167 if (aps == 0) return false;
168 return aps->isDirectOutputSupported(config, attributes);
169}
170
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800171// ---------------------------------------------------------------------------
172
Ray Essicked304702017-12-12 14:00:57 -0800173void AudioTrack::MediaMetrics::gather(const AudioTrack *track)
174{
Ray Essick88394302018-01-24 14:52:05 -0800175 // only if we're in a good state...
176 // XXX: shall we gather alternative info if failing?
177 const status_t lstatus = track->initCheck();
178 if (lstatus != NO_ERROR) {
Andy Hungfb8ede22018-09-12 19:03:24 -0700179 ALOGD("%s(): no metrics gathered, track status=%d", __func__, (int) lstatus);
Ray Essick88394302018-01-24 14:52:05 -0800180 return;
181 }
182
Andy Hungd0979812019-02-21 15:51:44 -0800183#define MM_PREFIX "android.media.audiotrack." // avoid cut-n-paste errors.
Ray Essicked304702017-12-12 14:00:57 -0800184
Andy Hungd0979812019-02-21 15:51:44 -0800185 // Java API 28 entries, do not change.
Ray Essickf27e9872019-12-07 06:28:46 -0800186 mMetricsItem->setCString(MM_PREFIX "streamtype", toString(track->streamType()).c_str());
187 mMetricsItem->setCString(MM_PREFIX "type",
Andy Hungd0979812019-02-21 15:51:44 -0800188 toString(track->mAttributes.content_type).c_str());
Ray Essickf27e9872019-12-07 06:28:46 -0800189 mMetricsItem->setCString(MM_PREFIX "usage", toString(track->mAttributes.usage).c_str());
Ray Essicked304702017-12-12 14:00:57 -0800190
Andy Hungd0979812019-02-21 15:51:44 -0800191 // Non-API entries, these can change due to a Java string mistake.
Ray Essickf27e9872019-12-07 06:28:46 -0800192 mMetricsItem->setInt32(MM_PREFIX "sampleRate", (int32_t)track->mSampleRate);
193 mMetricsItem->setInt64(MM_PREFIX "channelMask", (int64_t)track->mChannelMask);
Andy Hungd0979812019-02-21 15:51:44 -0800194 // Non-API entries, these can change.
Ray Essickf27e9872019-12-07 06:28:46 -0800195 mMetricsItem->setInt32(MM_PREFIX "portId", (int32_t)track->mPortId);
196 mMetricsItem->setCString(MM_PREFIX "encoding", toString(track->mFormat).c_str());
197 mMetricsItem->setInt32(MM_PREFIX "frameCount", (int32_t)track->mFrameCount);
198 mMetricsItem->setCString(MM_PREFIX "attributes", toString(track->mAttributes).c_str());
Ray Essicked304702017-12-12 14:00:57 -0800199}
200
Ray Essick88394302018-01-24 14:52:05 -0800201// hand the user a snapshot of the metrics.
Ray Essickf27e9872019-12-07 06:28:46 -0800202status_t AudioTrack::getMetrics(mediametrics::Item * &item)
Ray Essick88394302018-01-24 14:52:05 -0800203{
204 mMediaMetrics.gather(this);
Ray Essickf27e9872019-12-07 06:28:46 -0800205 mediametrics::Item *tmp = mMediaMetrics.dup();
Ray Essick88394302018-01-24 14:52:05 -0800206 if (tmp == nullptr) {
207 return BAD_VALUE;
208 }
209 item = tmp;
210 return NO_ERROR;
211}
Ray Essicked304702017-12-12 14:00:57 -0800212
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800213AudioTrack::AudioTrack()
Glenn Kasten87913512011-06-22 16:15:25 -0700214 : mStatus(NO_INIT),
Haynes Mathew George9b3359f2016-03-23 19:09:10 -0700215 mState(STATE_STOPPED),
John Grossman4ff14ba2012-02-08 16:37:41 -0800216 mPreviousPriority(ANDROID_PRIORITY_NORMAL),
Haynes Mathew George7064fd22014-01-08 13:59:53 -0800217 mPreviousSchedulingGroup(SP_DEFAULT),
Paul McLeanaa981192015-03-21 09:55:15 -0700218 mPausedPosition(0),
Eric Laurent20b9ef02016-12-05 11:03:16 -0800219 mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
jiabinf6eb4c32020-02-25 14:06:25 -0800220 mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE),
221 mAudioTrackCallback(new AudioTrackCallback())
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800222{
Jean-Michel Trivifaabb512014-06-11 16:55:06 -0700223 mAttributes.content_type = AUDIO_CONTENT_TYPE_UNKNOWN;
224 mAttributes.usage = AUDIO_USAGE_UNKNOWN;
225 mAttributes.flags = 0x0;
226 strcpy(mAttributes.tags, "");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800227}
228
229AudioTrack::AudioTrack(
Glenn Kastenfff6d712012-01-12 16:38:12 -0800230 audio_stream_type_t streamType,
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800231 uint32_t sampleRate,
Glenn Kastene1c39622012-01-04 09:36:37 -0800232 audio_format_t format,
Glenn Kasten28b76b32012-07-03 17:24:41 -0700233 audio_channel_mask_t channelMask,
Glenn Kastenbce50bf2014-02-27 15:29:51 -0800234 size_t frameCount,
Eric Laurent0ca3cf92012-04-18 09:24:29 -0700235 audio_output_flags_t flags,
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800236 callback_t cbf,
237 void* user,
Glenn Kastenea38ee72016-04-18 11:08:01 -0700238 int32_t notificationFrames,
Glenn Kastend848eb42016-03-08 13:42:11 -0800239 audio_session_t sessionId,
Richard Fitzgeraldad3af332013-03-25 16:54:37 +0000240 transfer_type transferType,
Marco Nelissen462fd2f2013-01-14 14:12:05 -0800241 const audio_offload_info_t *offloadInfo,
Andy Hung1f12a8a2016-11-07 16:10:30 -0800242 uid_t uid,
Jean-Michel Trivid9d7fa02014-06-24 08:01:46 -0700243 pid_t pid,
Ronghua Wufaeb0f22015-05-21 12:20:21 -0700244 const audio_attributes_t* pAttributes,
Andy Hungff874dc2016-04-11 16:49:09 -0700245 bool doNotReconnect,
jiabin156c6872017-10-06 09:47:15 -0700246 float maxRequiredSpeed,
247 audio_port_handle_t selectedDeviceId)
Glenn Kasten87913512011-06-22 16:15:25 -0700248 : mStatus(NO_INIT),
Haynes Mathew George9b3359f2016-03-23 19:09:10 -0700249 mState(STATE_STOPPED),
John Grossman4ff14ba2012-02-08 16:37:41 -0800250 mPreviousPriority(ANDROID_PRIORITY_NORMAL),
Haynes Mathew George7064fd22014-01-08 13:59:53 -0800251 mPreviousSchedulingGroup(SP_DEFAULT),
jiabinf6eb4c32020-02-25 14:06:25 -0800252 mPausedPosition(0),
253 mAudioTrackCallback(new AudioTrackCallback())
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800254{
François Gaffie393f0e02019-04-10 09:09:08 +0200255 mAttributes = AUDIO_ATTRIBUTES_INITIALIZER;
Ippei Murata5fa32ed2018-10-01 17:37:50 +0900256
Eric Laurentf32d7812017-11-30 14:44:07 -0800257 (void)set(streamType, sampleRate, format, channelMask,
Eric Laurenta514bdb2010-06-21 09:27:30 -0700258 frameCount, flags, cbf, user, notificationFrames,
Marco Nelissen462fd2f2013-01-14 14:12:05 -0800259 0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId, transferType,
jiabin156c6872017-10-06 09:47:15 -0700260 offloadInfo, uid, pid, pAttributes, doNotReconnect, maxRequiredSpeed, selectedDeviceId);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800261}
262
Andreas Huberc8139852012-01-18 10:51:55 -0800263AudioTrack::AudioTrack(
Glenn Kastenfff6d712012-01-12 16:38:12 -0800264 audio_stream_type_t streamType,
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800265 uint32_t sampleRate,
Glenn Kastene1c39622012-01-04 09:36:37 -0800266 audio_format_t format,
Glenn Kasten28b76b32012-07-03 17:24:41 -0700267 audio_channel_mask_t channelMask,
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800268 const sp<IMemory>& sharedBuffer,
Eric Laurent0ca3cf92012-04-18 09:24:29 -0700269 audio_output_flags_t flags,
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800270 callback_t cbf,
271 void* user,
Glenn Kastenea38ee72016-04-18 11:08:01 -0700272 int32_t notificationFrames,
Glenn Kastend848eb42016-03-08 13:42:11 -0800273 audio_session_t sessionId,
Richard Fitzgeraldad3af332013-03-25 16:54:37 +0000274 transfer_type transferType,
Marco Nelissen462fd2f2013-01-14 14:12:05 -0800275 const audio_offload_info_t *offloadInfo,
Andy Hung1f12a8a2016-11-07 16:10:30 -0800276 uid_t uid,
Jean-Michel Trivid9d7fa02014-06-24 08:01:46 -0700277 pid_t pid,
Ronghua Wufaeb0f22015-05-21 12:20:21 -0700278 const audio_attributes_t* pAttributes,
Andy Hungff874dc2016-04-11 16:49:09 -0700279 bool doNotReconnect,
280 float maxRequiredSpeed)
Glenn Kasten87913512011-06-22 16:15:25 -0700281 : mStatus(NO_INIT),
Haynes Mathew George9b3359f2016-03-23 19:09:10 -0700282 mState(STATE_STOPPED),
John Grossman4ff14ba2012-02-08 16:37:41 -0800283 mPreviousPriority(ANDROID_PRIORITY_NORMAL),
Haynes Mathew George7064fd22014-01-08 13:59:53 -0800284 mPreviousSchedulingGroup(SP_DEFAULT),
Paul McLeanaa981192015-03-21 09:55:15 -0700285 mPausedPosition(0),
jiabinf6eb4c32020-02-25 14:06:25 -0800286 mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
287 mAudioTrackCallback(new AudioTrackCallback())
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800288{
François Gaffie393f0e02019-04-10 09:09:08 +0200289 mAttributes = AUDIO_ATTRIBUTES_INITIALIZER;
Ippei Murata5fa32ed2018-10-01 17:37:50 +0900290
Eric Laurentf32d7812017-11-30 14:44:07 -0800291 (void)set(streamType, sampleRate, format, channelMask,
Glenn Kasten17a736c2012-02-14 08:52:15 -0800292 0 /*frameCount*/, flags, cbf, user, notificationFrames,
Marco Nelissend457c972014-02-11 08:47:07 -0800293 sharedBuffer, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo,
Andy Hungff874dc2016-04-11 16:49:09 -0700294 uid, pid, pAttributes, doNotReconnect, maxRequiredSpeed);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800295}
296
297AudioTrack::~AudioTrack()
298{
Ray Essicked304702017-12-12 14:00:57 -0800299 // pull together the numbers, before we clean up our structures
300 mMediaMetrics.gather(this);
301
Andy Hungb68f5eb2019-12-03 16:49:17 -0800302 mediametrics::LogItem(mMetricsId)
303 .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_DTOR)
304 .set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
305 .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)mStatus)
306 .record();
307
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800308 if (mStatus == NO_ERROR) {
309 // Make sure that callback function exits in the case where
310 // it is looping on buffer full condition in obtainBuffer().
311 // Otherwise the callback thread will never exit.
312 stop();
313 if (mAudioTrackThread != 0) {
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100314 mProxy->interrupt();
Glenn Kasten3acbd052012-02-28 10:39:56 -0800315 mAudioTrackThread->requestExit(); // see comment in AudioTrack.h
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800316 mAudioTrackThread->requestExitAndWait();
317 mAudioTrackThread.clear();
318 }
Eric Laurent296fb132015-05-01 11:38:42 -0700319 // No lock here: worst case we remove a NULL callback which will be a nop
320 if (mDeviceCallback != 0 && mOutput != AUDIO_IO_HANDLE_NONE) {
Eric Laurent09f1ed22019-04-24 17:45:17 -0700321 AudioSystem::removeAudioDeviceCallback(this, mOutput, mPortId);
Eric Laurent296fb132015-05-01 11:38:42 -0700322 }
Marco Nelissenf8880202014-11-14 07:58:25 -0800323 IInterface::asBinder(mAudioTrack)->unlinkToDeath(mDeathNotifier, this);
Glenn Kasten53cec222013-08-29 09:01:02 -0700324 mAudioTrack.clear();
Eric Laurent3bcffa12014-06-12 18:38:45 -0700325 mCblkMemory.clear();
326 mSharedBuffer.clear();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800327 IPCThreadState::self()->flushCommands();
Andy Hungfb8ede22018-09-12 19:03:24 -0700328 ALOGV("%s(%d), releasing session id %d from %d on behalf of %d",
Eric Laurent973db022018-11-20 14:54:31 -0800329 __func__, mPortId,
Glenn Kasten4c36d6f2015-03-20 09:05:01 -0700330 mSessionId, IPCThreadState::self()->getCallingPid(), mClientPid);
Marco Nelissend457c972014-02-11 08:47:07 -0800331 AudioSystem::releaseAudioSessionId(mSessionId, mClientPid);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800332 }
333}
334
335status_t AudioTrack::set(
Glenn Kastenfff6d712012-01-12 16:38:12 -0800336 audio_stream_type_t streamType,
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800337 uint32_t sampleRate,
Glenn Kastene1c39622012-01-04 09:36:37 -0800338 audio_format_t format,
Glenn Kasten28b76b32012-07-03 17:24:41 -0700339 audio_channel_mask_t channelMask,
Glenn Kastenbce50bf2014-02-27 15:29:51 -0800340 size_t frameCount,
Eric Laurent0ca3cf92012-04-18 09:24:29 -0700341 audio_output_flags_t flags,
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800342 callback_t cbf,
343 void* user,
Glenn Kastenea38ee72016-04-18 11:08:01 -0700344 int32_t notificationFrames,
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800345 const sp<IMemory>& sharedBuffer,
Eric Laurentbe916aa2010-06-01 23:49:17 -0700346 bool threadCanCallJava,
Glenn Kastend848eb42016-03-08 13:42:11 -0800347 audio_session_t sessionId,
Richard Fitzgeraldad3af332013-03-25 16:54:37 +0000348 transfer_type transferType,
Marco Nelissen462fd2f2013-01-14 14:12:05 -0800349 const audio_offload_info_t *offloadInfo,
Andy Hung1f12a8a2016-11-07 16:10:30 -0800350 uid_t uid,
Jean-Michel Trivifaabb512014-06-11 16:55:06 -0700351 pid_t pid,
Ronghua Wufaeb0f22015-05-21 12:20:21 -0700352 const audio_attributes_t* pAttributes,
Andy Hungff874dc2016-04-11 16:49:09 -0700353 bool doNotReconnect,
jiabin156c6872017-10-06 09:47:15 -0700354 float maxRequiredSpeed,
355 audio_port_handle_t selectedDeviceId)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800356{
Eric Laurentf32d7812017-11-30 14:44:07 -0800357 status_t status;
358 uint32_t channelCount;
359 pid_t callingPid;
360 pid_t myPid;
361
Eric Laurent973db022018-11-20 14:54:31 -0800362 // Note mPortId is not valid until the track is created, so omit mPortId in ALOG for set.
Andy Hungfb8ede22018-09-12 19:03:24 -0700363 ALOGV("%s(): streamType %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, "
Glenn Kastenea38ee72016-04-18 11:08:01 -0700364 "flags #%x, notificationFrames %d, sessionId %d, transferType %d, uid %d, pid %d",
Andy Hungfb8ede22018-09-12 19:03:24 -0700365 __func__,
Glenn Kastenbce50bf2014-02-27 15:29:51 -0800366 streamType, sampleRate, format, channelMask, frameCount, flags, notificationFrames,
Glenn Kasten4c36d6f2015-03-20 09:05:01 -0700367 sessionId, transferType, uid, pid);
Glenn Kasten86f04662014-02-24 15:13:05 -0800368
Phil Burk33ff89b2015-11-30 11:16:01 -0800369 mThreadCanCallJava = threadCanCallJava;
jiabin156c6872017-10-06 09:47:15 -0700370 mSelectedDeviceId = selectedDeviceId;
Eric Laurent21da6472017-11-09 16:29:26 -0800371 mSessionId = sessionId;
Phil Burk33ff89b2015-11-30 11:16:01 -0800372
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800373 switch (transferType) {
374 case TRANSFER_DEFAULT:
375 if (sharedBuffer != 0) {
376 transferType = TRANSFER_SHARED;
377 } else if (cbf == NULL || threadCanCallJava) {
378 transferType = TRANSFER_SYNC;
379 } else {
380 transferType = TRANSFER_CALLBACK;
381 }
382 break;
383 case TRANSFER_CALLBACK:
Jean-Michel Trivif4158d82018-09-25 12:43:58 -0700384 case TRANSFER_SYNC_NOTIF_CALLBACK:
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800385 if (cbf == NULL || sharedBuffer != 0) {
Jean-Michel Trivif4158d82018-09-25 12:43:58 -0700386 ALOGE("%s(): Transfer type %s but cbf == NULL || sharedBuffer != 0",
387 convertTransferToText(transferType), __func__);
Eric Laurentf32d7812017-11-30 14:44:07 -0800388 status = BAD_VALUE;
389 goto exit;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800390 }
391 break;
392 case TRANSFER_OBTAIN:
393 case TRANSFER_SYNC:
394 if (sharedBuffer != 0) {
Andy Hungfb8ede22018-09-12 19:03:24 -0700395 ALOGE("%s(): Transfer type TRANSFER_OBTAIN but sharedBuffer != 0", __func__);
Eric Laurentf32d7812017-11-30 14:44:07 -0800396 status = BAD_VALUE;
397 goto exit;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800398 }
399 break;
400 case TRANSFER_SHARED:
401 if (sharedBuffer == 0) {
Andy Hungfb8ede22018-09-12 19:03:24 -0700402 ALOGE("%s(): Transfer type TRANSFER_SHARED but sharedBuffer == 0", __func__);
Eric Laurentf32d7812017-11-30 14:44:07 -0800403 status = BAD_VALUE;
404 goto exit;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800405 }
406 break;
407 default:
Andy Hungfb8ede22018-09-12 19:03:24 -0700408 ALOGE("%s(): Invalid transfer type %d",
409 __func__, transferType);
Eric Laurentf32d7812017-11-30 14:44:07 -0800410 status = BAD_VALUE;
411 goto exit;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800412 }
Glenn Kastendd5f4c82014-01-13 10:26:32 -0800413 mSharedBuffer = sharedBuffer;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800414 mTransfer = transferType;
Ronghua Wufaeb0f22015-05-21 12:20:21 -0700415 mDoNotReconnect = doNotReconnect;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800416
Andy Hungfb8ede22018-09-12 19:03:24 -0700417 ALOGV_IF(sharedBuffer != 0, "%s(): sharedBuffer: %p, size: %zu",
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -0700418 __func__, sharedBuffer->unsecurePointer(), sharedBuffer->size());
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800419
Andy Hungfb8ede22018-09-12 19:03:24 -0700420 ALOGV("%s(): streamType %d frameCount %zu flags %04x",
421 __func__, streamType, frameCount, flags);
Eric Laurent1a9ed112012-03-20 18:36:01 -0700422
Glenn Kasten53cec222013-08-29 09:01:02 -0700423 // invariant that mAudioTrack != 0 is true only after set() returns successfully
Eric Laurent1dd70b92009-04-21 07:56:33 -0700424 if (mAudioTrack != 0) {
Andy Hungfb8ede22018-09-12 19:03:24 -0700425 ALOGE("%s(): Track already in use", __func__);
Eric Laurentf32d7812017-11-30 14:44:07 -0800426 status = INVALID_OPERATION;
427 goto exit;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800428 }
429
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800430 // handle default values first.
Eric Laurente83b55d2014-11-14 10:06:21 -0800431 if (streamType == AUDIO_STREAM_DEFAULT) {
Dima Zavinfce7a472011-04-19 22:30:36 -0700432 streamType = AUDIO_STREAM_MUSIC;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800433 }
Jean-Michel Trivifaabb512014-06-11 16:55:06 -0700434 if (pAttributes == NULL) {
Eric Laurent223fd5c2014-11-11 13:43:36 -0800435 if (uint32_t(streamType) >= AUDIO_STREAM_PUBLIC_CNT) {
Andy Hungfb8ede22018-09-12 19:03:24 -0700436 ALOGE("%s(): Invalid stream type %d", __func__, streamType);
Eric Laurentf32d7812017-11-30 14:44:07 -0800437 status = BAD_VALUE;
438 goto exit;
Jean-Michel Trivifaabb512014-06-11 16:55:06 -0700439 }
Jean-Michel Trivifaabb512014-06-11 16:55:06 -0700440 mStreamType = streamType;
Eric Laurente83b55d2014-11-14 10:06:21 -0800441
Jean-Michel Trivifaabb512014-06-11 16:55:06 -0700442 } else {
Jean-Michel Trivifaabb512014-06-11 16:55:06 -0700443 // stream type shouldn't be looked at, this track has audio attributes
444 memcpy(&mAttributes, pAttributes, sizeof(audio_attributes_t));
Andy Hungfb8ede22018-09-12 19:03:24 -0700445 ALOGV("%s(): Building AudioTrack with attributes:"
446 " usage=%d content=%d flags=0x%x tags=[%s]",
447 __func__,
448 mAttributes.usage, mAttributes.content_type, mAttributes.flags, mAttributes.tags);
Eric Laurente83b55d2014-11-14 10:06:21 -0800449 mStreamType = AUDIO_STREAM_DEFAULT;
François Gaffie58d4be52018-11-06 15:30:12 +0100450 audio_flags_to_audio_output_flags(mAttributes.flags, &flags);
Glenn Kastendd5f4c82014-01-13 10:26:32 -0800451 }
Glenn Kastenea7939a2012-03-14 12:56:26 -0700452
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800453 // these below should probably come from the audioFlinger too...
Glenn Kastene1c39622012-01-04 09:36:37 -0800454 if (format == AUDIO_FORMAT_DEFAULT) {
Dima Zavinfce7a472011-04-19 22:30:36 -0700455 format = AUDIO_FORMAT_PCM_16_BIT;
Phil Burkfdb3c072016-02-09 10:47:02 -0800456 } else if (format == AUDIO_FORMAT_IEC61937) { // HDMI pass-through?
457 mAttributes.flags |= AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800458 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800459
460 // validate parameters
Dima Zavinfce7a472011-04-19 22:30:36 -0700461 if (!audio_is_valid_format(format)) {
Andy Hungfb8ede22018-09-12 19:03:24 -0700462 ALOGE("%s(): Invalid format %#x", __func__, format);
Eric Laurentf32d7812017-11-30 14:44:07 -0800463 status = BAD_VALUE;
464 goto exit;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800465 }
Glenn Kastendd5f4c82014-01-13 10:26:32 -0800466 mFormat = format;
Eric Laurentc2f1f072009-07-17 12:17:14 -0700467
Glenn Kasten8ba90322013-10-30 11:29:27 -0700468 if (!audio_is_output_channel(channelMask)) {
Andy Hungfb8ede22018-09-12 19:03:24 -0700469 ALOGE("%s(): Invalid channel mask %#x", __func__, channelMask);
Eric Laurentf32d7812017-11-30 14:44:07 -0800470 status = BAD_VALUE;
471 goto exit;
Glenn Kasten8ba90322013-10-30 11:29:27 -0700472 }
Glenn Kastene3247bf2014-02-24 15:19:07 -0800473 mChannelMask = channelMask;
Eric Laurentf32d7812017-11-30 14:44:07 -0800474 channelCount = audio_channel_count_from_out_mask(channelMask);
Glenn Kastene3247bf2014-02-24 15:19:07 -0800475 mChannelCount = channelCount;
Glenn Kasten8ba90322013-10-30 11:29:27 -0700476
Eric Laurentc2f1f072009-07-17 12:17:14 -0700477 // force direct flag if format is not linear PCM
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100478 // or offload was requested
479 if ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)
480 || !audio_is_linear_pcm(format)) {
481 ALOGV( (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)
Andy Hungfb8ede22018-09-12 19:03:24 -0700482 ? "%s(): Offload request, forcing to Direct Output"
483 : "%s(): Not linear PCM, forcing to Direct Output",
484 __func__);
Eric Laurent0ca3cf92012-04-18 09:24:29 -0700485 flags = (audio_output_flags_t)
Glenn Kasten3acbd052012-02-28 10:39:56 -0800486 // FIXME why can't we allow direct AND fast?
Eric Laurent0ca3cf92012-04-18 09:24:29 -0700487 ((flags | AUDIO_OUTPUT_FLAG_DIRECT) & ~AUDIO_OUTPUT_FLAG_FAST);
Eric Laurentc2f1f072009-07-17 12:17:14 -0700488 }
489
Eric Laurentd1f69b02014-12-15 14:33:13 -0800490 // force direct flag if HW A/V sync requested
491 if ((flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC) != 0) {
492 flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_DIRECT);
493 }
494
Glenn Kastenb7730382014-04-30 15:50:31 -0700495 if (flags & AUDIO_OUTPUT_FLAG_DIRECT) {
Phil Burkfdb3c072016-02-09 10:47:02 -0800496 if (audio_has_proportional_frames(format)) {
Glenn Kastenb7730382014-04-30 15:50:31 -0700497 mFrameSize = channelCount * audio_bytes_per_sample(format);
498 } else {
499 mFrameSize = sizeof(uint8_t);
500 }
Glenn Kastene3aa6592012-12-04 12:22:46 -0800501 } else {
Phil Burkfdb3c072016-02-09 10:47:02 -0800502 ALOG_ASSERT(audio_has_proportional_frames(format));
Glenn Kastenb7730382014-04-30 15:50:31 -0700503 mFrameSize = channelCount * audio_bytes_per_sample(format);
Glenn Kastenb7730382014-04-30 15:50:31 -0700504 // createTrack will return an error if PCM format is not supported by server,
505 // so no need to check for specific PCM formats here
Glenn Kastene3aa6592012-12-04 12:22:46 -0800506 }
507
Eric Laurent0d6db582014-11-12 18:39:44 -0800508 // sampling rate must be specified for direct outputs
509 if (sampleRate == 0 && (flags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
Eric Laurentf32d7812017-11-30 14:44:07 -0800510 status = BAD_VALUE;
511 goto exit;
Eric Laurent0d6db582014-11-12 18:39:44 -0800512 }
513 mSampleRate = sampleRate;
Lajos Molnar3a474aa2015-04-24 17:10:07 -0700514 mOriginalSampleRate = sampleRate;
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700515 mPlaybackRate = AUDIO_PLAYBACK_RATE_DEFAULT;
Andy Hungff874dc2016-04-11 16:49:09 -0700516 // 1.0 <= mMaxRequiredSpeed <= AUDIO_TIMESTRETCH_SPEED_MAX
517 mMaxRequiredSpeed = min(max(maxRequiredSpeed, 1.0f), AUDIO_TIMESTRETCH_SPEED_MAX);
Eric Laurent0d6db582014-11-12 18:39:44 -0800518
Glenn Kastenb5ccb2d2014-01-13 14:42:43 -0800519 // Make copy of input parameter offloadInfo so that in the future:
520 // (a) createTrack_l doesn't need it as an input parameter
521 // (b) we can support re-creation of offloaded tracks
522 if (offloadInfo != NULL) {
523 mOffloadInfoCopy = *offloadInfo;
524 mOffloadInfo = &mOffloadInfoCopy;
525 } else {
526 mOffloadInfo = NULL;
Eric Laurent20b9ef02016-12-05 11:03:16 -0800527 memset(&mOffloadInfoCopy, 0, sizeof(audio_offload_info_t));
Glenn Kastenb5ccb2d2014-01-13 14:42:43 -0800528 }
529
Glenn Kasten66e46352014-01-16 17:44:23 -0800530 mVolume[AUDIO_INTERLEAVE_LEFT] = 1.0f;
531 mVolume[AUDIO_INTERLEAVE_RIGHT] = 1.0f;
Glenn Kasten05632a52012-01-03 14:22:33 -0800532 mSendLevel = 0.0f;
Glenn Kasten396fabd2014-01-08 08:54:23 -0800533 // mFrameCount is initialized in createTrack_l
Glenn Kastenb6037442012-11-14 13:42:25 -0800534 mReqFrameCount = frameCount;
Glenn Kastenea38ee72016-04-18 11:08:01 -0700535 if (notificationFrames >= 0) {
536 mNotificationFramesReq = notificationFrames;
537 mNotificationsPerBufferReq = 0;
538 } else {
539 if (!(flags & AUDIO_OUTPUT_FLAG_FAST)) {
Andy Hungfb8ede22018-09-12 19:03:24 -0700540 ALOGE("%s(): notificationFrames=%d not permitted for non-fast track",
541 __func__, notificationFrames);
Eric Laurentf32d7812017-11-30 14:44:07 -0800542 status = BAD_VALUE;
543 goto exit;
Glenn Kastenea38ee72016-04-18 11:08:01 -0700544 }
545 if (frameCount > 0) {
Andy Hungfb8ede22018-09-12 19:03:24 -0700546 ALOGE("%s(): notificationFrames=%d not permitted with non-zero frameCount=%zu",
547 __func__, notificationFrames, frameCount);
Eric Laurentf32d7812017-11-30 14:44:07 -0800548 status = BAD_VALUE;
549 goto exit;
Glenn Kastenea38ee72016-04-18 11:08:01 -0700550 }
551 mNotificationFramesReq = 0;
552 const uint32_t minNotificationsPerBuffer = 1;
553 const uint32_t maxNotificationsPerBuffer = 8;
554 mNotificationsPerBufferReq = min(maxNotificationsPerBuffer,
555 max((uint32_t) -notificationFrames, minNotificationsPerBuffer));
556 ALOGW_IF(mNotificationsPerBufferReq != (uint32_t) -notificationFrames,
Andy Hungfb8ede22018-09-12 19:03:24 -0700557 "%s(): notificationFrames=%d clamped to the range -%u to -%u",
558 __func__,
Glenn Kastenea38ee72016-04-18 11:08:01 -0700559 notificationFrames, minNotificationsPerBuffer, maxNotificationsPerBuffer);
560 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800561 mNotificationFramesAct = 0;
Eric Laurentf32d7812017-11-30 14:44:07 -0800562 callingPid = IPCThreadState::self()->getCallingPid();
563 myPid = getpid();
564 if (uid == AUDIO_UID_INVALID || (callingPid != myPid)) {
Marco Nelissen462fd2f2013-01-14 14:12:05 -0800565 mClientUid = IPCThreadState::self()->getCallingUid();
566 } else {
567 mClientUid = uid;
568 }
Eric Laurentf32d7812017-11-30 14:44:07 -0800569 if (pid == -1 || (callingPid != myPid)) {
570 mClientPid = callingPid;
Marco Nelissend457c972014-02-11 08:47:07 -0800571 } else {
572 mClientPid = pid;
573 }
Eric Laurent2beeb502010-07-16 07:43:46 -0700574 mAuxEffectId = 0;
Haynes Mathew Georgeae34ed22016-01-28 11:58:39 -0800575 mOrigFlags = mFlags = flags;
Glenn Kasten4a4a0952012-03-19 11:38:14 -0700576 mCbf = cbf;
Eric Laurentbe916aa2010-06-01 23:49:17 -0700577
Glenn Kastena997e7a2012-08-07 09:44:19 -0700578 if (cbf != NULL) {
Andy Hungca353672019-03-06 11:54:38 -0800579 mAudioTrackThread = new AudioTrackThread(*this);
Glenn Kastena997e7a2012-08-07 09:44:19 -0700580 mAudioTrackThread->run("AudioTrack", ANDROID_PRIORITY_AUDIO, 0 /*stack*/);
Glenn Kastenbfd31842015-03-20 09:01:44 -0700581 // thread begins in paused state, and will not reference us until start()
Glenn Kastena997e7a2012-08-07 09:44:19 -0700582 }
583
Eric Laurent34f1d8e2009-11-04 08:27:26 -0800584 // create the IAudioTrack
Francois Gaffie24a9fb02019-01-18 17:51:34 +0100585 {
586 AutoMutex lock(mLock);
587 status = createTrack_l();
588 }
Glenn Kastena997e7a2012-08-07 09:44:19 -0700589 if (status != NO_ERROR) {
590 if (mAudioTrackThread != 0) {
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100591 mAudioTrackThread->requestExit(); // see comment in AudioTrack.h
592 mAudioTrackThread->requestExitAndWait();
Glenn Kastena997e7a2012-08-07 09:44:19 -0700593 mAudioTrackThread.clear();
594 }
Eric Laurentf32d7812017-11-30 14:44:07 -0800595 goto exit;
Glenn Kasten5d464eb2012-06-22 17:19:53 -0700596 }
597
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800598 mUserData = user;
Andy Hung4ede21d2014-12-12 15:37:34 -0800599 mLoopCount = 0;
600 mLoopStart = 0;
601 mLoopEnd = 0;
Andy Hung53c3b5f2014-12-15 16:42:05 -0800602 mLoopCountNotified = 0;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800603 mMarkerPosition = 0;
Jean-Michel Trivi2c22aeb2009-03-24 18:11:07 -0700604 mMarkerReached = false;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800605 mNewPosition = 0;
606 mUpdatePeriod = 0;
Glenn Kasten200092b2014-08-15 15:13:30 -0700607 mPosition = 0;
608 mReleased = 0;
Andy Hungffa36952017-08-17 10:41:51 -0700609 mStartNs = 0;
610 mStartFromZeroUs = 0;
Andy Hung8b0bfd92019-12-23 13:11:11 -0800611 AudioSystem::acquireAudioSessionId(mSessionId, mClientPid, mClientUid);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800612 mSequence = 1;
613 mObservedSequence = mSequence;
614 mInUnderrun = false;
Phil Burk1b420972015-04-22 10:52:21 -0700615 mPreviousTimestampValid = false;
Andy Hungc8e09c62015-06-03 23:43:36 -0700616 mTimestampStartupGlitchReported = false;
Andy Hungcf3b7152019-04-19 18:29:21 -0700617 mTimestampRetrogradePositionReported = false;
618 mTimestampRetrogradeTimeReported = false;
619 mTimestampStallReported = false;
620 mTimestampStaleTimeReported = false;
Andy Hungb01faa32016-04-27 12:51:32 -0700621 mPreviousLocation = ExtendedTimestamp::LOCATION_INVALID;
Andy Hung65ffdfc2016-10-10 15:52:11 -0700622 mStartTs.mPosition = 0;
Phil Burk2812d9e2016-01-04 10:34:30 -0800623 mUnderrunCountOffset = 0;
Andy Hungea2b9c02016-02-12 17:06:53 -0800624 mFramesWritten = 0;
625 mFramesWrittenServerOffset = 0;
Andy Hungf20a4e92016-08-15 19:10:34 -0700626 mFramesWrittenAtRestore = -1; // -1 is a unique initializer.
Ivan Lozano8cf3a072017-08-09 09:01:33 -0700627 mVolumeHandler = new media::VolumeHandler();
Eric Laurentf32d7812017-11-30 14:44:07 -0800628
629exit:
630 mStatus = status;
631 return status;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800632}
633
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800634// -------------------------------------------------------------------------
635
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100636status_t AudioTrack::start()
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800637{
Andy Hungb68f5eb2019-12-03 16:49:17 -0800638 const int64_t beginNs = systemTime();
Eric Laurentf5aafb22010-11-18 08:40:16 -0800639 AutoMutex lock(mLock);
Andy Hungb68f5eb2019-12-03 16:49:17 -0800640
641 status_t status = NO_ERROR; // logged: make sure to set this before returning.
Andy Hung06a730b2020-04-09 13:28:31 -0700642 mediametrics::Defer defer([&] {
Andy Hungb68f5eb2019-12-03 16:49:17 -0800643 mediametrics::LogItem(mMetricsId)
644 .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_START)
645 .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
646 .set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
647 .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)status)
648 .record(); });
649
Eric Laurent973db022018-11-20 14:54:31 -0800650 ALOGV("%s(%d): prior state:%s", __func__, mPortId, stateToString(mState));
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100651
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800652 if (mState == STATE_ACTIVE) {
Andy Hungb68f5eb2019-12-03 16:49:17 -0800653 status = INVALID_OPERATION;
654 return status;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800655 }
656
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800657 mInUnderrun = true;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800658
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800659 State previousState = mState;
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100660 if (previousState == STATE_PAUSED_STOPPING) {
661 mState = STATE_STOPPING;
662 } else {
663 mState = STATE_ACTIVE;
664 }
Glenn Kasten200092b2014-08-15 15:13:30 -0700665 (void) updateAndGetPosition_l();
Andy Hung65ffdfc2016-10-10 15:52:11 -0700666
667 // save start timestamp
668 if (isOffloadedOrDirect_l()) {
669 if (getTimestamp_l(mStartTs) != OK) {
670 mStartTs.mPosition = 0;
671 }
672 } else {
673 if (getTimestamp_l(&mStartEts) != OK) {
674 mStartEts.clear();
675 }
676 }
Andy Hungffa36952017-08-17 10:41:51 -0700677 mStartNs = systemTime(); // save this for timestamp adjustment after starting.
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800678 if (previousState == STATE_STOPPED || previousState == STATE_FLUSHED) {
679 // reset current position as seen by client to 0
Glenn Kasten200092b2014-08-15 15:13:30 -0700680 mPosition = 0;
Phil Burk1b420972015-04-22 10:52:21 -0700681 mPreviousTimestampValid = false;
Andy Hungc8e09c62015-06-03 23:43:36 -0700682 mTimestampStartupGlitchReported = false;
Andy Hungcf3b7152019-04-19 18:29:21 -0700683 mTimestampRetrogradePositionReported = false;
684 mTimestampRetrogradeTimeReported = false;
685 mTimestampStallReported = false;
686 mTimestampStaleTimeReported = false;
Andy Hungb01faa32016-04-27 12:51:32 -0700687 mPreviousLocation = ExtendedTimestamp::LOCATION_INVALID;
Phil Burk1b420972015-04-22 10:52:21 -0700688
Andy Hung65ffdfc2016-10-10 15:52:11 -0700689 if (!isOffloadedOrDirect_l()
690 && mStartEts.mTimeNs[ExtendedTimestamp::LOCATION_SERVER] > 0) {
Andy Hunge1e98462016-04-12 10:18:51 -0700691 // Server side has consumed something, but is it finished consuming?
692 // It is possible since flush and stop are asynchronous that the server
693 // is still active at this point.
Andy Hungfb8ede22018-09-12 19:03:24 -0700694 ALOGV("%s(%d): server read:%lld cumulative flushed:%lld client written:%lld",
Eric Laurent973db022018-11-20 14:54:31 -0800695 __func__, mPortId,
Andy Hunge1e98462016-04-12 10:18:51 -0700696 (long long)(mFramesWrittenServerOffset
Andy Hung65ffdfc2016-10-10 15:52:11 -0700697 + mStartEts.mPosition[ExtendedTimestamp::LOCATION_SERVER]),
698 (long long)mStartEts.mFlushed,
Andy Hunge1e98462016-04-12 10:18:51 -0700699 (long long)mFramesWritten);
Andy Hungc4e60eb2017-09-06 11:14:57 -0700700 // mStartEts is already adjusted by mFramesWrittenServerOffset, so we delta adjust.
701 mFramesWrittenServerOffset -= mStartEts.mPosition[ExtendedTimestamp::LOCATION_SERVER];
Andy Hung61be8412015-10-06 10:51:09 -0700702 }
Andy Hunge1e98462016-04-12 10:18:51 -0700703 mFramesWritten = 0;
704 mProxy->clearTimestamp(); // need new server push for valid timestamp
705 mMarkerReached = false;
Andy Hung61be8412015-10-06 10:51:09 -0700706
Andy Hung7f1bc8a2014-09-12 14:43:11 -0700707 // For offloaded tracks, we don't know if the hardware counters are really zero here,
708 // since the flush is asynchronous and stop may not fully drain.
709 // We save the time when the track is started to later verify whether
710 // the counters are realistic (i.e. start from zero after this time).
Andy Hungffa36952017-08-17 10:41:51 -0700711 mStartFromZeroUs = mStartNs / 1000;
Andy Hung7f1bc8a2014-09-12 14:43:11 -0700712
Eric Laurentec9a0322013-08-28 10:23:01 -0700713 // force refresh of remaining frames by processAudioBuffer() as last
714 // write before stop could be partial.
715 mRefreshRemaining = true;
Tomoharu Kasahara6e8bf982017-06-09 16:17:33 +0900716
717 // for static track, clear the old flags when starting from stopped state
718 if (mSharedBuffer != 0) {
719 android_atomic_and(
720 ~(CBLK_LOOP_CYCLE | CBLK_LOOP_FINAL | CBLK_BUFFER_END),
721 &mCblk->mFlags);
722 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800723 }
Glenn Kasten200092b2014-08-15 15:13:30 -0700724 mNewPosition = mPosition + mUpdatePeriod;
Andy Hung4be3b832016-10-13 17:51:43 -0700725 int32_t flags = android_atomic_and(~(CBLK_STREAM_END_DONE | CBLK_DISABLED), &mCblk->mFlags);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800726
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800727 if (!(flags & CBLK_INVALID)) {
728 status = mAudioTrack->start();
729 if (status == DEAD_OBJECT) {
730 flags |= CBLK_INVALID;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800731 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800732 }
733 if (flags & CBLK_INVALID) {
734 status = restoreTrack_l("start");
735 }
736
Andy Hung79629f02016-03-24 13:57:40 -0700737 // resume or pause the callback thread as needed.
738 sp<AudioTrackThread> t = mAudioTrackThread;
739 if (status == NO_ERROR) {
740 if (t != 0) {
741 if (previousState == STATE_STOPPING) {
742 mProxy->interrupt();
743 } else {
744 t->resume();
745 }
746 } else {
747 mPreviousPriority = getpriority(PRIO_PROCESS, 0);
748 get_sched_policy(0, &mPreviousSchedulingGroup);
749 androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
750 }
Andy Hung39399b62017-04-21 15:07:45 -0700751
752 // Start our local VolumeHandler for restoration purposes.
753 mVolumeHandler->setStarted();
Andy Hung79629f02016-03-24 13:57:40 -0700754 } else {
Eric Laurent973db022018-11-20 14:54:31 -0800755 ALOGE("%s(%d): status %d", __func__, mPortId, status);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800756 mState = previousState;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800757 if (t != 0) {
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100758 if (previousState != STATE_STOPPING) {
759 t->pause();
760 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800761 } else {
Glenn Kasten87913512011-06-22 16:15:25 -0700762 setpriority(PRIO_PROCESS, 0, mPreviousPriority);
Glenn Kastena6364332012-04-19 09:35:04 -0700763 set_sched_policy(0, mPreviousSchedulingGroup);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800764 }
765 }
766
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100767 return status;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800768}
769
770void AudioTrack::stop()
771{
Andy Hungb68f5eb2019-12-03 16:49:17 -0800772 const int64_t beginNs = systemTime();
773
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800774 AutoMutex lock(mLock);
Andy Hung06a730b2020-04-09 13:28:31 -0700775 mediametrics::Defer defer([&]() {
Andy Hungb68f5eb2019-12-03 16:49:17 -0800776 mediametrics::LogItem(mMetricsId)
777 .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_STOP)
778 .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
779 .set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
Phil Burka9876702020-04-20 18:16:15 -0700780 .record();
781 logBufferSizeUnderruns();
782 });
Andy Hungb68f5eb2019-12-03 16:49:17 -0800783
Eric Laurent973db022018-11-20 14:54:31 -0800784 ALOGV("%s(%d): prior state:%s", __func__, mPortId, stateToString(mState));
Andy Hungfb8ede22018-09-12 19:03:24 -0700785
Glenn Kasten397edb32013-08-30 15:10:13 -0700786 if (mState != STATE_ACTIVE && mState != STATE_PAUSED) {
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800787 return;
788 }
789
Glenn Kasten23a75452014-01-13 10:37:17 -0800790 if (isOffloaded_l()) {
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100791 mState = STATE_STOPPING;
792 } else {
793 mState = STATE_STOPPED;
Andy Hung2148bf02016-11-28 19:01:02 -0800794 ALOGD_IF(mSharedBuffer == nullptr,
Eric Laurent973db022018-11-20 14:54:31 -0800795 "%s(%d): called with %u frames delivered", __func__, mPortId, mReleased.value());
Andy Hungc2813e52014-10-16 17:54:34 -0700796 mReleased = 0;
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100797 }
798
Andy Hung1d3556d2018-03-29 16:30:14 -0700799 mProxy->stop(); // notify server not to read beyond current client position until start().
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800800 mProxy->interrupt();
801 mAudioTrack->stop();
Andy Hung61be8412015-10-06 10:51:09 -0700802
803 // Note: legacy handling - stop does not clear playback marker
804 // and periodic update counter, but flush does for streaming tracks.
Andy Hung9b461582014-12-01 17:56:29 -0800805
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800806 if (mSharedBuffer != 0) {
Andy Hung9b461582014-12-01 17:56:29 -0800807 // clear buffer position and loop count.
Andy Hung9b461582014-12-01 17:56:29 -0800808 mStaticProxy->setBufferPositionAndLoop(0 /* position */,
809 0 /* loopStart */, 0 /* loopEnd */, 0 /* loopCount */);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800810 }
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100811
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800812 sp<AudioTrackThread> t = mAudioTrackThread;
813 if (t != 0) {
Glenn Kasten23a75452014-01-13 10:37:17 -0800814 if (!isOffloaded_l()) {
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100815 t->pause();
Jean-Michel Trivia60e9a22018-11-15 16:13:36 -0800816 } else if (mTransfer == TRANSFER_SYNC_NOTIF_CALLBACK) {
Jean-Michel Trivi0248a2a2018-11-21 10:05:57 -0800817 // causes wake up of the playback thread, that will callback the client for
818 // EVENT_STREAM_END in processAudioBuffer()
819 t->wake();
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100820 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800821 } else {
822 setpriority(PRIO_PROCESS, 0, mPreviousPriority);
823 set_sched_policy(0, mPreviousSchedulingGroup);
824 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800825}
826
827bool AudioTrack::stopped() const
828{
Glenn Kasten9a2aaf92012-01-03 09:42:47 -0800829 AutoMutex lock(mLock);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800830 return mState != STATE_ACTIVE;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800831}
832
833void AudioTrack::flush()
834{
Andy Hungb68f5eb2019-12-03 16:49:17 -0800835 const int64_t beginNs = systemTime();
Andy Hungfb8ede22018-09-12 19:03:24 -0700836 AutoMutex lock(mLock);
Andy Hung06a730b2020-04-09 13:28:31 -0700837 mediametrics::Defer defer([&]() {
Andy Hungb68f5eb2019-12-03 16:49:17 -0800838 mediametrics::LogItem(mMetricsId)
839 .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_FLUSH)
840 .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
841 .set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
842 .record(); });
843
Eric Laurent973db022018-11-20 14:54:31 -0800844 ALOGV("%s(%d): prior state:%s", __func__, mPortId, stateToString(mState));
Andy Hungfb8ede22018-09-12 19:03:24 -0700845
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800846 if (mSharedBuffer != 0) {
847 return;
Glenn Kasten4bae3642012-11-30 13:41:12 -0800848 }
Andy Hung4c5ed302018-05-09 11:16:21 -0700849 if (mState == STATE_ACTIVE) {
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800850 return;
851 }
852 flush_l();
Eric Laurent1703cdf2011-03-07 14:52:59 -0800853}
854
Eric Laurent1703cdf2011-03-07 14:52:59 -0800855void AudioTrack::flush_l()
856{
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800857 ALOG_ASSERT(mState != STATE_ACTIVE);
Eric Laurentc2f1f072009-07-17 12:17:14 -0700858
Jean-Michel Trivi2c22aeb2009-03-24 18:11:07 -0700859 // clear playback marker and periodic update counter
860 mMarkerPosition = 0;
861 mMarkerReached = false;
862 mUpdatePeriod = 0;
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100863 mRefreshRemaining = true;
Eric Laurentc2f1f072009-07-17 12:17:14 -0700864
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800865 mState = STATE_FLUSHED;
Andy Hungc2813e52014-10-16 17:54:34 -0700866 mReleased = 0;
Glenn Kasten23a75452014-01-13 10:37:17 -0800867 if (isOffloaded_l()) {
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100868 mProxy->interrupt();
869 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800870 mProxy->flush();
Glenn Kasten4bae3642012-11-30 13:41:12 -0800871 mAudioTrack->flush();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800872}
873
874void AudioTrack::pause()
875{
Andy Hungb68f5eb2019-12-03 16:49:17 -0800876 const int64_t beginNs = systemTime();
Eric Laurentf5aafb22010-11-18 08:40:16 -0800877 AutoMutex lock(mLock);
Andy Hungb68f5eb2019-12-03 16:49:17 -0800878 mediametrics::Defer([&]() {
879 mediametrics::LogItem(mMetricsId)
880 .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_PAUSE)
881 .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
882 .set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
883 .record(); });
884
Eric Laurent973db022018-11-20 14:54:31 -0800885 ALOGV("%s(%d): prior state:%s", __func__, mPortId, stateToString(mState));
Andy Hungfb8ede22018-09-12 19:03:24 -0700886
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100887 if (mState == STATE_ACTIVE) {
888 mState = STATE_PAUSED;
889 } else if (mState == STATE_STOPPING) {
890 mState = STATE_PAUSED_STOPPING;
891 } else {
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800892 return;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800893 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800894 mProxy->interrupt();
895 mAudioTrack->pause();
Haynes Mathew George7064fd22014-01-08 13:59:53 -0800896
Marco Nelissen3a90f282014-03-10 11:21:43 -0700897 if (isOffloaded_l()) {
Glenn Kasten142f5192014-03-25 17:44:59 -0700898 if (mOutput != AUDIO_IO_HANDLE_NONE) {
Andy Hung7f1bc8a2014-09-12 14:43:11 -0700899 // An offload output can be re-used between two audio tracks having
900 // the same configuration. A timestamp query for a paused track
901 // while the other is running would return an incorrect time.
902 // To fix this, cache the playback position on a pause() and return
903 // this time when requested until the track is resumed.
904
905 // OffloadThread sends HAL pause in its threadLoop. Time saved
906 // here can be slightly off.
907
908 // TODO: check return code for getRenderPosition.
909
Haynes Mathew George7064fd22014-01-08 13:59:53 -0800910 uint32_t halFrames;
Haynes Mathew George7064fd22014-01-08 13:59:53 -0800911 AudioSystem::getRenderPosition(mOutput, &halFrames, &mPausedPosition);
Andy Hungfb8ede22018-09-12 19:03:24 -0700912 ALOGV("%s(%d): for offload, cache current position %u",
Eric Laurent973db022018-11-20 14:54:31 -0800913 __func__, mPortId, mPausedPosition);
Haynes Mathew George7064fd22014-01-08 13:59:53 -0800914 }
915 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800916}
917
Eric Laurentbe916aa2010-06-01 23:49:17 -0700918status_t AudioTrack::setVolume(float left, float right)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800919{
Glenn Kastenc56f3422014-03-21 17:53:17 -0700920 // This duplicates a test by AudioTrack JNI, but that is not the only caller
921 if (isnanf(left) || left < GAIN_FLOAT_ZERO || left > GAIN_FLOAT_UNITY ||
922 isnanf(right) || right < GAIN_FLOAT_ZERO || right > GAIN_FLOAT_UNITY) {
Eric Laurentbe916aa2010-06-01 23:49:17 -0700923 return BAD_VALUE;
924 }
925
Andy Hungb68f5eb2019-12-03 16:49:17 -0800926 mediametrics::LogItem(mMetricsId)
927 .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOLUME)
928 .set(AMEDIAMETRICS_PROP_VOLUME_LEFT, (double)left)
929 .set(AMEDIAMETRICS_PROP_VOLUME_RIGHT, (double)right)
930 .record();
931
Eric Laurent1703cdf2011-03-07 14:52:59 -0800932 AutoMutex lock(mLock);
Glenn Kasten66e46352014-01-16 17:44:23 -0800933 mVolume[AUDIO_INTERLEAVE_LEFT] = left;
934 mVolume[AUDIO_INTERLEAVE_RIGHT] = right;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800935
Glenn Kastenc56f3422014-03-21 17:53:17 -0700936 mProxy->setVolumeLR(gain_minifloat_pack(gain_from_float(left), gain_from_float(right)));
Eric Laurentbe916aa2010-06-01 23:49:17 -0700937
Glenn Kasten23a75452014-01-13 10:37:17 -0800938 if (isOffloaded_l()) {
Eric Laurent59fe0102013-09-27 18:48:26 -0700939 mAudioTrack->signal();
940 }
Eric Laurentbe916aa2010-06-01 23:49:17 -0700941 return NO_ERROR;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800942}
943
Glenn Kastenb1c09932012-02-27 16:21:04 -0800944status_t AudioTrack::setVolume(float volume)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800945{
Glenn Kastenb1c09932012-02-27 16:21:04 -0800946 return setVolume(volume, volume);
Eric Laurentbe916aa2010-06-01 23:49:17 -0700947}
948
Eric Laurent2beeb502010-07-16 07:43:46 -0700949status_t AudioTrack::setAuxEffectSendLevel(float level)
Eric Laurentbe916aa2010-06-01 23:49:17 -0700950{
Glenn Kastenc56f3422014-03-21 17:53:17 -0700951 // This duplicates a test by AudioTrack JNI, but that is not the only caller
952 if (isnanf(level) || level < GAIN_FLOAT_ZERO || level > GAIN_FLOAT_UNITY) {
Eric Laurentbe916aa2010-06-01 23:49:17 -0700953 return BAD_VALUE;
954 }
955
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800956 AutoMutex lock(mLock);
Eric Laurentbe916aa2010-06-01 23:49:17 -0700957 mSendLevel = level;
Glenn Kastene3aa6592012-12-04 12:22:46 -0800958 mProxy->setSendLevel(level);
Eric Laurentbe916aa2010-06-01 23:49:17 -0700959
960 return NO_ERROR;
961}
962
Glenn Kastena5224f32012-01-04 12:41:44 -0800963void AudioTrack::getAuxEffectSendLevel(float* level) const
Eric Laurentbe916aa2010-06-01 23:49:17 -0700964{
965 if (level != NULL) {
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800966 *level = mSendLevel;
Eric Laurentbe916aa2010-06-01 23:49:17 -0700967 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800968}
969
Glenn Kasten3b16c762012-11-14 08:44:39 -0800970status_t AudioTrack::setSampleRate(uint32_t rate)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800971{
Andy Hung5cbb5782015-03-27 18:39:59 -0700972 AutoMutex lock(mLock);
Eric Laurent973db022018-11-20 14:54:31 -0800973 ALOGV("%s(%d): prior state:%s rate:%u", __func__, mPortId, stateToString(mState), rate);
Andy Hungfb8ede22018-09-12 19:03:24 -0700974
Andy Hung5cbb5782015-03-27 18:39:59 -0700975 if (rate == mSampleRate) {
976 return NO_ERROR;
977 }
jiabinf4de6112018-12-19 12:40:08 -0800978 if (isOffloadedOrDirect_l() || (mFlags & AUDIO_OUTPUT_FLAG_FAST)
979 || (mChannelMask & AUDIO_CHANNEL_HAPTIC_ALL)) {
John Grossman4ff14ba2012-02-08 16:37:41 -0800980 return INVALID_OPERATION;
981 }
Eric Laurent0d6db582014-11-12 18:39:44 -0800982 if (mOutput == AUDIO_IO_HANDLE_NONE) {
983 return NO_INIT;
984 }
Andy Hung5cbb5782015-03-27 18:39:59 -0700985 // NOTE: it is theoretically possible, but highly unlikely, that a device change
986 // could mean a previously allowed sampling rate is no longer allowed.
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800987 uint32_t afSamplingRate;
Eric Laurent0d6db582014-11-12 18:39:44 -0800988 if (AudioSystem::getSamplingRate(mOutput, &afSamplingRate) != NO_ERROR) {
Eric Laurent57326622009-07-07 07:10:45 -0700989 return NO_INIT;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800990 }
Andy Hung26145642015-04-15 21:56:53 -0700991 // pitch is emulated by adjusting speed and sampleRate
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700992 const uint32_t effectiveSampleRate = adjustSampleRate(rate, mPlaybackRate.mPitch);
Andy Hung26145642015-04-15 21:56:53 -0700993 if (rate == 0 || effectiveSampleRate > afSamplingRate * AUDIO_RESAMPLER_DOWN_RATIO_MAX) {
Glenn Kastend65d73c2012-06-22 17:21:07 -0700994 return BAD_VALUE;
995 }
Andy Hung8edb8dc2015-03-26 19:13:55 -0700996 // TODO: Should we also check if the buffer size is compatible?
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800997
Glenn Kastene3aa6592012-12-04 12:22:46 -0800998 mSampleRate = rate;
Andy Hung26145642015-04-15 21:56:53 -0700999 mProxy->setSampleRate(effectiveSampleRate);
Glenn Kastene3aa6592012-12-04 12:22:46 -08001000
Eric Laurent57326622009-07-07 07:10:45 -07001001 return NO_ERROR;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001002}
1003
Glenn Kastena5224f32012-01-04 12:41:44 -08001004uint32_t AudioTrack::getSampleRate() const
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001005{
Eric Laurent1703cdf2011-03-07 14:52:59 -08001006 AutoMutex lock(mLock);
Eric Laurent6f59db12013-07-26 17:16:50 -07001007
1008 // sample rate can be updated during playback by the offloaded decoder so we need to
1009 // query the HAL and update if needed.
1010// FIXME use Proxy return channel to update the rate from server and avoid polling here
Eric Laurentab5cdba2014-06-09 17:22:27 -07001011 if (isOffloadedOrDirect_l()) {
Glenn Kasten142f5192014-03-25 17:44:59 -07001012 if (mOutput != AUDIO_IO_HANDLE_NONE) {
Eric Laurent6f59db12013-07-26 17:16:50 -07001013 uint32_t sampleRate = 0;
Jean-Michel Trivib7f24b12014-06-11 10:05:30 -07001014 status_t status = AudioSystem::getSamplingRate(mOutput, &sampleRate);
Eric Laurent6f59db12013-07-26 17:16:50 -07001015 if (status == NO_ERROR) {
1016 mSampleRate = sampleRate;
1017 }
1018 }
1019 }
Glenn Kastene3aa6592012-12-04 12:22:46 -08001020 return mSampleRate;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001021}
1022
Lajos Molnar3a474aa2015-04-24 17:10:07 -07001023uint32_t AudioTrack::getOriginalSampleRate() const
1024{
Lajos Molnar3a474aa2015-04-24 17:10:07 -07001025 return mOriginalSampleRate;
1026}
1027
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -07001028status_t AudioTrack::setPlaybackRate(const AudioPlaybackRate &playbackRate)
Andy Hung8edb8dc2015-03-26 19:13:55 -07001029{
Andy Hung8edb8dc2015-03-26 19:13:55 -07001030 AutoMutex lock(mLock);
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -07001031 if (isAudioPlaybackRateEqual(playbackRate, mPlaybackRate)) {
Andy Hung8edb8dc2015-03-26 19:13:55 -07001032 return NO_ERROR;
1033 }
Glenn Kastend79072e2016-01-06 08:41:20 -08001034 if (isOffloadedOrDirect_l()) {
Andy Hung8edb8dc2015-03-26 19:13:55 -07001035 return INVALID_OPERATION;
1036 }
1037 if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
1038 return INVALID_OPERATION;
1039 }
Andy Hungff874dc2016-04-11 16:49:09 -07001040
Andy Hungfb8ede22018-09-12 19:03:24 -07001041 ALOGV("%s(%d): mSampleRate:%u mSpeed:%f mPitch:%f",
Eric Laurent973db022018-11-20 14:54:31 -08001042 __func__, mPortId, mSampleRate, playbackRate.mSpeed, playbackRate.mPitch);
Andy Hung26145642015-04-15 21:56:53 -07001043 // pitch is emulated by adjusting speed and sampleRate
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -07001044 const uint32_t effectiveRate = adjustSampleRate(mSampleRate, playbackRate.mPitch);
1045 const float effectiveSpeed = adjustSpeed(playbackRate.mSpeed, playbackRate.mPitch);
1046 const float effectivePitch = adjustPitch(playbackRate.mPitch);
Ricardo Garcia6c7f0622015-04-30 18:39:16 -07001047 AudioPlaybackRate playbackRateTemp = playbackRate;
1048 playbackRateTemp.mSpeed = effectiveSpeed;
1049 playbackRateTemp.mPitch = effectivePitch;
1050
Andy Hungfb8ede22018-09-12 19:03:24 -07001051 ALOGV("%s(%d) (effective) mSampleRate:%u mSpeed:%f mPitch:%f",
Eric Laurent973db022018-11-20 14:54:31 -08001052 __func__, mPortId, effectiveRate, effectiveSpeed, effectivePitch);
Andy Hungff874dc2016-04-11 16:49:09 -07001053
Ricardo Garcia6c7f0622015-04-30 18:39:16 -07001054 if (!isAudioPlaybackRateValid(playbackRateTemp)) {
Andy Hungfb8ede22018-09-12 19:03:24 -07001055 ALOGW("%s(%d) (%f, %f) failed (effective rate out of bounds)",
Eric Laurent973db022018-11-20 14:54:31 -08001056 __func__, mPortId, playbackRate.mSpeed, playbackRate.mPitch);
Andy Hung26145642015-04-15 21:56:53 -07001057 return BAD_VALUE;
1058 }
Andy Hung8edb8dc2015-03-26 19:13:55 -07001059 // Check if the buffer size is compatible.
Andy Hung26145642015-04-15 21:56:53 -07001060 if (!isSampleRateSpeedAllowed_l(effectiveRate, effectiveSpeed)) {
Andy Hungfb8ede22018-09-12 19:03:24 -07001061 ALOGW("%s(%d) (%f, %f) failed (buffer size)",
Eric Laurent973db022018-11-20 14:54:31 -08001062 __func__, mPortId, playbackRate.mSpeed, playbackRate.mPitch);
Andy Hung8edb8dc2015-03-26 19:13:55 -07001063 return BAD_VALUE;
1064 }
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -07001065
Ricardo Garcia6c7f0622015-04-30 18:39:16 -07001066 // Check resampler ratios are within bounds
Glenn Kastend3bb6452016-12-05 18:14:37 -08001067 if ((uint64_t)effectiveRate > (uint64_t)mSampleRate *
1068 (uint64_t)AUDIO_RESAMPLER_DOWN_RATIO_MAX) {
Andy Hungfb8ede22018-09-12 19:03:24 -07001069 ALOGW("%s(%d) (%f, %f) failed. Resample rate exceeds max accepted value",
Eric Laurent973db022018-11-20 14:54:31 -08001070 __func__, mPortId, playbackRate.mSpeed, playbackRate.mPitch);
Ricardo Garcia6c7f0622015-04-30 18:39:16 -07001071 return BAD_VALUE;
1072 }
1073
Dan Austine34eae22015-10-27 16:14:52 -07001074 if ((uint64_t)effectiveRate * (uint64_t)AUDIO_RESAMPLER_UP_RATIO_MAX < (uint64_t)mSampleRate) {
Andy Hungfb8ede22018-09-12 19:03:24 -07001075 ALOGW("%s(%d) (%f, %f) failed. Resample rate below min accepted value",
Eric Laurent973db022018-11-20 14:54:31 -08001076 __func__, mPortId, playbackRate.mSpeed, playbackRate.mPitch);
Ricardo Garcia6c7f0622015-04-30 18:39:16 -07001077 return BAD_VALUE;
1078 }
1079 mPlaybackRate = playbackRate;
1080 //set effective rates
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -07001081 mProxy->setPlaybackRate(playbackRateTemp);
Andy Hung26145642015-04-15 21:56:53 -07001082 mProxy->setSampleRate(effectiveRate); // FIXME: not quite "atomic" with setPlaybackRate
Andy Hungb68f5eb2019-12-03 16:49:17 -08001083
1084 mediametrics::LogItem(mMetricsId)
1085 .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_SETPLAYBACKPARAM)
1086 .set(AMEDIAMETRICS_PROP_SAMPLERATE, (int32_t)mSampleRate)
1087 .set(AMEDIAMETRICS_PROP_PLAYBACK_SPEED, (double)mPlaybackRate.mSpeed)
1088 .set(AMEDIAMETRICS_PROP_PLAYBACK_PITCH, (double)mPlaybackRate.mPitch)
1089 .set(AMEDIAMETRICS_PROP_PREFIX_EFFECTIVE
1090 AMEDIAMETRICS_PROP_SAMPLERATE, (int32_t)effectiveRate)
1091 .set(AMEDIAMETRICS_PROP_PREFIX_EFFECTIVE
1092 AMEDIAMETRICS_PROP_PLAYBACK_SPEED, (double)playbackRateTemp.mSpeed)
1093 .set(AMEDIAMETRICS_PROP_PREFIX_EFFECTIVE
1094 AMEDIAMETRICS_PROP_PLAYBACK_PITCH, (double)playbackRateTemp.mPitch)
1095 .record();
1096
Andy Hung8edb8dc2015-03-26 19:13:55 -07001097 return NO_ERROR;
1098}
1099
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -07001100const AudioPlaybackRate& AudioTrack::getPlaybackRate() const
Andy Hung8edb8dc2015-03-26 19:13:55 -07001101{
1102 AutoMutex lock(mLock);
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -07001103 return mPlaybackRate;
Andy Hung8edb8dc2015-03-26 19:13:55 -07001104}
1105
Phil Burkc0adecb2016-01-08 12:44:11 -08001106ssize_t AudioTrack::getBufferSizeInFrames()
1107{
1108 AutoMutex lock(mLock);
1109 if (mOutput == AUDIO_IO_HANDLE_NONE || mProxy.get() == 0) {
1110 return NO_INIT;
1111 }
Phil Burka9876702020-04-20 18:16:15 -07001112
Phil Burke8972b02016-03-04 11:29:57 -08001113 return (ssize_t) mProxy->getBufferSizeInFrames();
Phil Burkc0adecb2016-01-08 12:44:11 -08001114}
1115
Andy Hungf2c87b32016-04-07 19:49:29 -07001116status_t AudioTrack::getBufferDurationInUs(int64_t *duration)
1117{
1118 if (duration == nullptr) {
1119 return BAD_VALUE;
1120 }
1121 AutoMutex lock(mLock);
1122 if (mOutput == AUDIO_IO_HANDLE_NONE || mProxy.get() == 0) {
1123 return NO_INIT;
1124 }
1125 ssize_t bufferSizeInFrames = (ssize_t) mProxy->getBufferSizeInFrames();
1126 if (bufferSizeInFrames < 0) {
1127 return (status_t)bufferSizeInFrames;
1128 }
1129 *duration = (int64_t)((double)bufferSizeInFrames * 1000000
1130 / ((double)mSampleRate * mPlaybackRate.mSpeed));
1131 return NO_ERROR;
1132}
1133
Phil Burka9876702020-04-20 18:16:15 -07001134void AudioTrack::logBufferSizeUnderruns() {
1135 LOG_ALWAYS_FATAL_IF(mMetricsId.size() == 0, "mMetricsId is empty!");
1136 ALOGD("%s(), mMetricsId = %s", __func__, mMetricsId.c_str());
1137 // FIXME THis hangs! Why?
1138// android::mediametrics::LogItem(mMetricsId)
1139// .set(AMEDIAMETRICS_PROP_BUFFERSIZEFRAMES, (int32_t) getBufferSizeInFrames())
1140// .set(AMEDIAMETRICS_PROP_UNDERRUN, (int32_t) getUnderrunCount())
1141// .record();
1142}
1143
Phil Burkc0adecb2016-01-08 12:44:11 -08001144ssize_t AudioTrack::setBufferSizeInFrames(size_t bufferSizeInFrames)
1145{
1146 AutoMutex lock(mLock);
1147 if (mOutput == AUDIO_IO_HANDLE_NONE || mProxy.get() == 0) {
1148 return NO_INIT;
1149 }
1150 // Reject if timed track or compressed audio.
Glenn Kastend79072e2016-01-06 08:41:20 -08001151 if (!audio_is_linear_pcm(mFormat)) {
Phil Burkc0adecb2016-01-08 12:44:11 -08001152 return INVALID_OPERATION;
1153 }
Phil Burka9876702020-04-20 18:16:15 -07001154
1155 ssize_t originalBufferSize = mProxy->getBufferSizeInFrames();
1156 ssize_t finalBufferSize = mProxy->setBufferSizeInFrames((uint32_t) bufferSizeInFrames);
1157 if (originalBufferSize != finalBufferSize) {
1158 logBufferSizeUnderruns();
1159 }
1160 return finalBufferSize;
Phil Burkc0adecb2016-01-08 12:44:11 -08001161}
1162
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001163status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount)
1164{
Glenn Kastend79072e2016-01-06 08:41:20 -08001165 if (mSharedBuffer == 0 || isOffloadedOrDirect()) {
Glenn Kasten083d1c12012-11-30 15:00:36 -08001166 return INVALID_OPERATION;
1167 }
1168
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001169 if (loopCount == 0) {
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001170 ;
1171 } else if (loopCount >= -1 && loopStart < loopEnd && loopEnd <= mFrameCount &&
1172 loopEnd - loopStart >= MIN_LOOP) {
1173 ;
1174 } else {
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001175 return BAD_VALUE;
1176 }
1177
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001178 AutoMutex lock(mLock);
1179 // See setPosition() regarding setting parameters such as loop points or position while active
1180 if (mState == STATE_ACTIVE) {
1181 return INVALID_OPERATION;
Eric Laurentc2f1f072009-07-17 12:17:14 -07001182 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001183 setLoop_l(loopStart, loopEnd, loopCount);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001184 return NO_ERROR;
1185}
1186
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001187void AudioTrack::setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCount)
1188{
Andy Hung4ede21d2014-12-12 15:37:34 -08001189 // We do not update the periodic notification point.
1190 // mNewPosition = updateAndGetPosition_l() + mUpdatePeriod;
1191 mLoopCount = loopCount;
1192 mLoopEnd = loopEnd;
1193 mLoopStart = loopStart;
Andy Hung53c3b5f2014-12-15 16:42:05 -08001194 mLoopCountNotified = loopCount;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001195 mStaticProxy->setLoop(loopStart, loopEnd, loopCount);
Andy Hung3c09c782014-12-29 18:39:32 -08001196
1197 // Waking the AudioTrackThread is not needed as this cannot be called when active.
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001198}
1199
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001200status_t AudioTrack::setMarkerPosition(uint32_t marker)
1201{
Glenn Kastenfb1fdc92013-07-10 17:03:19 -07001202 // The only purpose of setting marker position is to get a callback
Eric Laurentab5cdba2014-06-09 17:22:27 -07001203 if (mCbf == NULL || isOffloadedOrDirect()) {
Glenn Kastend65d73c2012-06-22 17:21:07 -07001204 return INVALID_OPERATION;
1205 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001206
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001207 AutoMutex lock(mLock);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001208 mMarkerPosition = marker;
Jean-Michel Trivi2c22aeb2009-03-24 18:11:07 -07001209 mMarkerReached = false;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001210
Andy Hung3c09c782014-12-29 18:39:32 -08001211 sp<AudioTrackThread> t = mAudioTrackThread;
1212 if (t != 0) {
1213 t->wake();
1214 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001215 return NO_ERROR;
1216}
1217
Glenn Kastena5224f32012-01-04 12:41:44 -08001218status_t AudioTrack::getMarkerPosition(uint32_t *marker) const
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001219{
Eric Laurentab5cdba2014-06-09 17:22:27 -07001220 if (isOffloadedOrDirect()) {
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +01001221 return INVALID_OPERATION;
1222 }
Glenn Kastend65d73c2012-06-22 17:21:07 -07001223 if (marker == NULL) {
1224 return BAD_VALUE;
1225 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001226
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001227 AutoMutex lock(mLock);
Andy Hung90e8a972015-11-09 16:42:40 -08001228 mMarkerPosition.getValue(marker);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001229
1230 return NO_ERROR;
1231}
1232
1233status_t AudioTrack::setPositionUpdatePeriod(uint32_t updatePeriod)
1234{
Glenn Kastenfb1fdc92013-07-10 17:03:19 -07001235 // The only purpose of setting position update period is to get a callback
Eric Laurentab5cdba2014-06-09 17:22:27 -07001236 if (mCbf == NULL || isOffloadedOrDirect()) {
Glenn Kastend65d73c2012-06-22 17:21:07 -07001237 return INVALID_OPERATION;
1238 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001239
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001240 AutoMutex lock(mLock);
Glenn Kasten200092b2014-08-15 15:13:30 -07001241 mNewPosition = updateAndGetPosition_l() + updatePeriod;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001242 mUpdatePeriod = updatePeriod;
Glenn Kasten2b2165c2014-01-13 08:53:36 -08001243
Andy Hung3c09c782014-12-29 18:39:32 -08001244 sp<AudioTrackThread> t = mAudioTrackThread;
1245 if (t != 0) {
1246 t->wake();
1247 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001248 return NO_ERROR;
1249}
1250
Glenn Kastena5224f32012-01-04 12:41:44 -08001251status_t AudioTrack::getPositionUpdatePeriod(uint32_t *updatePeriod) const
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001252{
Eric Laurentab5cdba2014-06-09 17:22:27 -07001253 if (isOffloadedOrDirect()) {
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +01001254 return INVALID_OPERATION;
1255 }
Glenn Kastend65d73c2012-06-22 17:21:07 -07001256 if (updatePeriod == NULL) {
1257 return BAD_VALUE;
1258 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001259
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001260 AutoMutex lock(mLock);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001261 *updatePeriod = mUpdatePeriod;
1262
1263 return NO_ERROR;
1264}
1265
1266status_t AudioTrack::setPosition(uint32_t position)
1267{
Glenn Kastend79072e2016-01-06 08:41:20 -08001268 if (mSharedBuffer == 0 || isOffloadedOrDirect()) {
Glenn Kastend65d73c2012-06-22 17:21:07 -07001269 return INVALID_OPERATION;
1270 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001271 if (position > mFrameCount) {
1272 return BAD_VALUE;
1273 }
John Grossman4ff14ba2012-02-08 16:37:41 -08001274
Eric Laurent1703cdf2011-03-07 14:52:59 -08001275 AutoMutex lock(mLock);
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001276 // Currently we require that the player is inactive before setting parameters such as position
1277 // or loop points. Otherwise, there could be a race condition: the application could read the
1278 // current position, compute a new position or loop parameters, and then set that position or
1279 // loop parameters but it would do the "wrong" thing since the position has continued to advance
1280 // in the mean time. If we ever provide a sequencer in server, we could allow a way for the app
1281 // to specify how it wants to handle such scenarios.
1282 if (mState == STATE_ACTIVE) {
Glenn Kastend65d73c2012-06-22 17:21:07 -07001283 return INVALID_OPERATION;
1284 }
Andy Hung9b461582014-12-01 17:56:29 -08001285 // After setting the position, use full update period before notification.
Glenn Kasten200092b2014-08-15 15:13:30 -07001286 mNewPosition = updateAndGetPosition_l() + mUpdatePeriod;
Andy Hung9b461582014-12-01 17:56:29 -08001287 mStaticProxy->setBufferPosition(position);
Andy Hung3c09c782014-12-29 18:39:32 -08001288
1289 // Waking the AudioTrackThread is not needed as this cannot be called when active.
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001290 return NO_ERROR;
1291}
1292
Glenn Kasten200092b2014-08-15 15:13:30 -07001293status_t AudioTrack::getPosition(uint32_t *position)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001294{
Glenn Kastend65d73c2012-06-22 17:21:07 -07001295 if (position == NULL) {
1296 return BAD_VALUE;
1297 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001298
Eric Laurent1703cdf2011-03-07 14:52:59 -08001299 AutoMutex lock(mLock);
Andy Hung7a490e72016-03-23 15:58:10 -07001300 // FIXME: offloaded and direct tracks call into the HAL for render positions
1301 // for compressed/synced data; however, we use proxy position for pure linear pcm data
1302 // as we do not know the capability of the HAL for pcm position support and standby.
1303 // There may be some latency differences between the HAL position and the proxy position.
1304 if (isOffloadedOrDirect_l() && !isPurePcmData_l()) {
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +01001305 uint32_t dspFrames = 0;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001306
Eric Laurentab5cdba2014-06-09 17:22:27 -07001307 if (isOffloaded_l() && ((mState == STATE_PAUSED) || (mState == STATE_PAUSED_STOPPING))) {
Andy Hungfb8ede22018-09-12 19:03:24 -07001308 ALOGV("%s(%d): called in paused state, return cached position %u",
Eric Laurent973db022018-11-20 14:54:31 -08001309 __func__, mPortId, mPausedPosition);
Haynes Mathew George7064fd22014-01-08 13:59:53 -08001310 *position = mPausedPosition;
1311 return NO_ERROR;
1312 }
1313
Glenn Kasten142f5192014-03-25 17:44:59 -07001314 if (mOutput != AUDIO_IO_HANDLE_NONE) {
Andy Hung1f1db832015-06-08 13:26:10 -07001315 uint32_t halFrames; // actually unused
1316 (void) AudioSystem::getRenderPosition(mOutput, &halFrames, &dspFrames);
1317 // FIXME: on getRenderPosition() error, we return OK with frame position 0.
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +01001318 }
Andy Hung7f1bc8a2014-09-12 14:43:11 -07001319 // FIXME: dspFrames may not be zero in (mState == STATE_STOPPED || mState == STATE_FLUSHED)
1320 // due to hardware latency. We leave this behavior for now.
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +01001321 *position = dspFrames;
1322 } else {
Eric Laurent275e8e92014-11-30 15:14:47 -08001323 if (mCblk->mFlags & CBLK_INVALID) {
Andy Hung1f1db832015-06-08 13:26:10 -07001324 (void) restoreTrack_l("getPosition");
1325 // FIXME: for compatibility with the Java API we ignore the restoreTrack_l()
1326 // error here (e.g. DEAD_OBJECT) and return OK with the last recorded server position.
Eric Laurent275e8e92014-11-30 15:14:47 -08001327 }
1328
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +01001329 // IAudioTrack::stop() isn't synchronous; we don't know when presentation completes
Glenn Kasten200092b2014-08-15 15:13:30 -07001330 *position = (mState == STATE_STOPPED || mState == STATE_FLUSHED) ?
Andy Hung90e8a972015-11-09 16:42:40 -08001331 0 : updateAndGetPosition_l().value();
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +01001332 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001333 return NO_ERROR;
1334}
1335
Kévin PETIT377b2ec2014-02-03 12:35:36 +00001336status_t AudioTrack::getBufferPosition(uint32_t *position)
Glenn Kasten9c6745f2012-11-30 13:35:29 -08001337{
Glenn Kastend79072e2016-01-06 08:41:20 -08001338 if (mSharedBuffer == 0) {
Glenn Kasten9c6745f2012-11-30 13:35:29 -08001339 return INVALID_OPERATION;
1340 }
1341 if (position == NULL) {
1342 return BAD_VALUE;
1343 }
Glenn Kasten9c6745f2012-11-30 13:35:29 -08001344
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001345 AutoMutex lock(mLock);
1346 *position = mStaticProxy->getBufferPosition();
Glenn Kasten9c6745f2012-11-30 13:35:29 -08001347 return NO_ERROR;
1348}
Glenn Kasten9c6745f2012-11-30 13:35:29 -08001349
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001350status_t AudioTrack::reload()
1351{
Glenn Kastend79072e2016-01-06 08:41:20 -08001352 if (mSharedBuffer == 0 || isOffloadedOrDirect()) {
Glenn Kasten083d1c12012-11-30 15:00:36 -08001353 return INVALID_OPERATION;
1354 }
1355
Eric Laurent1703cdf2011-03-07 14:52:59 -08001356 AutoMutex lock(mLock);
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001357 // See setPosition() regarding setting parameters such as loop points or position while active
1358 if (mState == STATE_ACTIVE) {
Glenn Kastend65d73c2012-06-22 17:21:07 -07001359 return INVALID_OPERATION;
1360 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001361 mNewPosition = mUpdatePeriod;
Andy Hung9b461582014-12-01 17:56:29 -08001362 (void) updateAndGetPosition_l();
1363 mPosition = 0;
Phil Burk1b420972015-04-22 10:52:21 -07001364 mPreviousTimestampValid = false;
Andy Hung53c3b5f2014-12-15 16:42:05 -08001365#if 0
Andy Hung9b461582014-12-01 17:56:29 -08001366 // The documentation is not clear on the behavior of reload() and the restoration
Andy Hung53c3b5f2014-12-15 16:42:05 -08001367 // of loop count. Historically we have not restored loop count, start, end,
1368 // but it makes sense if one desires to repeat playing a particular sound.
1369 if (mLoopCount != 0) {
1370 mLoopCountNotified = mLoopCount;
1371 mStaticProxy->setLoop(mLoopStart, mLoopEnd, mLoopCount);
1372 }
1373#endif
Andy Hung9b461582014-12-01 17:56:29 -08001374 mStaticProxy->setBufferPosition(0);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001375 return NO_ERROR;
1376}
1377
Glenn Kasten38e905b2014-01-13 10:21:48 -08001378audio_io_handle_t AudioTrack::getOutput() const
Eric Laurentc2f1f072009-07-17 12:17:14 -07001379{
Eric Laurent1703cdf2011-03-07 14:52:59 -08001380 AutoMutex lock(mLock);
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +01001381 return mOutput;
Eric Laurent1703cdf2011-03-07 14:52:59 -08001382}
1383
Paul McLeanaa981192015-03-21 09:55:15 -07001384status_t AudioTrack::setOutputDevice(audio_port_handle_t deviceId) {
1385 AutoMutex lock(mLock);
1386 if (mSelectedDeviceId != deviceId) {
1387 mSelectedDeviceId = deviceId;
Eric Laurentfb00fc72017-05-25 18:17:12 -07001388 if (mStatus == NO_ERROR) {
1389 android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
jiabin156c6872017-10-06 09:47:15 -07001390 mProxy->interrupt();
Eric Laurentfb00fc72017-05-25 18:17:12 -07001391 }
Paul McLeanaa981192015-03-21 09:55:15 -07001392 }
Eric Laurent493404d2015-04-21 15:07:36 -07001393 return NO_ERROR;
Paul McLeanaa981192015-03-21 09:55:15 -07001394}
1395
1396audio_port_handle_t AudioTrack::getOutputDevice() {
1397 AutoMutex lock(mLock);
1398 return mSelectedDeviceId;
1399}
1400
Eric Laurentad2e7b92017-09-14 20:06:42 -07001401// must be called with mLock held
1402void AudioTrack::updateRoutedDeviceId_l()
1403{
1404 // if the track is inactive, do not update actual device as the output stream maybe routed
1405 // to a device not relevant to this client because of other active use cases.
1406 if (mState != STATE_ACTIVE) {
1407 return;
1408 }
1409 if (mOutput != AUDIO_IO_HANDLE_NONE) {
1410 audio_port_handle_t deviceId = AudioSystem::getDeviceIdForIo(mOutput);
1411 if (deviceId != AUDIO_PORT_HANDLE_NONE) {
1412 mRoutedDeviceId = deviceId;
1413 }
1414 }
1415}
1416
Eric Laurent296fb132015-05-01 11:38:42 -07001417audio_port_handle_t AudioTrack::getRoutedDeviceId() {
1418 AutoMutex lock(mLock);
Eric Laurentad2e7b92017-09-14 20:06:42 -07001419 updateRoutedDeviceId_l();
1420 return mRoutedDeviceId;
Eric Laurent296fb132015-05-01 11:38:42 -07001421}
1422
Eric Laurentbe916aa2010-06-01 23:49:17 -07001423status_t AudioTrack::attachAuxEffect(int effectId)
1424{
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001425 AutoMutex lock(mLock);
Eric Laurent2beeb502010-07-16 07:43:46 -07001426 status_t status = mAudioTrack->attachAuxEffect(effectId);
1427 if (status == NO_ERROR) {
1428 mAuxEffectId = effectId;
1429 }
1430 return status;
Eric Laurentbe916aa2010-06-01 23:49:17 -07001431}
1432
Eric Laurente83b55d2014-11-14 10:06:21 -08001433audio_stream_type_t AudioTrack::streamType() const
1434{
1435 if (mStreamType == AUDIO_STREAM_DEFAULT) {
François Gaffie58d4be52018-11-06 15:30:12 +01001436 return AudioSystem::attributesToStreamType(mAttributes);
Eric Laurente83b55d2014-11-14 10:06:21 -08001437 }
1438 return mStreamType;
1439}
1440
Haynes Mathew Georgefb12e202017-04-06 12:24:42 -07001441uint32_t AudioTrack::latency()
1442{
1443 AutoMutex lock(mLock);
1444 updateLatency_l();
1445 return mLatency;
1446}
1447
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001448// -------------------------------------------------------------------------
1449
Eric Laurent1703cdf2011-03-07 14:52:59 -08001450// must be called with mLock held
Haynes Mathew Georgefb12e202017-04-06 12:24:42 -07001451void AudioTrack::updateLatency_l()
1452{
1453 status_t status = AudioSystem::getLatency(mOutput, &mAfLatency);
1454 if (status != NO_ERROR) {
Eric Laurent973db022018-11-20 14:54:31 -08001455 ALOGW("%s(%d): getLatency(%d) failed status %d", __func__, mPortId, mOutput, status);
Haynes Mathew Georgefb12e202017-04-06 12:24:42 -07001456 } else {
1457 // FIXME don't believe this lie
Andy Hung13969262017-09-11 17:24:21 -07001458 mLatency = mAfLatency + (1000LL * mFrameCount) / mSampleRate;
Haynes Mathew Georgefb12e202017-04-06 12:24:42 -07001459 }
1460}
1461
Phil Burkadbb75a2017-06-16 12:19:42 -07001462// TODO Move this macro to a common header file for enum to string conversion in audio framework.
1463#define MEDIA_CASE_ENUM(name) case name: return #name
1464const char * AudioTrack::convertTransferToText(transfer_type transferType) {
1465 switch (transferType) {
1466 MEDIA_CASE_ENUM(TRANSFER_DEFAULT);
1467 MEDIA_CASE_ENUM(TRANSFER_CALLBACK);
1468 MEDIA_CASE_ENUM(TRANSFER_OBTAIN);
1469 MEDIA_CASE_ENUM(TRANSFER_SYNC);
1470 MEDIA_CASE_ENUM(TRANSFER_SHARED);
Jean-Michel Trivif4158d82018-09-25 12:43:58 -07001471 MEDIA_CASE_ENUM(TRANSFER_SYNC_NOTIF_CALLBACK);
Phil Burkadbb75a2017-06-16 12:19:42 -07001472 default:
1473 return "UNRECOGNIZED";
1474 }
1475}
1476
Glenn Kasten200092b2014-08-15 15:13:30 -07001477status_t AudioTrack::createTrack_l()
Eric Laurent34f1d8e2009-11-04 08:27:26 -08001478{
Eric Laurentf32d7812017-11-30 14:44:07 -08001479 status_t status;
1480 bool callbackAdded = false;
1481
Eric Laurent34f1d8e2009-11-04 08:27:26 -08001482 const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
1483 if (audioFlinger == 0) {
Andy Hungfb8ede22018-09-12 19:03:24 -07001484 ALOGE("%s(%d): Could not get audioflinger",
Eric Laurent973db022018-11-20 14:54:31 -08001485 __func__, mPortId);
Eric Laurentf32d7812017-11-30 14:44:07 -08001486 status = NO_INIT;
1487 goto exit;
Eric Laurent34f1d8e2009-11-04 08:27:26 -08001488 }
1489
Eric Laurent21da6472017-11-09 16:29:26 -08001490 {
Haynes Mathew Georgeae34ed22016-01-28 11:58:39 -08001491 // mFlags (not mOrigFlags) is modified depending on whether fast request is accepted.
1492 // After fast request is denied, we will request again if IAudioTrack is re-created.
Glenn Kastend79072e2016-01-06 08:41:20 -08001493 // Client can only express a preference for FAST. Server will perform additional tests.
Phil Burk33ff89b2015-11-30 11:16:01 -08001494 if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
Phil Burkadbb75a2017-06-16 12:19:42 -07001495 // either of these use cases:
1496 // use case 1: shared buffer
1497 bool sharedBuffer = mSharedBuffer != 0;
1498 bool transferAllowed =
Glenn Kastenc6ba8232014-02-27 13:34:29 -08001499 // use case 2: callback transfer mode
Glenn Kasten1dfe2f92015-03-09 12:03:14 -07001500 (mTransfer == TRANSFER_CALLBACK) ||
1501 // use case 3: obtain/release mode
Phil Burk33ff89b2015-11-30 11:16:01 -08001502 (mTransfer == TRANSFER_OBTAIN) ||
1503 // use case 4: synchronous write
Jean-Michel Trivif4158d82018-09-25 12:43:58 -07001504 ((mTransfer == TRANSFER_SYNC || mTransfer == TRANSFER_SYNC_NOTIF_CALLBACK)
1505 && mThreadCanCallJava);
Phil Burkadbb75a2017-06-16 12:19:42 -07001506
Eric Laurent21da6472017-11-09 16:29:26 -08001507 bool fastAllowed = sharedBuffer || transferAllowed;
1508 if (!fastAllowed) {
Andy Hungfb8ede22018-09-12 19:03:24 -07001509 ALOGW("%s(%d): AUDIO_OUTPUT_FLAG_FAST denied by client,"
1510 " not shared buffer and transfer = %s",
Eric Laurent973db022018-11-20 14:54:31 -08001511 __func__, mPortId,
Phil Burkadbb75a2017-06-16 12:19:42 -07001512 convertTransferToText(mTransfer));
Phil Burk33ff89b2015-11-30 11:16:01 -08001513 mFlags = (audio_output_flags_t) (mFlags & ~AUDIO_OUTPUT_FLAG_FAST);
1514 }
Glenn Kasten4a4a0952012-03-19 11:38:14 -07001515 }
1516
Eric Laurent21da6472017-11-09 16:29:26 -08001517 IAudioFlinger::CreateTrackInput input;
1518 if (mStreamType != AUDIO_STREAM_DEFAULT) {
François Gaffie58d4be52018-11-06 15:30:12 +01001519 input.attr = AudioSystem::streamTypeToAttributes(mStreamType);
Glenn Kastene0fa4672012-04-24 14:35:14 -07001520 } else {
Eric Laurent21da6472017-11-09 16:29:26 -08001521 input.attr = mAttributes;
Eric Laurentd1b449a2010-05-14 03:26:45 -07001522 }
Eric Laurent21da6472017-11-09 16:29:26 -08001523 input.config = AUDIO_CONFIG_INITIALIZER;
1524 input.config.sample_rate = mSampleRate;
1525 input.config.channel_mask = mChannelMask;
1526 input.config.format = mFormat;
1527 input.config.offload_info = mOffloadInfoCopy;
1528 input.clientInfo.clientUid = mClientUid;
1529 input.clientInfo.clientPid = mClientPid;
1530 input.clientInfo.clientTid = -1;
Glenn Kasten363fb752014-01-15 12:27:31 -08001531 if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
Glenn Kasten47d55172017-05-23 11:19:30 -07001532 // It is currently meaningless to request SCHED_FIFO for a Java thread. Even if the
1533 // application-level code follows all non-blocking design rules, the language runtime
1534 // doesn't also follow those rules, so the thread will not benefit overall.
Phil Burk33ff89b2015-11-30 11:16:01 -08001535 if (mAudioTrackThread != 0 && !mThreadCanCallJava) {
Eric Laurent21da6472017-11-09 16:29:26 -08001536 input.clientInfo.clientTid = mAudioTrackThread->getTid();
Glenn Kasten3acbd052012-02-28 10:39:56 -08001537 }
Glenn Kasten4a4a0952012-03-19 11:38:14 -07001538 }
Eric Laurent21da6472017-11-09 16:29:26 -08001539 input.sharedBuffer = mSharedBuffer;
1540 input.notificationsPerBuffer = mNotificationsPerBufferReq;
1541 input.speed = 1.0;
1542 if (audio_has_proportional_frames(mFormat) && mSharedBuffer == 0 &&
1543 (mFlags & AUDIO_OUTPUT_FLAG_FAST) == 0) {
1544 input.speed = !isPurePcmData_l() || isOffloadedOrDirect_l() ? 1.0f :
1545 max(mMaxRequiredSpeed, mPlaybackRate.mSpeed);
1546 }
1547 input.flags = mFlags;
1548 input.frameCount = mReqFrameCount;
1549 input.notificationFrameCount = mNotificationFramesReq;
1550 input.selectedDeviceId = mSelectedDeviceId;
1551 input.sessionId = mSessionId;
jiabinf6eb4c32020-02-25 14:06:25 -08001552 input.audioTrackCallback = mAudioTrackCallback;
Glenn Kasten4a4a0952012-03-19 11:38:14 -07001553
Eric Laurent21da6472017-11-09 16:29:26 -08001554 IAudioFlinger::CreateTrackOutput output;
1555
1556 sp<IAudioTrack> track = audioFlinger->createTrack(input,
Eric Laurent34f1d8e2009-11-04 08:27:26 -08001557 output,
Eric Laurent21da6472017-11-09 16:29:26 -08001558 &status);
Eric Laurent34f1d8e2009-11-04 08:27:26 -08001559
Eric Laurent21da6472017-11-09 16:29:26 -08001560 if (status != NO_ERROR || output.outputId == AUDIO_IO_HANDLE_NONE) {
Andy Hungfb8ede22018-09-12 19:03:24 -07001561 ALOGE("%s(%d): AudioFlinger could not create track, status: %d output %d",
Eric Laurent973db022018-11-20 14:54:31 -08001562 __func__, mPortId, status, output.outputId);
Eric Laurentf32d7812017-11-30 14:44:07 -08001563 if (status == NO_ERROR) {
1564 status = NO_INIT;
1565 }
1566 goto exit;
Eric Laurent34f1d8e2009-11-04 08:27:26 -08001567 }
Glenn Kastenc08d20b2014-02-24 15:21:10 -08001568 ALOG_ASSERT(track != 0);
1569
Eric Laurent21da6472017-11-09 16:29:26 -08001570 mFrameCount = output.frameCount;
1571 mNotificationFramesAct = (uint32_t)output.notificationFrameCount;
1572 mRoutedDeviceId = output.selectedDeviceId;
1573 mSessionId = output.sessionId;
1574
1575 mSampleRate = output.sampleRate;
1576 if (mOriginalSampleRate == 0) {
1577 mOriginalSampleRate = mSampleRate;
1578 }
1579
1580 mAfFrameCount = output.afFrameCount;
1581 mAfSampleRate = output.afSampleRate;
1582 mAfLatency = output.afLatencyMs;
1583
1584 mLatency = mAfLatency + (1000LL * mFrameCount) / mSampleRate;
1585
Glenn Kasten38e905b2014-01-13 10:21:48 -08001586 // AudioFlinger now owns the reference to the I/O handle,
1587 // so we are no longer responsible for releasing it.
1588
Glenn Kasten7fd04222016-02-02 12:38:16 -08001589 // FIXME compare to AudioRecord
Glenn Kastend2c38fc2012-11-01 14:58:02 -07001590 sp<IMemory> iMem = track->getCblk();
1591 if (iMem == 0) {
Eric Laurent973db022018-11-20 14:54:31 -08001592 ALOGE("%s(%d): Could not get control block", __func__, mPortId);
Eric Laurentad2e7b92017-09-14 20:06:42 -07001593 status = NO_INIT;
Eric Laurentf32d7812017-11-30 14:44:07 -08001594 goto exit;
Eric Laurent34f1d8e2009-11-04 08:27:26 -08001595 }
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -07001596 // TODO: Using unsecurePointer() has some associated security pitfalls
1597 // (see declaration for details).
1598 // Either document why it is safe in this case or address the
1599 // issue (e.g. by copying).
1600 void *iMemPointer = iMem->unsecurePointer();
Glenn Kasten0cde0762014-01-16 15:06:36 -08001601 if (iMemPointer == NULL) {
Eric Laurent973db022018-11-20 14:54:31 -08001602 ALOGE("%s(%d): Could not get control block pointer", __func__, mPortId);
Eric Laurentad2e7b92017-09-14 20:06:42 -07001603 status = NO_INIT;
Eric Laurentf32d7812017-11-30 14:44:07 -08001604 goto exit;
Glenn Kasten0cde0762014-01-16 15:06:36 -08001605 }
Glenn Kasten53cec222013-08-29 09:01:02 -07001606 // invariant that mAudioTrack != 0 is true only after set() returns successfully
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001607 if (mAudioTrack != 0) {
Marco Nelissenf8880202014-11-14 07:58:25 -08001608 IInterface::asBinder(mAudioTrack)->unlinkToDeath(mDeathNotifier, this);
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001609 mDeathNotifier.clear();
1610 }
Eric Laurent34f1d8e2009-11-04 08:27:26 -08001611 mAudioTrack = track;
Glenn Kastend2c38fc2012-11-01 14:58:02 -07001612 mCblkMemory = iMem;
Eric Laurent3bcffa12014-06-12 18:38:45 -07001613 IPCThreadState::self()->flushCommands();
1614
Glenn Kasten0cde0762014-01-16 15:06:36 -08001615 audio_track_cblk_t* cblk = static_cast<audio_track_cblk_t*>(iMemPointer);
Glenn Kastend2c38fc2012-11-01 14:58:02 -07001616 mCblk = cblk;
Glenn Kasten5f631512014-02-24 15:16:07 -08001617
Glenn Kastena07f17c2013-04-23 12:39:37 -07001618 mAwaitBoost = false;
Glenn Kasten363fb752014-01-15 12:27:31 -08001619 if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
Eric Laurent21da6472017-11-09 16:29:26 -08001620 if (output.flags & AUDIO_OUTPUT_FLAG_FAST) {
Andy Hungfb8ede22018-09-12 19:03:24 -07001621 ALOGI("%s(%d): AUDIO_OUTPUT_FLAG_FAST successful; frameCount %zu -> %zu",
Eric Laurent973db022018-11-20 14:54:31 -08001622 __func__, mPortId, mReqFrameCount, mFrameCount);
Phil Burk33ff89b2015-11-30 11:16:01 -08001623 if (!mThreadCanCallJava) {
1624 mAwaitBoost = true;
1625 }
Glenn Kasten3acbd052012-02-28 10:39:56 -08001626 } else {
Andy Hungfb8ede22018-09-12 19:03:24 -07001627 ALOGW("%s(%d): AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount %zu -> %zu",
Eric Laurent973db022018-11-20 14:54:31 -08001628 __func__, mPortId, mReqFrameCount, mFrameCount);
Glenn Kastene0fa4672012-04-24 14:35:14 -07001629 }
Glenn Kasten3acbd052012-02-28 10:39:56 -08001630 }
Eric Laurent21da6472017-11-09 16:29:26 -08001631 mFlags = output.flags;
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +01001632
Eric Laurentad2e7b92017-09-14 20:06:42 -07001633 //mOutput != output includes the case where mOutput == AUDIO_IO_HANDLE_NONE for first creation
Eric Laurent09f1ed22019-04-24 17:45:17 -07001634 if (mDeviceCallback != 0) {
Eric Laurentad2e7b92017-09-14 20:06:42 -07001635 if (mOutput != AUDIO_IO_HANDLE_NONE) {
Eric Laurent09f1ed22019-04-24 17:45:17 -07001636 AudioSystem::removeAudioDeviceCallback(this, mOutput, mPortId);
Eric Laurentad2e7b92017-09-14 20:06:42 -07001637 }
Eric Laurent09f1ed22019-04-24 17:45:17 -07001638 AudioSystem::addAudioDeviceCallback(this, output.outputId, output.portId);
Eric Laurentad2e7b92017-09-14 20:06:42 -07001639 callbackAdded = true;
1640 }
1641
Eric Laurent09f1ed22019-04-24 17:45:17 -07001642 mPortId = output.portId;
Glenn Kasten38e905b2014-01-13 10:21:48 -08001643 // We retain a copy of the I/O handle, but don't own the reference
Eric Laurent21da6472017-11-09 16:29:26 -08001644 mOutput = output.outputId;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001645 mRefreshRemaining = true;
1646
1647 // Starting address of buffers in shared memory. If there is a shared buffer, buffers
1648 // is the value of pointer() for the shared buffer, otherwise buffers points
1649 // immediately after the control block. This address is for the mapping within client
1650 // address space. AudioFlinger::TrackBase::mBuffer is for the server address space.
1651 void* buffers;
Glenn Kasten363fb752014-01-15 12:27:31 -08001652 if (mSharedBuffer == 0) {
Glenn Kasten138d6f92015-03-20 10:54:51 -07001653 buffers = cblk + 1;
Eric Laurent34f1d8e2009-11-04 08:27:26 -08001654 } else {
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -07001655 // TODO: Using unsecurePointer() has some associated security pitfalls
1656 // (see declaration for details).
1657 // Either document why it is safe in this case or address the
1658 // issue (e.g. by copying).
1659 buffers = mSharedBuffer->unsecurePointer();
Glenn Kasten138d6f92015-03-20 10:54:51 -07001660 if (buffers == NULL) {
Eric Laurent973db022018-11-20 14:54:31 -08001661 ALOGE("%s(%d): Could not get buffer pointer", __func__, mPortId);
Eric Laurentad2e7b92017-09-14 20:06:42 -07001662 status = NO_INIT;
Eric Laurentf32d7812017-11-30 14:44:07 -08001663 goto exit;
Glenn Kasten138d6f92015-03-20 10:54:51 -07001664 }
Eric Laurent34f1d8e2009-11-04 08:27:26 -08001665 }
1666
Eric Laurent2beeb502010-07-16 07:43:46 -07001667 mAudioTrack->attachAuxEffect(mAuxEffectId);
Glenn Kasten5f631512014-02-24 15:16:07 -08001668
Glenn Kasten093000f2012-05-03 09:35:36 -07001669 // If IAudioTrack is re-created, don't let the requested frameCount
1670 // decrease. This can confuse clients that cache frameCount().
Eric Laurent21da6472017-11-09 16:29:26 -08001671 if (mFrameCount > mReqFrameCount) {
1672 mReqFrameCount = mFrameCount;
Glenn Kasten093000f2012-05-03 09:35:36 -07001673 }
Glenn Kastene3aa6592012-12-04 12:22:46 -08001674
Andy Hungd7bd69e2015-07-24 07:52:41 -07001675 // reset server position to 0 as we have new cblk.
1676 mServer = 0;
1677
Glenn Kastene3aa6592012-12-04 12:22:46 -08001678 // update proxy
Glenn Kasten363fb752014-01-15 12:27:31 -08001679 if (mSharedBuffer == 0) {
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001680 mStaticProxy.clear();
Eric Laurent21da6472017-11-09 16:29:26 -08001681 mProxy = new AudioTrackClientProxy(cblk, buffers, mFrameCount, mFrameSize);
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001682 } else {
Eric Laurent21da6472017-11-09 16:29:26 -08001683 mStaticProxy = new StaticAudioTrackClientProxy(cblk, buffers, mFrameCount, mFrameSize);
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001684 mProxy = mStaticProxy;
1685 }
seunghak.hane6a9d6582014-11-22 15:22:35 +09001686
1687 mProxy->setVolumeLR(gain_minifloat_pack(
1688 gain_from_float(mVolume[AUDIO_INTERLEAVE_LEFT]),
1689 gain_from_float(mVolume[AUDIO_INTERLEAVE_RIGHT])));
1690
Glenn Kastene3aa6592012-12-04 12:22:46 -08001691 mProxy->setSendLevel(mSendLevel);
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -07001692 const uint32_t effectiveSampleRate = adjustSampleRate(mSampleRate, mPlaybackRate.mPitch);
1693 const float effectiveSpeed = adjustSpeed(mPlaybackRate.mSpeed, mPlaybackRate.mPitch);
1694 const float effectivePitch = adjustPitch(mPlaybackRate.mPitch);
Andy Hung26145642015-04-15 21:56:53 -07001695 mProxy->setSampleRate(effectiveSampleRate);
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -07001696
1697 AudioPlaybackRate playbackRateTemp = mPlaybackRate;
1698 playbackRateTemp.mSpeed = effectiveSpeed;
1699 playbackRateTemp.mPitch = effectivePitch;
1700 mProxy->setPlaybackRate(playbackRateTemp);
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001701 mProxy->setMinimum(mNotificationFramesAct);
1702
1703 mDeathNotifier = new DeathNotifier(this);
Marco Nelissenf8880202014-11-14 07:58:25 -08001704 IInterface::asBinder(mAudioTrack)->linkToDeath(mDeathNotifier, this);
Glenn Kastene3aa6592012-12-04 12:22:46 -08001705
Andy Hungb68f5eb2019-12-03 16:49:17 -08001706 // This is the first log sent from the AudioTrack client.
1707 // The creation of the audio track by AudioFlinger (in the code above)
1708 // is the first log of the AudioTrack and must be present before
1709 // any AudioTrack client logs will be accepted.
1710 mMetricsId = std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK) + std::to_string(mPortId);
1711 mediametrics::LogItem(mMetricsId)
1712 .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE)
1713 // the following are immutable
1714 .set(AMEDIAMETRICS_PROP_FLAGS, (int32_t)mFlags)
1715 .set(AMEDIAMETRICS_PROP_ORIGINALFLAGS, (int32_t)mOrigFlags)
1716 .set(AMEDIAMETRICS_PROP_SESSIONID, (int32_t)mSessionId)
1717 .set(AMEDIAMETRICS_PROP_TRACKID, mPortId) // dup from key
1718 .set(AMEDIAMETRICS_PROP_STREAMTYPE, toString(mStreamType).c_str())
1719 .set(AMEDIAMETRICS_PROP_CONTENTTYPE, toString(mAttributes.content_type).c_str())
1720 .set(AMEDIAMETRICS_PROP_USAGE, toString(mAttributes.usage).c_str())
1721 .set(AMEDIAMETRICS_PROP_THREADID, (int32_t)output.outputId)
1722 .set(AMEDIAMETRICS_PROP_SELECTEDDEVICEID, (int32_t)mSelectedDeviceId)
1723 .set(AMEDIAMETRICS_PROP_ROUTEDDEVICEID, (int32_t)mRoutedDeviceId)
1724 .set(AMEDIAMETRICS_PROP_ENCODING, toString(mFormat).c_str())
1725 .set(AMEDIAMETRICS_PROP_CHANNELMASK, (int32_t)mChannelMask)
1726 .set(AMEDIAMETRICS_PROP_FRAMECOUNT, (int32_t)mFrameCount)
1727 // the following are NOT immutable
1728 .set(AMEDIAMETRICS_PROP_VOLUME_LEFT, (double)mVolume[AUDIO_INTERLEAVE_LEFT])
1729 .set(AMEDIAMETRICS_PROP_VOLUME_RIGHT, (double)mVolume[AUDIO_INTERLEAVE_RIGHT])
1730 .set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
1731 .set(AMEDIAMETRICS_PROP_AUXEFFECTID, (int32_t)mAuxEffectId)
1732 .set(AMEDIAMETRICS_PROP_SAMPLERATE, (int32_t)mSampleRate)
1733 .set(AMEDIAMETRICS_PROP_PLAYBACK_SPEED, (double)mPlaybackRate.mSpeed)
1734 .set(AMEDIAMETRICS_PROP_PLAYBACK_PITCH, (double)mPlaybackRate.mPitch)
1735 .set(AMEDIAMETRICS_PROP_PREFIX_EFFECTIVE
1736 AMEDIAMETRICS_PROP_SAMPLERATE, (int32_t)effectiveSampleRate)
1737 .set(AMEDIAMETRICS_PROP_PREFIX_EFFECTIVE
1738 AMEDIAMETRICS_PROP_PLAYBACK_SPEED, (double)effectiveSpeed)
1739 .set(AMEDIAMETRICS_PROP_PREFIX_EFFECTIVE
1740 AMEDIAMETRICS_PROP_PLAYBACK_PITCH, (double)effectivePitch)
1741 .record();
1742
1743 // mSendLevel
1744 // mReqFrameCount?
1745 // mNotificationFramesAct, mNotificationFramesReq, mNotificationsPerBufferReq
1746 // mLatency, mAfLatency, mAfFrameCount, mAfSampleRate
1747
Glenn Kasten38e905b2014-01-13 10:21:48 -08001748 }
1749
Eric Laurentf32d7812017-11-30 14:44:07 -08001750exit:
1751 if (status != NO_ERROR && callbackAdded) {
Eric Laurentad2e7b92017-09-14 20:06:42 -07001752 // note: mOutput is always valid is callbackAdded is true
Eric Laurent09f1ed22019-04-24 17:45:17 -07001753 AudioSystem::removeAudioDeviceCallback(this, mOutput, mPortId);
Eric Laurentad2e7b92017-09-14 20:06:42 -07001754 }
Eric Laurentf32d7812017-11-30 14:44:07 -08001755
1756 mStatus = status;
Eric Laurent21da6472017-11-09 16:29:26 -08001757
1758 // sp<IAudioTrack> track destructor will cause releaseOutput() to be called by AudioFlinger
Glenn Kasten38e905b2014-01-13 10:21:48 -08001759 return status;
Eric Laurent34f1d8e2009-11-04 08:27:26 -08001760}
1761
Glenn Kastenb46f3942015-03-09 12:00:30 -07001762status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount, size_t *nonContig)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001763{
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001764 if (audioBuffer == NULL) {
Glenn Kasten551b5352015-03-20 11:30:28 -07001765 if (nonContig != NULL) {
1766 *nonContig = 0;
1767 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001768 return BAD_VALUE;
Eric Laurent9b7d9502011-03-21 11:49:00 -07001769 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001770 if (mTransfer != TRANSFER_OBTAIN) {
1771 audioBuffer->frameCount = 0;
1772 audioBuffer->size = 0;
1773 audioBuffer->raw = NULL;
Glenn Kasten551b5352015-03-20 11:30:28 -07001774 if (nonContig != NULL) {
1775 *nonContig = 0;
1776 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001777 return INVALID_OPERATION;
1778 }
Eric Laurent9b7d9502011-03-21 11:49:00 -07001779
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001780 const struct timespec *requested;
Eric Laurentdf576992014-01-27 18:13:39 -08001781 struct timespec timeout;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001782 if (waitCount == -1) {
1783 requested = &ClientProxy::kForever;
1784 } else if (waitCount == 0) {
1785 requested = &ClientProxy::kNonBlocking;
1786 } else if (waitCount > 0) {
Chih-Hung Hsiehbca74292018-08-10 16:06:07 -07001787 time_t ms = WAIT_PERIOD_MS * (time_t) waitCount;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001788 timeout.tv_sec = ms / 1000;
Andy Hung06a730b2020-04-09 13:28:31 -07001789 timeout.tv_nsec = (ms % 1000) * 1000000;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001790 requested = &timeout;
1791 } else {
Eric Laurent973db022018-11-20 14:54:31 -08001792 ALOGE("%s(%d): invalid waitCount %d", __func__, mPortId, waitCount);
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001793 requested = NULL;
1794 }
Glenn Kastenb46f3942015-03-09 12:00:30 -07001795 return obtainBuffer(audioBuffer, requested, NULL /*elapsed*/, nonContig);
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001796}
Eric Laurent1703cdf2011-03-07 14:52:59 -08001797
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001798status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, const struct timespec *requested,
1799 struct timespec *elapsed, size_t *nonContig)
1800{
1801 // previous and new IAudioTrack sequence numbers are used to detect track re-creation
1802 uint32_t oldSequence = 0;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001803
1804 Proxy::Buffer buffer;
1805 status_t status = NO_ERROR;
1806
1807 static const int32_t kMaxTries = 5;
1808 int32_t tryCounter = kMaxTries;
1809
1810 do {
1811 // obtainBuffer() is called with mutex unlocked, so keep extra references to these fields to
1812 // keep them from going away if another thread re-creates the track during obtainBuffer()
1813 sp<AudioTrackClientProxy> proxy;
1814 sp<IMemory> iMem;
1815
1816 { // start of lock scope
1817 AutoMutex lock(mLock);
1818
Glenn Kasten305996c2020-01-27 08:03:37 -08001819 uint32_t newSequence = mSequence;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001820 // did previous obtainBuffer() fail due to media server death or voluntary invalidation?
1821 if (status == DEAD_OBJECT) {
1822 // re-create track, unless someone else has already done so
1823 if (newSequence == oldSequence) {
1824 status = restoreTrack_l("obtainBuffer");
1825 if (status != NO_ERROR) {
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +01001826 buffer.mFrameCount = 0;
1827 buffer.mRaw = NULL;
1828 buffer.mNonContig = 0;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001829 break;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001830 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001831 }
1832 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001833 oldSequence = newSequence;
1834
Eric Laurent4d231dc2016-03-11 18:38:23 -08001835 if (status == NOT_ENOUGH_DATA) {
1836 restartIfDisabled();
1837 }
1838
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001839 // Keep the extra references
1840 proxy = mProxy;
1841 iMem = mCblkMemory;
1842
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +01001843 if (mState == STATE_STOPPING) {
1844 status = -EINTR;
1845 buffer.mFrameCount = 0;
1846 buffer.mRaw = NULL;
1847 buffer.mNonContig = 0;
1848 break;
1849 }
1850
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001851 // Non-blocking if track is stopped or paused
1852 if (mState != STATE_ACTIVE) {
1853 requested = &ClientProxy::kNonBlocking;
1854 }
1855
1856 } // end of lock scope
1857
1858 buffer.mFrameCount = audioBuffer->frameCount;
1859 // FIXME starts the requested timeout and elapsed over from scratch
1860 status = proxy->obtainBuffer(&buffer, requested, elapsed);
Eric Laurent4d231dc2016-03-11 18:38:23 -08001861 } while (((status == DEAD_OBJECT) || (status == NOT_ENOUGH_DATA)) && (tryCounter-- > 0));
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001862
1863 audioBuffer->frameCount = buffer.mFrameCount;
Andy Hungabdb9902015-01-12 15:08:22 -08001864 audioBuffer->size = buffer.mFrameCount * mFrameSize;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001865 audioBuffer->raw = buffer.mRaw;
Glenn Kasten305996c2020-01-27 08:03:37 -08001866 audioBuffer->sequence = oldSequence;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001867 if (nonContig != NULL) {
1868 *nonContig = buffer.mNonContig;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001869 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001870 return status;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001871}
1872
Glenn Kasten54a8a452015-03-09 12:03:00 -07001873void AudioTrack::releaseBuffer(const Buffer* audioBuffer)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001874{
Glenn Kasten3f02be22015-03-09 11:59:04 -07001875 // FIXME add error checking on mode, by adding an internal version
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001876 if (mTransfer == TRANSFER_SHARED) {
1877 return;
1878 }
1879
Andy Hungabdb9902015-01-12 15:08:22 -08001880 size_t stepCount = audioBuffer->size / mFrameSize;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001881 if (stepCount == 0) {
1882 return;
1883 }
1884
1885 Proxy::Buffer buffer;
1886 buffer.mFrameCount = stepCount;
1887 buffer.mRaw = audioBuffer->raw;
Glenn Kastene3aa6592012-12-04 12:22:46 -08001888
Eric Laurent1703cdf2011-03-07 14:52:59 -08001889 AutoMutex lock(mLock);
Glenn Kasten305996c2020-01-27 08:03:37 -08001890 if (audioBuffer->sequence != mSequence) {
1891 // This Buffer came from a different IAudioTrack instance, so ignore the releaseBuffer
1892 ALOGD("%s is no-op due to IAudioTrack sequence mismatch %u != %u",
1893 __func__, audioBuffer->sequence, mSequence);
1894 return;
1895 }
Glenn Kasten200092b2014-08-15 15:13:30 -07001896 mReleased += stepCount;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001897 mInUnderrun = false;
1898 mProxy->releaseBuffer(&buffer);
1899
1900 // restart track if it was disabled by audioflinger due to previous underrun
Eric Laurent4d231dc2016-03-11 18:38:23 -08001901 restartIfDisabled();
1902}
1903
1904void AudioTrack::restartIfDisabled()
1905{
1906 int32_t flags = android_atomic_and(~CBLK_DISABLED, &mCblk->mFlags);
1907 if ((mState == STATE_ACTIVE) && (flags & CBLK_DISABLED)) {
Andy Hungfb8ede22018-09-12 19:03:24 -07001908 ALOGW("%s(%d): releaseBuffer() track %p disabled due to previous underrun, restarting",
Eric Laurent973db022018-11-20 14:54:31 -08001909 __func__, mPortId, this);
Eric Laurent4d231dc2016-03-11 18:38:23 -08001910 // FIXME ignoring status
1911 mAudioTrack->start();
Eric Laurentdf839842012-05-31 14:27:14 -07001912 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001913}
1914
1915// -------------------------------------------------------------------------
1916
Jean-Michel Trivi720ad9d2014-02-04 11:00:59 -08001917ssize_t AudioTrack::write(const void* buffer, size_t userSize, bool blocking)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001918{
Jean-Michel Trivif4158d82018-09-25 12:43:58 -07001919 if (mTransfer != TRANSFER_SYNC && mTransfer != TRANSFER_SYNC_NOTIF_CALLBACK) {
Glenn Kastend65d73c2012-06-22 17:21:07 -07001920 return INVALID_OPERATION;
1921 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001922
Eric Laurentab5cdba2014-06-09 17:22:27 -07001923 if (isDirect()) {
1924 AutoMutex lock(mLock);
1925 int32_t flags = android_atomic_and(
1926 ~(CBLK_UNDERRUN | CBLK_LOOP_CYCLE | CBLK_LOOP_FINAL | CBLK_BUFFER_END),
1927 &mCblk->mFlags);
1928 if (flags & CBLK_INVALID) {
1929 return DEAD_OBJECT;
1930 }
1931 }
1932
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001933 if (ssize_t(userSize) < 0 || (buffer == NULL && userSize != 0)) {
Glenn Kasten99e53b82012-01-19 08:59:58 -08001934 // Sanity-check: user is most-likely passing an error code, and it would
1935 // make the return value ambiguous (actualSize vs error).
Andy Hungfb8ede22018-09-12 19:03:24 -07001936 ALOGE("%s(%d): AudioTrack::write(buffer=%p, size=%zu (%zd)",
Eric Laurent973db022018-11-20 14:54:31 -08001937 __func__, mPortId, buffer, userSize, userSize);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001938 return BAD_VALUE;
1939 }
1940
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001941 size_t written = 0;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001942 Buffer audioBuffer;
1943
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001944 while (userSize >= mFrameSize) {
1945 audioBuffer.frameCount = userSize / mFrameSize;
Eric Laurentc2f1f072009-07-17 12:17:14 -07001946
Jean-Michel Trivi720ad9d2014-02-04 11:00:59 -08001947 status_t err = obtainBuffer(&audioBuffer,
1948 blocking ? &ClientProxy::kForever : &ClientProxy::kNonBlocking);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001949 if (err < 0) {
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001950 if (written > 0) {
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001951 break;
Glenn Kastend65d73c2012-06-22 17:21:07 -07001952 }
Glenn Kasten0a2f1512016-07-22 08:06:37 -07001953 if (err == TIMED_OUT || err == -EINTR) {
1954 err = WOULD_BLOCK;
1955 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001956 return ssize_t(err);
1957 }
1958
Glenn Kastenae4b8792015-03-20 09:04:21 -07001959 size_t toWrite = audioBuffer.size;
Andy Hungabdb9902015-01-12 15:08:22 -08001960 memcpy(audioBuffer.i8, buffer, toWrite);
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001961 buffer = ((const char *) buffer) + toWrite;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001962 userSize -= toWrite;
1963 written += toWrite;
1964
1965 releaseBuffer(&audioBuffer);
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001966 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001967
Andy Hungea2b9c02016-02-12 17:06:53 -08001968 if (written > 0) {
1969 mFramesWritten += written / mFrameSize;
Jean-Michel Trivif4158d82018-09-25 12:43:58 -07001970
1971 if (mTransfer == TRANSFER_SYNC_NOTIF_CALLBACK) {
1972 const sp<AudioTrackThread> t = mAudioTrackThread;
1973 if (t != 0) {
1974 // causes wake up of the playback thread, that will callback the client for
1975 // more data (with EVENT_CAN_WRITE_MORE_DATA) in processAudioBuffer()
1976 t->wake();
1977 }
1978 }
Andy Hungea2b9c02016-02-12 17:06:53 -08001979 }
Jean-Michel Trivif4158d82018-09-25 12:43:58 -07001980
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001981 return written;
1982}
1983
1984// -------------------------------------------------------------------------
1985
Glenn Kasten7c7be1e2013-12-19 16:34:04 -08001986nsecs_t AudioTrack::processAudioBuffer()
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001987{
Glenn Kastenfb1fdc92013-07-10 17:03:19 -07001988 // Currently the AudioTrack thread is not created if there are no callbacks.
1989 // Would it ever make sense to run the thread, even without callbacks?
1990 // If so, then replace this by checks at each use for mCbf != NULL.
1991 LOG_ALWAYS_FATAL_IF(mCblk == NULL);
1992
Eric Laurent1703cdf2011-03-07 14:52:59 -08001993 mLock.lock();
Glenn Kastena07f17c2013-04-23 12:39:37 -07001994 if (mAwaitBoost) {
1995 mAwaitBoost = false;
1996 mLock.unlock();
1997 static const int32_t kMaxTries = 5;
1998 int32_t tryCounter = kMaxTries;
1999 uint32_t pollUs = 10000;
2000 do {
Glenn Kasten8255ba72016-08-23 13:54:23 -07002001 int policy = sched_getscheduler(0) & ~SCHED_RESET_ON_FORK;
Glenn Kastena07f17c2013-04-23 12:39:37 -07002002 if (policy == SCHED_FIFO || policy == SCHED_RR) {
2003 break;
2004 }
2005 usleep(pollUs);
2006 pollUs <<= 1;
2007 } while (tryCounter-- > 0);
2008 if (tryCounter < 0) {
Andy Hungfb8ede22018-09-12 19:03:24 -07002009 ALOGE("%s(%d): did not receive expected priority boost on time",
Eric Laurent973db022018-11-20 14:54:31 -08002010 __func__, mPortId);
Glenn Kastena07f17c2013-04-23 12:39:37 -07002011 }
Glenn Kastenb0dfd462013-07-10 16:52:47 -07002012 // Run again immediately
2013 return 0;
Glenn Kastena07f17c2013-04-23 12:39:37 -07002014 }
Eric Laurent1703cdf2011-03-07 14:52:59 -08002015
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002016 // Can only reference mCblk while locked
2017 int32_t flags = android_atomic_and(
Glenn Kasten96f60d82013-07-12 10:21:18 -07002018 ~(CBLK_UNDERRUN | CBLK_LOOP_CYCLE | CBLK_LOOP_FINAL | CBLK_BUFFER_END), &mCblk->mFlags);
Glenn Kastena47f3162012-11-07 10:13:08 -08002019
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002020 // Check for track invalidation
2021 if (flags & CBLK_INVALID) {
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +01002022 // for offloaded tracks restoreTrack_l() will just update the sequence and clear
2023 // AudioSystem cache. We should not exit here but after calling the callback so
2024 // that the upper layers can recreate the track
Eric Laurentab5cdba2014-06-09 17:22:27 -07002025 if (!isOffloadedOrDirect_l() || (mSequence == mObservedSequence)) {
Lajos Molnarf1063e22015-04-17 15:19:42 -07002026 status_t status __unused = restoreTrack_l("processAudioBuffer");
2027 // FIXME unused status
Andy Hung53c3b5f2014-12-15 16:42:05 -08002028 // after restoration, continue below to make sure that the loop and buffer events
2029 // are notified because they have been cleared from mCblk->mFlags above.
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +01002030 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002031 }
2032
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +01002033 bool waitStreamEnd = mState == STATE_STOPPING;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002034 bool active = mState == STATE_ACTIVE;
2035
2036 // Manage underrun callback, must be done under lock to avoid race with releaseBuffer()
2037 bool newUnderrun = false;
2038 if (flags & CBLK_UNDERRUN) {
2039#if 0
2040 // Currently in shared buffer mode, when the server reaches the end of buffer,
2041 // the track stays active in continuous underrun state. It's up to the application
2042 // to pause or stop the track, or set the position to a new offset within buffer.
2043 // This was some experimental code to auto-pause on underrun. Keeping it here
2044 // in "if 0" so we can re-visit this if we add a real sequencer for shared memory content.
2045 if (mTransfer == TRANSFER_SHARED) {
2046 mState = STATE_PAUSED;
2047 active = false;
2048 }
2049#endif
2050 if (!mInUnderrun) {
2051 mInUnderrun = true;
2052 newUnderrun = true;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08002053 }
2054 }
Eric Laurentc2f1f072009-07-17 12:17:14 -07002055
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002056 // Get current position of server
Andy Hung90e8a972015-11-09 16:42:40 -08002057 Modulo<uint32_t> position(updateAndGetPosition_l());
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08002058
2059 // Manage marker callback
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002060 bool markerReached = false;
Andy Hung90e8a972015-11-09 16:42:40 -08002061 Modulo<uint32_t> markerPosition(mMarkerPosition);
2062 // uses 32 bit wraparound for comparison with position.
2063 if (!mMarkerReached && markerPosition.value() > 0 && position >= markerPosition) {
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002064 mMarkerReached = markerReached = true;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08002065 }
2066
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002067 // Determine number of new position callback(s) that will be needed, while locked
2068 size_t newPosCount = 0;
Andy Hung90e8a972015-11-09 16:42:40 -08002069 Modulo<uint32_t> newPosition(mNewPosition);
2070 uint32_t updatePeriod = mUpdatePeriod;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002071 // FIXME fails for wraparound, need 64 bits
2072 if (updatePeriod > 0 && position >= newPosition) {
Andy Hung90e8a972015-11-09 16:42:40 -08002073 newPosCount = ((position - newPosition).value() / updatePeriod) + 1;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002074 mNewPosition += updatePeriod * newPosCount;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08002075 }
2076
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002077 // Cache other fields that will be needed soon
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002078 uint32_t sampleRate = mSampleRate;
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -07002079 float speed = mPlaybackRate.mSpeed;
Andy Hunga7f03352015-05-31 21:54:49 -07002080 const uint32_t notificationFrames = mNotificationFramesAct;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002081 if (mRefreshRemaining) {
2082 mRefreshRemaining = false;
2083 mRemainingFrames = notificationFrames;
2084 mRetryOnPartialBuffer = false;
2085 }
2086 size_t misalignment = mProxy->getMisalignment();
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +01002087 uint32_t sequence = mSequence;
Glenn Kasten96f04882013-09-20 09:28:56 -07002088 sp<AudioTrackClientProxy> proxy = mProxy;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002089
Andy Hung53c3b5f2014-12-15 16:42:05 -08002090 // Determine the number of new loop callback(s) that will be needed, while locked.
2091 int loopCountNotifications = 0;
2092 uint32_t loopPeriod = 0; // time in frames for next EVENT_LOOP_END or EVENT_BUFFER_END
2093
2094 if (mLoopCount > 0) {
2095 int loopCount;
2096 size_t bufferPosition;
2097 mStaticProxy->getBufferPositionAndLoopCount(&bufferPosition, &loopCount);
2098 loopPeriod = ((loopCount > 0) ? mLoopEnd : mFrameCount) - bufferPosition;
2099 loopCountNotifications = min(mLoopCountNotified - loopCount, kMaxLoopCountNotifications);
2100 mLoopCountNotified = loopCount; // discard any excess notifications
2101 } else if (mLoopCount < 0) {
2102 // FIXME: We're not accurate with notification count and position with infinite looping
2103 // since loopCount from server side will always return -1 (we could decrement it).
2104 size_t bufferPosition = mStaticProxy->getBufferPosition();
2105 loopCountNotifications = int((flags & (CBLK_LOOP_CYCLE | CBLK_LOOP_FINAL)) != 0);
2106 loopPeriod = mLoopEnd - bufferPosition;
2107 } else if (/* mLoopCount == 0 && */ mSharedBuffer != 0) {
2108 size_t bufferPosition = mStaticProxy->getBufferPosition();
2109 loopPeriod = mFrameCount - bufferPosition;
2110 }
2111
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002112 // These fields don't need to be cached, because they are assigned only by set():
Andy Hungabdb9902015-01-12 15:08:22 -08002113 // mTransfer, mCbf, mUserData, mFormat, mFrameSize, mFlags
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002114 // mFlags is also assigned by createTrack_l(), but not the bit we care about.
2115
2116 mLock.unlock();
2117
Andy Hunga7f03352015-05-31 21:54:49 -07002118 // get anchor time to account for callbacks.
2119 const nsecs_t timeBeforeCallbacks = systemTime();
2120
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +01002121 if (waitStreamEnd) {
Andy Hunga7f03352015-05-31 21:54:49 -07002122 // FIXME: Instead of blocking in proxy->waitStreamEndDone(), Callback thread
2123 // should wait on proxy futex and handle CBLK_STREAM_END_DONE within this function
2124 // (and make sure we don't callback for more data while we're stopping).
2125 // This helps with position, marker notifications, and track invalidation.
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +01002126 struct timespec timeout;
2127 timeout.tv_sec = WAIT_STREAM_END_TIMEOUT_SEC;
2128 timeout.tv_nsec = 0;
2129
Glenn Kasten96f04882013-09-20 09:28:56 -07002130 status_t status = proxy->waitStreamEndDone(&timeout);
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +01002131 switch (status) {
2132 case NO_ERROR:
2133 case DEAD_OBJECT:
2134 case TIMED_OUT:
Andy Hung39609a02015-09-03 16:38:38 -07002135 if (status != DEAD_OBJECT) {
2136 // for DEAD_OBJECT, we do not send a EVENT_STREAM_END after stop();
2137 // instead, the application should handle the EVENT_NEW_IAUDIOTRACK.
2138 mCbf(EVENT_STREAM_END, mUserData, NULL);
2139 }
Glenn Kasten96f04882013-09-20 09:28:56 -07002140 {
2141 AutoMutex lock(mLock);
2142 // The previously assigned value of waitStreamEnd is no longer valid,
2143 // since the mutex has been unlocked and either the callback handler
2144 // or another thread could have re-started the AudioTrack during that time.
2145 waitStreamEnd = mState == STATE_STOPPING;
2146 if (waitStreamEnd) {
2147 mState = STATE_STOPPED;
Andy Hungc2813e52014-10-16 17:54:34 -07002148 mReleased = 0;
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +01002149 }
2150 }
Glenn Kasten96f04882013-09-20 09:28:56 -07002151 if (waitStreamEnd && status != DEAD_OBJECT) {
2152 return NS_INACTIVE;
2153 }
2154 break;
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +01002155 }
Glenn Kasten96f04882013-09-20 09:28:56 -07002156 return 0;
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +01002157 }
2158
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002159 // perform callbacks while unlocked
2160 if (newUnderrun) {
2161 mCbf(EVENT_UNDERRUN, mUserData, NULL);
2162 }
Andy Hung53c3b5f2014-12-15 16:42:05 -08002163 while (loopCountNotifications > 0) {
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002164 mCbf(EVENT_LOOP_END, mUserData, NULL);
Andy Hung53c3b5f2014-12-15 16:42:05 -08002165 --loopCountNotifications;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002166 }
2167 if (flags & CBLK_BUFFER_END) {
2168 mCbf(EVENT_BUFFER_END, mUserData, NULL);
2169 }
2170 if (markerReached) {
2171 mCbf(EVENT_MARKER, mUserData, &markerPosition);
2172 }
2173 while (newPosCount > 0) {
Andy Hung90e8a972015-11-09 16:42:40 -08002174 size_t temp = newPosition.value(); // FIXME size_t != uint32_t
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002175 mCbf(EVENT_NEW_POS, mUserData, &temp);
2176 newPosition += updatePeriod;
2177 newPosCount--;
2178 }
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +01002179
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002180 if (mObservedSequence != sequence) {
2181 mObservedSequence = sequence;
2182 mCbf(EVENT_NEW_IAUDIOTRACK, mUserData, NULL);
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +01002183 // for offloaded tracks, just wait for the upper layers to recreate the track
Eric Laurentab5cdba2014-06-09 17:22:27 -07002184 if (isOffloadedOrDirect()) {
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +01002185 return NS_INACTIVE;
2186 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08002187 }
2188
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002189 // if inactive, then don't run me again until re-started
2190 if (!active) {
2191 return NS_INACTIVE;
Eric Laurent2267ba12011-09-07 11:13:23 -07002192 }
2193
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002194 // Compute the estimated time until the next timed event (position, markers, loops)
2195 // FIXME only for non-compressed audio
2196 uint32_t minFrames = ~0;
2197 if (!markerReached && position < markerPosition) {
Andy Hung90e8a972015-11-09 16:42:40 -08002198 minFrames = (markerPosition - position).value();
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002199 }
2200 if (loopPeriod > 0 && loopPeriod < minFrames) {
Andy Hung2d85f092015-01-07 12:45:13 -08002201 // loopPeriod is already adjusted for actual position.
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002202 minFrames = loopPeriod;
2203 }
Andy Hung2d85f092015-01-07 12:45:13 -08002204 if (updatePeriod > 0) {
Andy Hung90e8a972015-11-09 16:42:40 -08002205 minFrames = min(minFrames, (newPosition - position).value());
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002206 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08002207
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002208 // If > 0, poll periodically to recover from a stuck server. A good value is 2.
2209 static const uint32_t kPoll = 0;
2210 if (kPoll > 0 && mTransfer == TRANSFER_CALLBACK && kPoll * notificationFrames < minFrames) {
2211 minFrames = kPoll * notificationFrames;
2212 }
Eric Laurentc2f1f072009-07-17 12:17:14 -07002213
Andy Hunga7f03352015-05-31 21:54:49 -07002214 // This "fudge factor" avoids soaking CPU, and compensates for late progress by server
2215 static const nsecs_t kWaitPeriodNs = WAIT_PERIOD_MS * 1000000LL;
2216 const nsecs_t timeAfterCallbacks = systemTime();
2217
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002218 // Convert frame units to time units
2219 nsecs_t ns = NS_WHENEVER;
2220 if (minFrames != (uint32_t) ~0) {
jiabinc7bb8322017-09-06 18:20:11 -07002221 // AudioFlinger consumption of client data may be irregular when coming out of device
2222 // standby since the kernel buffers require filling. This is throttled to no more than 2x
2223 // the expected rate in the MixerThread. Hence, we reduce the estimated time to wait by one
2224 // half (but no more than half a second) to improve callback accuracy during these temporary
2225 // data surges.
2226 const nsecs_t estimatedNs = framesToNanoseconds(minFrames, sampleRate, speed);
2227 constexpr nsecs_t maxThrottleCompensationNs = 500000000LL;
2228 ns = estimatedNs - min(estimatedNs / 2, maxThrottleCompensationNs) + kWaitPeriodNs;
Andy Hunga7f03352015-05-31 21:54:49 -07002229 ns -= (timeAfterCallbacks - timeBeforeCallbacks); // account for callback time
2230 // TODO: Should we warn if the callback time is too long?
2231 if (ns < 0) ns = 0;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002232 }
2233
Jean-Michel Trivif4158d82018-09-25 12:43:58 -07002234 // If not supplying data by EVENT_MORE_DATA or EVENT_CAN_WRITE_MORE_DATA, then we're done
2235 if (mTransfer != TRANSFER_CALLBACK && mTransfer != TRANSFER_SYNC_NOTIF_CALLBACK) {
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002236 return ns;
2237 }
2238
Andy Hunga7f03352015-05-31 21:54:49 -07002239 // EVENT_MORE_DATA callback handling.
2240 // Timing for linear pcm audio data formats can be derived directly from the
2241 // buffer fill level.
2242 // Timing for compressed data is not directly available from the buffer fill level,
2243 // rather indirectly from waiting for blocking mode callbacks or waiting for obtain()
2244 // to return a certain fill level.
2245
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002246 struct timespec timeout;
2247 const struct timespec *requested = &ClientProxy::kForever;
2248 if (ns != NS_WHENEVER) {
2249 timeout.tv_sec = ns / 1000000000LL;
2250 timeout.tv_nsec = ns % 1000000000LL;
Andy Hungfb8ede22018-09-12 19:03:24 -07002251 ALOGV("%s(%d): timeout %ld.%03d",
Eric Laurent973db022018-11-20 14:54:31 -08002252 __func__, mPortId, timeout.tv_sec, (int) timeout.tv_nsec / 1000000);
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002253 requested = &timeout;
2254 }
2255
Andy Hungea2b9c02016-02-12 17:06:53 -08002256 size_t writtenFrames = 0;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002257 while (mRemainingFrames > 0) {
2258
2259 Buffer audioBuffer;
2260 audioBuffer.frameCount = mRemainingFrames;
2261 size_t nonContig;
2262 status_t err = obtainBuffer(&audioBuffer, requested, NULL, &nonContig);
2263 LOG_ALWAYS_FATAL_IF((err != NO_ERROR) != (audioBuffer.frameCount == 0),
Andy Hungfb8ede22018-09-12 19:03:24 -07002264 "%s(%d): obtainBuffer() err=%d frameCount=%zu",
Eric Laurent973db022018-11-20 14:54:31 -08002265 __func__, mPortId, err, audioBuffer.frameCount);
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002266 requested = &ClientProxy::kNonBlocking;
2267 size_t avail = audioBuffer.frameCount + nonContig;
Andy Hungfb8ede22018-09-12 19:03:24 -07002268 ALOGV("%s(%d): obtainBuffer(%u) returned %zu = %zu + %zu err %d",
Eric Laurent973db022018-11-20 14:54:31 -08002269 __func__, mPortId, mRemainingFrames, avail, audioBuffer.frameCount, nonContig, err);
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002270 if (err != NO_ERROR) {
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +01002271 if (err == TIMED_OUT || err == WOULD_BLOCK || err == -EINTR ||
2272 (isOffloaded() && (err == DEAD_OBJECT))) {
Glenn Kasten606fbc12015-10-22 15:28:15 -07002273 // FIXME bug 25195759
2274 return 1000000;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08002275 }
Andy Hungfb8ede22018-09-12 19:03:24 -07002276 ALOGE("%s(%d): Error %d obtaining an audio buffer, giving up.",
Eric Laurent973db022018-11-20 14:54:31 -08002277 __func__, mPortId, err);
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002278 return NS_NEVER;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08002279 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002280
Phil Burkfdb3c072016-02-09 10:47:02 -08002281 if (mRetryOnPartialBuffer && audio_has_proportional_frames(mFormat)) {
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002282 mRetryOnPartialBuffer = false;
2283 if (avail < mRemainingFrames) {
Andy Hunga7f03352015-05-31 21:54:49 -07002284 if (ns > 0) { // account for obtain time
2285 const nsecs_t timeNow = systemTime();
2286 ns = max((nsecs_t)0, ns - (timeNow - timeAfterCallbacks));
2287 }
Andy Hungeb6e6502019-04-29 13:47:40 -07002288
2289 // delayNs is first computed by the additional frames required in the buffer.
2290 nsecs_t delayNs = framesToNanoseconds(
2291 mRemainingFrames - avail, sampleRate, speed);
2292
2293 // afNs is the AudioFlinger mixer period in ns.
2294 const nsecs_t afNs = framesToNanoseconds(mAfFrameCount, mAfSampleRate, speed);
2295
2296 // If the AudioTrack is double buffered based on the AudioFlinger mixer period,
2297 // we may have a race if we wait based on the number of frames desired.
2298 // This is a possible issue with resampling and AAudio.
2299 //
2300 // The granularity of audioflinger processing is one mixer period; if
2301 // our wait time is less than one mixer period, wait at most half the period.
2302 if (delayNs < afNs) {
2303 delayNs = std::min(delayNs, afNs / 2);
2304 }
2305
2306 // adjust our ns wait by delayNs.
2307 if (ns < 0 /* NS_WHENEVER */ || delayNs < ns) {
2308 ns = delayNs;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002309 }
2310 return ns;
2311 }
Glenn Kastend65d73c2012-06-22 17:21:07 -07002312 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08002313
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08002314 size_t reqSize = audioBuffer.size;
Jean-Michel Trivif4158d82018-09-25 12:43:58 -07002315 if (mTransfer == TRANSFER_SYNC_NOTIF_CALLBACK) {
2316 // when notifying client it can write more data, pass the total size that can be
2317 // written in the next write() call, since it's not passed through the callback
2318 audioBuffer.size += nonContig;
2319 }
2320 mCbf(mTransfer == TRANSFER_CALLBACK ? EVENT_MORE_DATA : EVENT_CAN_WRITE_MORE_DATA,
2321 mUserData, &audioBuffer);
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002322 size_t writtenSize = audioBuffer.size;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08002323
2324 // Sanity check on returned size
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002325 if (ssize_t(writtenSize) < 0 || writtenSize > reqSize) {
Andy Hungfb8ede22018-09-12 19:03:24 -07002326 ALOGE("%s(%d): EVENT_MORE_DATA requested %zu bytes but callback returned %zd bytes",
Eric Laurent973db022018-11-20 14:54:31 -08002327 __func__, mPortId, reqSize, ssize_t(writtenSize));
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002328 return NS_NEVER;
2329 }
2330
2331 if (writtenSize == 0) {
Jean-Michel Trivif4158d82018-09-25 12:43:58 -07002332 if (mTransfer == TRANSFER_SYNC_NOTIF_CALLBACK) {
2333 // The callback EVENT_CAN_WRITE_MORE_DATA was processed in the JNI of
2334 // android.media.AudioTrack. The JNI is not using the callback to provide data,
2335 // it only signals to the Java client that it can provide more data, which
2336 // this track is read to accept now.
2337 // The playback thread will be awaken at the next ::write()
2338 return NS_WHENEVER;
2339 }
The Android Open Source Project8555d082009-03-05 14:34:35 -08002340 // The callback is done filling buffers
2341 // Keep this thread going to handle timed events and
2342 // still try to get more data in intervals of WAIT_PERIOD_MS
2343 // but don't just loop and block the CPU, so wait
Andy Hunga7f03352015-05-31 21:54:49 -07002344
2345 // mCbf(EVENT_MORE_DATA, ...) might either
2346 // (1) Block until it can fill the buffer, returning 0 size on EOS.
2347 // (2) Block until it can fill the buffer, returning 0 data (silence) on EOS.
2348 // (3) Return 0 size when no data is available, does not wait for more data.
2349 //
2350 // (1) and (2) occurs with AudioPlayer/AwesomePlayer; (3) occurs with NuPlayer.
2351 // We try to compute the wait time to avoid a tight sleep-wait cycle,
2352 // especially for case (3).
2353 //
2354 // The decision to support (1) and (2) affect the sizing of mRemainingFrames
2355 // and this loop; whereas for case (3) we could simply check once with the full
2356 // buffer size and skip the loop entirely.
2357
2358 nsecs_t myns;
Phil Burkfdb3c072016-02-09 10:47:02 -08002359 if (audio_has_proportional_frames(mFormat)) {
Andy Hunga7f03352015-05-31 21:54:49 -07002360 // time to wait based on buffer occupancy
2361 const nsecs_t datans = mRemainingFrames <= avail ? 0 :
2362 framesToNanoseconds(mRemainingFrames - avail, sampleRate, speed);
2363 // audio flinger thread buffer size (TODO: adjust for fast tracks)
Glenn Kastenea38ee72016-04-18 11:08:01 -07002364 // FIXME: use mAfFrameCountHAL instead of mAfFrameCount below for fast tracks.
Andy Hunga7f03352015-05-31 21:54:49 -07002365 const nsecs_t afns = framesToNanoseconds(mAfFrameCount, mAfSampleRate, speed);
2366 // add a half the AudioFlinger buffer time to avoid soaking CPU if datans is 0.
2367 myns = datans + (afns / 2);
2368 } else {
2369 // FIXME: This could ping quite a bit if the buffer isn't full.
2370 // Note that when mState is stopping we waitStreamEnd, so it never gets here.
2371 myns = kWaitPeriodNs;
2372 }
2373 if (ns > 0) { // account for obtain and callback time
2374 const nsecs_t timeNow = systemTime();
2375 ns = max((nsecs_t)0, ns - (timeNow - timeAfterCallbacks));
2376 }
2377 if (ns < 0 /* NS_WHENEVER */ || myns < ns) {
2378 ns = myns;
2379 }
2380 return ns;
Glenn Kastend65d73c2012-06-22 17:21:07 -07002381 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08002382
Glenn Kasten138d6f92015-03-20 10:54:51 -07002383 size_t releasedFrames = writtenSize / mFrameSize;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002384 audioBuffer.frameCount = releasedFrames;
2385 mRemainingFrames -= releasedFrames;
2386 if (misalignment >= releasedFrames) {
2387 misalignment -= releasedFrames;
2388 } else {
2389 misalignment = 0;
2390 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08002391
2392 releaseBuffer(&audioBuffer);
Andy Hungea2b9c02016-02-12 17:06:53 -08002393 writtenFrames += releasedFrames;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08002394
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002395 // FIXME here is where we would repeat EVENT_MORE_DATA again on same advanced buffer
2396 // if callback doesn't like to accept the full chunk
2397 if (writtenSize < reqSize) {
2398 continue;
2399 }
2400
2401 // There could be enough non-contiguous frames available to satisfy the remaining request
2402 if (mRemainingFrames <= nonContig) {
2403 continue;
2404 }
2405
2406#if 0
2407 // This heuristic tries to collapse a series of EVENT_MORE_DATA that would total to a
2408 // sum <= notificationFrames. It replaces that series by at most two EVENT_MORE_DATA
2409 // that total to a sum == notificationFrames.
2410 if (0 < misalignment && misalignment <= mRemainingFrames) {
2411 mRemainingFrames = misalignment;
Andy Hung8edb8dc2015-03-26 19:13:55 -07002412 return ((double)mRemainingFrames * 1100000000) / ((double)sampleRate * speed);
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002413 }
2414#endif
2415
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08002416 }
Andy Hungea2b9c02016-02-12 17:06:53 -08002417 if (writtenFrames > 0) {
2418 AutoMutex lock(mLock);
2419 mFramesWritten += writtenFrames;
2420 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002421 mRemainingFrames = notificationFrames;
2422 mRetryOnPartialBuffer = true;
2423
2424 // A lot has transpired since ns was calculated, so run again immediately and re-calculate
2425 return 0;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08002426}
2427
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002428status_t AudioTrack::restoreTrack_l(const char *from)
Eric Laurent1703cdf2011-03-07 14:52:59 -08002429{
Andy Hungb68f5eb2019-12-03 16:49:17 -08002430 status_t result = NO_ERROR; // logged: make sure to set this before returning.
2431 const int64_t beginNs = systemTime();
2432 mediametrics::Defer([&] {
2433 mediametrics::LogItem(mMetricsId)
2434 .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_RESTORE)
2435 .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
2436 .set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
2437 .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)result)
2438 .set(AMEDIAMETRICS_PROP_WHERE, from)
2439 .record(); });
2440
Andy Hungfb8ede22018-09-12 19:03:24 -07002441 ALOGW("%s(%d): dead IAudioTrack, %s, creating a new one from %s()",
Eric Laurent973db022018-11-20 14:54:31 -08002442 __func__, mPortId, isOffloadedOrDirect_l() ? "Offloaded or Direct" : "PCM", from);
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002443 ++mSequence;
Eric Laurent1703cdf2011-03-07 14:52:59 -08002444
Glenn Kastena47f3162012-11-07 10:13:08 -08002445 // refresh the audio configuration cache in this process to make sure we get new
Glenn Kastend2d089f2014-11-05 11:48:12 -08002446 // output parameters and new IAudioFlinger in createTrack_l()
Glenn Kastena47f3162012-11-07 10:13:08 -08002447 AudioSystem::clearAudioConfigCache();
Eric Laurent9f6530f2011-08-30 10:18:54 -07002448
Ronghua Wufaeb0f22015-05-21 12:20:21 -07002449 if (isOffloadedOrDirect_l() || mDoNotReconnect) {
Andy Hung1f1db832015-06-08 13:26:10 -07002450 // FIXME re-creation of offloaded and direct tracks is not yet implemented;
2451 // reconsider enabling for linear PCM encodings when position can be preserved.
Andy Hungb68f5eb2019-12-03 16:49:17 -08002452 result = DEAD_OBJECT;
2453 return result;
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +01002454 }
2455
Phil Burk2812d9e2016-01-04 10:34:30 -08002456 // Save so we can return count since creation.
2457 mUnderrunCountOffset = getUnderrunCount_l();
2458
Glenn Kasten200092b2014-08-15 15:13:30 -07002459 // save the old static buffer position
Andy Hungf20a4e92016-08-15 19:10:34 -07002460 uint32_t staticPosition = 0;
Andy Hung4ede21d2014-12-12 15:37:34 -08002461 size_t bufferPosition = 0;
2462 int loopCount = 0;
2463 if (mStaticProxy != 0) {
2464 mStaticProxy->getBufferPositionAndLoopCount(&bufferPosition, &loopCount);
Andy Hungf20a4e92016-08-15 19:10:34 -07002465 staticPosition = mStaticProxy->getPosition().unsignedValue();
Andy Hung4ede21d2014-12-12 15:37:34 -08002466 }
Glenn Kasten200092b2014-08-15 15:13:30 -07002467
Mikhail Naganovb13b35d2018-03-30 17:21:14 -07002468 // See b/74409267. Connecting to a BT A2DP device supporting multiple codecs
2469 // causes a lot of churn on the service side, and it can reject starting
2470 // playback of a previously created track. May also apply to other cases.
2471 const int INITIAL_RETRIES = 3;
2472 int retries = INITIAL_RETRIES;
2473retry:
2474 if (retries < INITIAL_RETRIES) {
2475 // See the comment for clearAudioConfigCache at the start of the function.
2476 AudioSystem::clearAudioConfigCache();
2477 }
Haynes Mathew Georgeae34ed22016-01-28 11:58:39 -08002478 mFlags = mOrigFlags;
2479
Glenn Kasten200092b2014-08-15 15:13:30 -07002480 // If a new IAudioTrack is successfully created, createTrack_l() will modify the
Glenn Kastena47f3162012-11-07 10:13:08 -08002481 // following member variables: mAudioTrack, mCblkMemory and mCblk.
Glenn Kasten200092b2014-08-15 15:13:30 -07002482 // It will also delete the strong references on previous IAudioTrack and IMemory.
2483 // If a new IAudioTrack cannot be created, the previous (dead) instance will be left intact.
Andy Hungb68f5eb2019-12-03 16:49:17 -08002484 result = createTrack_l();
Eric Laurentcc21e4f2013-10-16 15:12:32 -07002485
Eric Laurent6ec546d2018-10-10 16:52:14 -07002486 if (result == NO_ERROR) {
Andy Hungd7bd69e2015-07-24 07:52:41 -07002487 // take the frames that will be lost by track recreation into account in saved position
2488 // For streaming tracks, this is the amount we obtained from the user/client
2489 // (not the number actually consumed at the server - those are already lost).
2490 if (mStaticProxy == 0) {
2491 mPosition = mReleased;
2492 }
Andy Hung4ede21d2014-12-12 15:37:34 -08002493 // Continue playback from last known position and restore loop.
2494 if (mStaticProxy != 0) {
2495 if (loopCount != 0) {
2496 mStaticProxy->setBufferPositionAndLoop(bufferPosition,
2497 mLoopStart, mLoopEnd, loopCount);
2498 } else {
2499 mStaticProxy->setBufferPosition(bufferPosition);
Andy Hung53c3b5f2014-12-15 16:42:05 -08002500 if (bufferPosition == mFrameCount) {
Eric Laurent973db022018-11-20 14:54:31 -08002501 ALOGD("%s(%d): restoring track at end of static buffer", __func__, mPortId);
Andy Hung53c3b5f2014-12-15 16:42:05 -08002502 }
Eric Laurent1703cdf2011-03-07 14:52:59 -08002503 }
2504 }
Andy Hung4ef88d72017-02-21 19:47:53 -08002505 // restore volume handler
Andy Hung39399b62017-04-21 15:07:45 -07002506 mVolumeHandler->forall([this](const VolumeShaper &shaper) -> VolumeShaper::Status {
2507 sp<VolumeShaper::Operation> operationToEnd =
2508 new VolumeShaper::Operation(shaper.mOperation);
Andy Hung4ef88d72017-02-21 19:47:53 -08002509 // TODO: Ideally we would restore to the exact xOffset position
2510 // as returned by getVolumeShaperState(), but we don't have that
2511 // information when restoring at the client unless we periodically poll
2512 // the server or create shared memory state.
2513 //
Andy Hung39399b62017-04-21 15:07:45 -07002514 // For now, we simply advance to the end of the VolumeShaper effect
2515 // if it has been started.
2516 if (shaper.isStarted()) {
Andy Hungf3702642017-05-05 17:33:32 -07002517 operationToEnd->setNormalizedTime(1.f);
Andy Hung39399b62017-04-21 15:07:45 -07002518 }
2519 return mAudioTrack->applyVolumeShaper(shaper.mConfiguration, operationToEnd);
Andy Hung4ef88d72017-02-21 19:47:53 -08002520 });
2521
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002522 if (mState == STATE_ACTIVE) {
Glenn Kastena47f3162012-11-07 10:13:08 -08002523 result = mAudioTrack->start();
Eric Laurent1703cdf2011-03-07 14:52:59 -08002524 }
Andy Hungf20a4e92016-08-15 19:10:34 -07002525 // server resets to zero so we offset
2526 mFramesWrittenServerOffset =
2527 mStaticProxy.get() != nullptr ? staticPosition : mFramesWritten;
2528 mFramesWrittenAtRestore = mFramesWrittenServerOffset;
Eric Laurent1703cdf2011-03-07 14:52:59 -08002529 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -08002530 if (result != NO_ERROR) {
Eric Laurent973db022018-11-20 14:54:31 -08002531 ALOGW("%s(%d): failed status %d, retries %d", __func__, mPortId, result, retries);
Mikhail Naganovb13b35d2018-03-30 17:21:14 -07002532 if (--retries > 0) {
Eric Laurent6ec546d2018-10-10 16:52:14 -07002533 // leave time for an eventual race condition to clear before retrying
2534 usleep(500000);
Mikhail Naganovb13b35d2018-03-30 17:21:14 -07002535 goto retry;
2536 }
Eric Laurent6ec546d2018-10-10 16:52:14 -07002537 // if no retries left, set invalid bit to force restoring at next occasion
2538 // and avoid inconsistent active state on client and server sides
2539 if (mCblk != nullptr) {
2540 android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
2541 }
Eric Laurent1703cdf2011-03-07 14:52:59 -08002542 }
Eric Laurent1703cdf2011-03-07 14:52:59 -08002543 return result;
2544}
2545
Andy Hung90e8a972015-11-09 16:42:40 -08002546Modulo<uint32_t> AudioTrack::updateAndGetPosition_l()
Glenn Kasten200092b2014-08-15 15:13:30 -07002547{
2548 // This is the sole place to read server consumed frames
Andy Hung90e8a972015-11-09 16:42:40 -08002549 Modulo<uint32_t> newServer(mProxy->getPosition());
2550 const int32_t delta = (newServer - mServer).signedValue();
Glenn Kasten200092b2014-08-15 15:13:30 -07002551 // TODO There is controversy about whether there can be "negative jitter" in server position.
2552 // This should be investigated further, and if possible, it should be addressed.
2553 // A more definite failure mode is infrequent polling by client.
2554 // One could call (void)getPosition_l() in releaseBuffer(),
2555 // so mReleased and mPosition are always lock-step as best possible.
2556 // That should ensure delta never goes negative for infrequent polling
2557 // unless the server has more than 2^31 frames in its buffer,
2558 // in which case the use of uint32_t for these counters has bigger issues.
Andy Hung90e8a972015-11-09 16:42:40 -08002559 ALOGE_IF(delta < 0,
Andy Hungfb8ede22018-09-12 19:03:24 -07002560 "%s(%d): detected illegal retrograde motion by the server: mServer advanced by %d",
Eric Laurent973db022018-11-20 14:54:31 -08002561 __func__, mPortId, delta);
Chad Brubaker039c27a2015-09-23 15:17:29 -07002562 mServer = newServer;
Andy Hung90e8a972015-11-09 16:42:40 -08002563 if (delta > 0) { // avoid retrograde
2564 mPosition += delta;
2565 }
2566 return mPosition;
Glenn Kasten200092b2014-08-15 15:13:30 -07002567}
2568
Haynes Mathew Georgefb12e202017-04-06 12:24:42 -07002569bool AudioTrack::isSampleRateSpeedAllowed_l(uint32_t sampleRate, float speed)
Andy Hung8edb8dc2015-03-26 19:13:55 -07002570{
Haynes Mathew Georgefb12e202017-04-06 12:24:42 -07002571 updateLatency_l();
Andy Hung8edb8dc2015-03-26 19:13:55 -07002572 // applicable for mixing tracks only (not offloaded or direct)
2573 if (mStaticProxy != 0) {
2574 return true; // static tracks do not have issues with buffer sizing.
2575 }
Andy Hung8edb8dc2015-03-26 19:13:55 -07002576 const size_t minFrameCount =
Eric Laurent21da6472017-11-09 16:29:26 -08002577 AudioSystem::calculateMinFrameCount(mAfLatency, mAfFrameCount, mAfSampleRate,
2578 sampleRate, speed /*, 0 mNotificationsPerBufferReq*/);
Haynes Mathew Georgefb12e202017-04-06 12:24:42 -07002579 const bool allowed = mFrameCount >= minFrameCount;
2580 ALOGD_IF(!allowed,
Andy Hungfb8ede22018-09-12 19:03:24 -07002581 "%s(%d): denied "
Haynes Mathew Georgefb12e202017-04-06 12:24:42 -07002582 "mAfLatency:%u mAfFrameCount:%zu mAfSampleRate:%u sampleRate:%u speed:%f "
2583 "mFrameCount:%zu < minFrameCount:%zu",
Eric Laurent973db022018-11-20 14:54:31 -08002584 __func__, mPortId,
Haynes Mathew Georgefb12e202017-04-06 12:24:42 -07002585 mAfLatency, mAfFrameCount, mAfSampleRate, sampleRate, speed,
Andy Hung8edb8dc2015-03-26 19:13:55 -07002586 mFrameCount, minFrameCount);
Haynes Mathew Georgefb12e202017-04-06 12:24:42 -07002587 return allowed;
Andy Hung8edb8dc2015-03-26 19:13:55 -07002588}
2589
Richard Fitzgeraldad3af332013-03-25 16:54:37 +00002590status_t AudioTrack::setParameters(const String8& keyValuePairs)
2591{
2592 AutoMutex lock(mLock);
Glenn Kasten53cec222013-08-29 09:01:02 -07002593 return mAudioTrack->setParameters(keyValuePairs);
Richard Fitzgeraldad3af332013-03-25 16:54:37 +00002594}
2595
Dean Wheatleya70eef72018-01-04 14:23:50 +11002596status_t AudioTrack::selectPresentation(int presentationId, int programId)
2597{
2598 AutoMutex lock(mLock);
Eric Laurent973db022018-11-20 14:54:31 -08002599 AudioParameter param = AudioParameter();
2600 param.addInt(String8(AudioParameter::keyPresentationId), presentationId);
2601 param.addInt(String8(AudioParameter::keyProgramId), programId);
2602 ALOGV("%s(%d): PresentationId/ProgramId[%s]",
2603 __func__, mPortId, param.toString().string());
2604
2605 return mAudioTrack->setParameters(param.toString());
Dean Wheatleya70eef72018-01-04 14:23:50 +11002606}
2607
Andy Hung9fc8b5c2017-01-24 13:36:48 -08002608VolumeShaper::Status AudioTrack::applyVolumeShaper(
2609 const sp<VolumeShaper::Configuration>& configuration,
2610 const sp<VolumeShaper::Operation>& operation)
2611{
2612 AutoMutex lock(mLock);
Andy Hung4ef88d72017-02-21 19:47:53 -08002613 mVolumeHandler->setIdIfNecessary(configuration);
Andy Hung9fc8b5c2017-01-24 13:36:48 -08002614 VolumeShaper::Status status = mAudioTrack->applyVolumeShaper(configuration, operation);
Andy Hung39399b62017-04-21 15:07:45 -07002615
2616 if (status == DEAD_OBJECT) {
2617 if (restoreTrack_l("applyVolumeShaper") == OK) {
2618 status = mAudioTrack->applyVolumeShaper(configuration, operation);
2619 }
2620 }
Andy Hung4ef88d72017-02-21 19:47:53 -08002621 if (status >= 0) {
2622 // save VolumeShaper for restore
2623 mVolumeHandler->applyVolumeShaper(configuration, operation);
Andy Hung39399b62017-04-21 15:07:45 -07002624 if (mState == STATE_ACTIVE || mState == STATE_STOPPING) {
2625 mVolumeHandler->setStarted();
2626 }
2627 } else {
2628 // warn only if not an expected restore failure.
2629 ALOGW_IF(!((isOffloadedOrDirect_l() || mDoNotReconnect) && status == DEAD_OBJECT),
Eric Laurent973db022018-11-20 14:54:31 -08002630 "%s(%d): applyVolumeShaper failed: %d", __func__, mPortId, status);
Andy Hung4ef88d72017-02-21 19:47:53 -08002631 }
Andy Hung9fc8b5c2017-01-24 13:36:48 -08002632 return status;
2633}
2634
2635sp<VolumeShaper::State> AudioTrack::getVolumeShaperState(int id)
2636{
Andy Hung9fc8b5c2017-01-24 13:36:48 -08002637 AutoMutex lock(mLock);
Andy Hung39399b62017-04-21 15:07:45 -07002638 sp<VolumeShaper::State> state = mAudioTrack->getVolumeShaperState(id);
2639 if (state.get() == nullptr && (mCblk->mFlags & CBLK_INVALID) != 0) {
2640 if (restoreTrack_l("getVolumeShaperState") == OK) {
2641 state = mAudioTrack->getVolumeShaperState(id);
2642 }
2643 }
2644 return state;
Andy Hung9fc8b5c2017-01-24 13:36:48 -08002645}
2646
Andy Hungea2b9c02016-02-12 17:06:53 -08002647status_t AudioTrack::getTimestamp(ExtendedTimestamp *timestamp)
2648{
2649 if (timestamp == nullptr) {
2650 return BAD_VALUE;
2651 }
2652 AutoMutex lock(mLock);
Andy Hunge13f8a62016-03-30 14:20:42 -07002653 return getTimestamp_l(timestamp);
2654}
2655
2656status_t AudioTrack::getTimestamp_l(ExtendedTimestamp *timestamp)
2657{
Andy Hungea2b9c02016-02-12 17:06:53 -08002658 if (mCblk->mFlags & CBLK_INVALID) {
2659 const status_t status = restoreTrack_l("getTimestampExtended");
2660 if (status != OK) {
2661 // per getTimestamp() API doc in header, we return DEAD_OBJECT here,
2662 // recommending that the track be recreated.
2663 return DEAD_OBJECT;
2664 }
2665 }
2666 // check for offloaded/direct here in case restoring somehow changed those flags.
2667 if (isOffloadedOrDirect_l()) {
2668 return INVALID_OPERATION; // not supported
2669 }
2670 status_t status = mProxy->getTimestamp(timestamp);
Andy Hungfb8ede22018-09-12 19:03:24 -07002671 LOG_ALWAYS_FATAL_IF(status != OK, "%s(%d): status %d not allowed from proxy getTimestamp",
Eric Laurent973db022018-11-20 14:54:31 -08002672 __func__, mPortId, status);
Andy Hungea2b9c02016-02-12 17:06:53 -08002673 bool found = false;
Andy Hunge1e98462016-04-12 10:18:51 -07002674 timestamp->mPosition[ExtendedTimestamp::LOCATION_CLIENT] = mFramesWritten;
2675 timestamp->mTimeNs[ExtendedTimestamp::LOCATION_CLIENT] = 0;
2676 // server side frame offset in case AudioTrack has been restored.
2677 for (int i = ExtendedTimestamp::LOCATION_SERVER;
2678 i < ExtendedTimestamp::LOCATION_MAX; ++i) {
2679 if (timestamp->mTimeNs[i] >= 0) {
2680 // apply server offset (frames flushed is ignored
2681 // so we don't report the jump when the flush occurs).
2682 timestamp->mPosition[i] += mFramesWrittenServerOffset;
2683 found = true;
Andy Hungea2b9c02016-02-12 17:06:53 -08002684 }
2685 }
2686 return found ? OK : WOULD_BLOCK;
2687}
2688
Glenn Kastence703742013-07-19 16:33:58 -07002689status_t AudioTrack::getTimestamp(AudioTimestamp& timestamp)
2690{
Glenn Kasten53cec222013-08-29 09:01:02 -07002691 AutoMutex lock(mLock);
Andy Hung65ffdfc2016-10-10 15:52:11 -07002692 return getTimestamp_l(timestamp);
2693}
Phil Burk1b420972015-04-22 10:52:21 -07002694
Andy Hung65ffdfc2016-10-10 15:52:11 -07002695status_t AudioTrack::getTimestamp_l(AudioTimestamp& timestamp)
2696{
Phil Burk1b420972015-04-22 10:52:21 -07002697 bool previousTimestampValid = mPreviousTimestampValid;
2698 // Set false here to cover all the error return cases.
2699 mPreviousTimestampValid = false;
2700
Andy Hung7f1bc8a2014-09-12 14:43:11 -07002701 switch (mState) {
2702 case STATE_ACTIVE:
2703 case STATE_PAUSED:
2704 break; // handle below
2705 case STATE_FLUSHED:
2706 case STATE_STOPPED:
2707 return WOULD_BLOCK;
2708 case STATE_STOPPING:
2709 case STATE_PAUSED_STOPPING:
2710 if (!isOffloaded_l()) {
2711 return INVALID_OPERATION;
2712 }
2713 break; // offloaded tracks handled below
2714 default:
Andy Hungfb8ede22018-09-12 19:03:24 -07002715 LOG_ALWAYS_FATAL("%s(%d): Invalid mState in getTimestamp(): %d",
Eric Laurent973db022018-11-20 14:54:31 -08002716 __func__, mPortId, mState);
Andy Hung7f1bc8a2014-09-12 14:43:11 -07002717 break;
Glenn Kastenfe346c72013-08-30 13:28:22 -07002718 }
Andy Hung7f1bc8a2014-09-12 14:43:11 -07002719
Eric Laurent275e8e92014-11-30 15:14:47 -08002720 if (mCblk->mFlags & CBLK_INVALID) {
Andy Hung6653c932015-06-08 13:27:48 -07002721 const status_t status = restoreTrack_l("getTimestamp");
2722 if (status != OK) {
2723 // per getTimestamp() API doc in header, we return DEAD_OBJECT here,
2724 // recommending that the track be recreated.
2725 return DEAD_OBJECT;
2726 }
Eric Laurent275e8e92014-11-30 15:14:47 -08002727 }
2728
Glenn Kasten200092b2014-08-15 15:13:30 -07002729 // The presented frame count must always lag behind the consumed frame count.
2730 // To avoid a race, read the presented frames first. This ensures that presented <= consumed.
Andy Hung6ae58432016-02-16 18:32:24 -08002731
2732 status_t status;
Andy Hung818e7a32016-02-16 18:08:07 -08002733 if (isOffloadedOrDirect_l()) {
Andy Hung6ae58432016-02-16 18:32:24 -08002734 // use Binder to get timestamp
2735 status = mAudioTrack->getTimestamp(timestamp);
2736 } else {
2737 // read timestamp from shared memory
2738 ExtendedTimestamp ets;
2739 status = mProxy->getTimestamp(&ets);
2740 if (status == OK) {
Andy Hungb01faa32016-04-27 12:51:32 -07002741 ExtendedTimestamp::Location location;
2742 status = ets.getBestTimestamp(&timestamp, &location);
2743
2744 if (status == OK) {
Haynes Mathew Georgefb12e202017-04-06 12:24:42 -07002745 updateLatency_l();
Andy Hungb01faa32016-04-27 12:51:32 -07002746 // It is possible that the best location has moved from the kernel to the server.
2747 // In this case we adjust the position from the previous computed latency.
2748 if (location == ExtendedTimestamp::LOCATION_SERVER) {
2749 ALOGW_IF(mPreviousLocation == ExtendedTimestamp::LOCATION_KERNEL,
Andy Hungfb8ede22018-09-12 19:03:24 -07002750 "%s(%d): location moved from kernel to server",
Eric Laurent973db022018-11-20 14:54:31 -08002751 __func__, mPortId);
Andy Hung07eee802016-06-21 16:47:16 -07002752 // check that the last kernel OK time info exists and the positions
2753 // are valid (if they predate the current track, the positions may
2754 // be zero or negative).
Andy Hungb01faa32016-04-27 12:51:32 -07002755 const int64_t frames =
Andy Hung6d7b1192016-05-07 22:59:48 -07002756 (ets.mTimeNs[ExtendedTimestamp::LOCATION_SERVER_LASTKERNELOK] < 0 ||
Andy Hung07eee802016-06-21 16:47:16 -07002757 ets.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL_LASTKERNELOK] < 0 ||
2758 ets.mPosition[ExtendedTimestamp::LOCATION_SERVER_LASTKERNELOK] <= 0 ||
2759 ets.mPosition[ExtendedTimestamp::LOCATION_KERNEL_LASTKERNELOK] <= 0)
Andy Hung6d7b1192016-05-07 22:59:48 -07002760 ?
2761 int64_t((double)mAfLatency * mSampleRate * mPlaybackRate.mSpeed
2762 / 1000)
2763 :
2764 (ets.mPosition[ExtendedTimestamp::LOCATION_SERVER_LASTKERNELOK]
2765 - ets.mPosition[ExtendedTimestamp::LOCATION_KERNEL_LASTKERNELOK]);
Andy Hungfb8ede22018-09-12 19:03:24 -07002766 ALOGV("%s(%d): frame adjustment:%lld timestamp:%s",
Eric Laurent973db022018-11-20 14:54:31 -08002767 __func__, mPortId, (long long)frames, ets.toString().c_str());
Andy Hungb01faa32016-04-27 12:51:32 -07002768 if (frames >= ets.mPosition[location]) {
2769 timestamp.mPosition = 0;
2770 } else {
2771 timestamp.mPosition = (uint32_t)(ets.mPosition[location] - frames);
2772 }
Andy Hung69488c42016-05-16 18:43:33 -07002773 } else if (location == ExtendedTimestamp::LOCATION_KERNEL) {
2774 ALOGV_IF(mPreviousLocation == ExtendedTimestamp::LOCATION_SERVER,
Andy Hungfb8ede22018-09-12 19:03:24 -07002775 "%s(%d): location moved from server to kernel",
Eric Laurent973db022018-11-20 14:54:31 -08002776 __func__, mPortId);
Andy Hung98731a22019-04-08 19:19:07 -07002777
2778 if (ets.mPosition[ExtendedTimestamp::LOCATION_SERVER] ==
2779 ets.mPosition[ExtendedTimestamp::LOCATION_KERNEL]) {
2780 // In Q, we don't return errors as an invalid time
2781 // but instead we leave the last kernel good timestamp alone.
2782 //
2783 // If server is identical to kernel, the device data pipeline is idle.
2784 // A better start time is now. The retrograde check ensures
2785 // timestamp monotonicity.
2786 const int64_t nowNs = systemTime();
Andy Hungcf3b7152019-04-19 18:29:21 -07002787 if (!mTimestampStallReported) {
2788 ALOGD("%s(%d): device stall time corrected using current time %lld",
2789 __func__, mPortId, (long long)nowNs);
2790 mTimestampStallReported = true;
2791 }
Andy Hung98731a22019-04-08 19:19:07 -07002792 timestamp.mTime = convertNsToTimespec(nowNs);
Andy Hungcf3b7152019-04-19 18:29:21 -07002793 } else {
2794 mTimestampStallReported = false;
Andy Hung98731a22019-04-08 19:19:07 -07002795 }
Andy Hungb01faa32016-04-27 12:51:32 -07002796 }
Andy Hung5d313802016-10-10 15:09:39 -07002797
2798 // We update the timestamp time even when paused.
2799 if (mState == STATE_PAUSED /* not needed: STATE_PAUSED_STOPPING */) {
2800 const int64_t now = systemTime();
Andy Hung2b01f002017-07-05 12:01:36 -07002801 const int64_t at = audio_utils_ns_from_timespec(&timestamp.mTime);
Andy Hung5d313802016-10-10 15:09:39 -07002802 const int64_t lag =
2803 (ets.mTimeNs[ExtendedTimestamp::LOCATION_SERVER_LASTKERNELOK] < 0 ||
2804 ets.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL_LASTKERNELOK] < 0)
2805 ? int64_t(mAfLatency * 1000000LL)
2806 : (ets.mPosition[ExtendedTimestamp::LOCATION_SERVER_LASTKERNELOK]
2807 - ets.mPosition[ExtendedTimestamp::LOCATION_KERNEL_LASTKERNELOK])
2808 * NANOS_PER_SECOND / mSampleRate;
2809 const int64_t limit = now - lag; // no earlier than this limit
2810 if (at < limit) {
2811 ALOGV("timestamp pause lag:%lld adjusting from %lld to %lld",
2812 (long long)lag, (long long)at, (long long)limit);
Andy Hungffa36952017-08-17 10:41:51 -07002813 timestamp.mTime = convertNsToTimespec(limit);
Andy Hung5d313802016-10-10 15:09:39 -07002814 }
2815 }
Andy Hungb01faa32016-04-27 12:51:32 -07002816 mPreviousLocation = location;
2817 } else {
2818 // right after AudioTrack is started, one may not find a timestamp
Eric Laurent973db022018-11-20 14:54:31 -08002819 ALOGV("%s(%d): getBestTimestamp did not find timestamp", __func__, mPortId);
Andy Hungb01faa32016-04-27 12:51:32 -07002820 }
Andy Hung6ae58432016-02-16 18:32:24 -08002821 }
2822 if (status == INVALID_OPERATION) {
Andy Hungf20a4e92016-08-15 19:10:34 -07002823 // INVALID_OPERATION occurs when no timestamp has been issued by the server;
2824 // other failures are signaled by a negative time.
2825 // If we come out of FLUSHED or STOPPED where the position is known
2826 // to be zero we convert this to WOULD_BLOCK (with the implicit meaning of
2827 // "zero" for NuPlayer). We don't convert for track restoration as position
2828 // does not reset.
Andy Hungfb8ede22018-09-12 19:03:24 -07002829 ALOGV("%s(%d): timestamp server offset:%lld restore frames:%lld",
Eric Laurent973db022018-11-20 14:54:31 -08002830 __func__, mPortId,
Andy Hungf20a4e92016-08-15 19:10:34 -07002831 (long long)mFramesWrittenServerOffset, (long long)mFramesWrittenAtRestore);
2832 if (mFramesWrittenServerOffset != mFramesWrittenAtRestore) {
2833 status = WOULD_BLOCK;
2834 }
Andy Hung6ae58432016-02-16 18:32:24 -08002835 }
2836 }
Andy Hung7f1bc8a2014-09-12 14:43:11 -07002837 if (status != NO_ERROR) {
Eric Laurent973db022018-11-20 14:54:31 -08002838 ALOGV_IF(status != WOULD_BLOCK, "%s(%d): getTimestamp error:%#x", __func__, mPortId, status);
Andy Hung7f1bc8a2014-09-12 14:43:11 -07002839 return status;
2840 }
2841 if (isOffloadedOrDirect_l()) {
2842 if (isOffloaded_l() && (mState == STATE_PAUSED || mState == STATE_PAUSED_STOPPING)) {
2843 // use cached paused position in case another offloaded track is running.
2844 timestamp.mPosition = mPausedPosition;
2845 clock_gettime(CLOCK_MONOTONIC, &timestamp.mTime);
Andy Hung5d313802016-10-10 15:09:39 -07002846 // TODO: adjust for delay
Andy Hung7f1bc8a2014-09-12 14:43:11 -07002847 return NO_ERROR;
2848 }
2849
2850 // Check whether a pending flush or stop has completed, as those commands may
Andy Hungc8e09c62015-06-03 23:43:36 -07002851 // be asynchronous or return near finish or exhibit glitchy behavior.
2852 //
2853 // Originally this showed up as the first timestamp being a continuation of
2854 // the previous song under gapless playback.
2855 // However, we sometimes see zero timestamps, then a glitch of
2856 // the previous song's position, and then correct timestamps afterwards.
Andy Hungffa36952017-08-17 10:41:51 -07002857 if (mStartFromZeroUs != 0 && mSampleRate != 0) {
Andy Hung7f1bc8a2014-09-12 14:43:11 -07002858 static const int kTimeJitterUs = 100000; // 100 ms
2859 static const int k1SecUs = 1000000;
2860
2861 const int64_t timeNow = getNowUs();
2862
Andy Hungffa36952017-08-17 10:41:51 -07002863 if (timeNow < mStartFromZeroUs + k1SecUs) { // within first second of starting
Andy Hung7f1bc8a2014-09-12 14:43:11 -07002864 const int64_t timestampTimeUs = convertTimespecToUs(timestamp.mTime);
Andy Hungffa36952017-08-17 10:41:51 -07002865 if (timestampTimeUs < mStartFromZeroUs) {
Andy Hung7f1bc8a2014-09-12 14:43:11 -07002866 return WOULD_BLOCK; // stale timestamp time, occurs before start.
2867 }
Andy Hungffa36952017-08-17 10:41:51 -07002868 const int64_t deltaTimeUs = timestampTimeUs - mStartFromZeroUs;
Andy Hung8edb8dc2015-03-26 19:13:55 -07002869 const int64_t deltaPositionByUs = (double)timestamp.mPosition * 1000000
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -07002870 / ((double)mSampleRate * mPlaybackRate.mSpeed);
Andy Hung7f1bc8a2014-09-12 14:43:11 -07002871
2872 if (deltaPositionByUs > deltaTimeUs + kTimeJitterUs) {
2873 // Verify that the counter can't count faster than the sample rate
Andy Hungc8e09c62015-06-03 23:43:36 -07002874 // since the start time. If greater, then that means we may have failed
Andy Hung7f1bc8a2014-09-12 14:43:11 -07002875 // to completely flush or stop the previous playing track.
Andy Hungc8e09c62015-06-03 23:43:36 -07002876 ALOGW_IF(!mTimestampStartupGlitchReported,
Andy Hungfb8ede22018-09-12 19:03:24 -07002877 "%s(%d): startup glitch detected"
Andy Hung7f1bc8a2014-09-12 14:43:11 -07002878 " deltaTimeUs(%lld) deltaPositionUs(%lld) tsmPosition(%u)",
Eric Laurent973db022018-11-20 14:54:31 -08002879 __func__, mPortId,
Andy Hung7f1bc8a2014-09-12 14:43:11 -07002880 (long long)deltaTimeUs, (long long)deltaPositionByUs,
2881 timestamp.mPosition);
Andy Hungc8e09c62015-06-03 23:43:36 -07002882 mTimestampStartupGlitchReported = true;
2883 if (previousTimestampValid
2884 && mPreviousTimestamp.mPosition == 0 /* should be true if valid */) {
2885 timestamp = mPreviousTimestamp;
2886 mPreviousTimestampValid = true;
2887 return NO_ERROR;
2888 }
Andy Hung7f1bc8a2014-09-12 14:43:11 -07002889 return WOULD_BLOCK;
2890 }
Andy Hungc8e09c62015-06-03 23:43:36 -07002891 if (deltaPositionByUs != 0) {
Andy Hungffa36952017-08-17 10:41:51 -07002892 mStartFromZeroUs = 0; // don't check again, we got valid nonzero position.
Andy Hungc8e09c62015-06-03 23:43:36 -07002893 }
2894 } else {
Andy Hungffa36952017-08-17 10:41:51 -07002895 mStartFromZeroUs = 0; // don't check again, start time expired.
Andy Hung7f1bc8a2014-09-12 14:43:11 -07002896 }
Andy Hungc8e09c62015-06-03 23:43:36 -07002897 mTimestampStartupGlitchReported = false;
Andy Hung7f1bc8a2014-09-12 14:43:11 -07002898 }
2899 } else {
Glenn Kasten200092b2014-08-15 15:13:30 -07002900 // Update the mapping between local consumed (mPosition) and server consumed (mServer)
2901 (void) updateAndGetPosition_l();
2902 // Server consumed (mServer) and presented both use the same server time base,
2903 // and server consumed is always >= presented.
2904 // The delta between these represents the number of frames in the buffer pipeline.
2905 // If this delta between these is greater than the client position, it means that
2906 // actually presented is still stuck at the starting line (figuratively speaking),
2907 // waiting for the first frame to go by. So we can't report a valid timestamp yet.
Andy Hung90e8a972015-11-09 16:42:40 -08002908 // Note: We explicitly use non-Modulo comparison here - potential wrap issue when
2909 // mPosition exceeds 32 bits.
2910 // TODO Remove when timestamp is updated to contain pipeline status info.
2911 const int32_t pipelineDepthInFrames = (mServer - timestamp.mPosition).signedValue();
2912 if (pipelineDepthInFrames > 0 /* should be true, but we check anyways */
2913 && (uint32_t)pipelineDepthInFrames > mPosition.value()) {
Glenn Kasten200092b2014-08-15 15:13:30 -07002914 return INVALID_OPERATION;
2915 }
2916 // Convert timestamp position from server time base to client time base.
2917 // TODO The following code should work OK now because timestamp.mPosition is 32-bit.
2918 // But if we change it to 64-bit then this could fail.
Andy Hung90e8a972015-11-09 16:42:40 -08002919 // Use Modulo computation here.
2920 timestamp.mPosition = (mPosition - mServer + timestamp.mPosition).value();
Glenn Kasten200092b2014-08-15 15:13:30 -07002921 // Immediately after a call to getPosition_l(), mPosition and
2922 // mServer both represent the same frame position. mPosition is
2923 // in client's point of view, and mServer is in server's point of
2924 // view. So the difference between them is the "fudge factor"
2925 // between client and server views due to stop() and/or new
2926 // IAudioTrack. And timestamp.mPosition is initially in server's
2927 // point of view, so we need to apply the same fudge factor to it.
Glenn Kastenfe346c72013-08-30 13:28:22 -07002928 }
Phil Burk1b420972015-04-22 10:52:21 -07002929
2930 // Prevent retrograde motion in timestamp.
2931 // This is sometimes caused by erratic reports of the available space in the ALSA drivers.
2932 if (status == NO_ERROR) {
Andy Hung3b8c6332019-04-03 19:29:36 -07002933 // Fix stale time when checking timestamp right after start().
2934 // The position is at the last reported location but the time can be stale
2935 // due to pause or standby or cold start latency.
2936 //
2937 // We keep advancing the time (but not the position) to ensure that the
2938 // stale value does not confuse the application.
2939 //
2940 // For offload compatibility, use a default lag value here.
2941 // Any time discrepancy between this update and the pause timestamp is handled
2942 // by the retrograde check afterwards.
2943 int64_t currentTimeNanos = audio_utils_ns_from_timespec(&timestamp.mTime);
2944 const int64_t lagNs = int64_t(mAfLatency * 1000000LL);
2945 const int64_t limitNs = mStartNs - lagNs;
2946 if (currentTimeNanos < limitNs) {
Andy Hungcf3b7152019-04-19 18:29:21 -07002947 if (!mTimestampStaleTimeReported) {
2948 ALOGD("%s(%d): stale timestamp time corrected, "
2949 "currentTimeNanos: %lld < limitNs: %lld < mStartNs: %lld",
2950 __func__, mPortId,
2951 (long long)currentTimeNanos, (long long)limitNs, (long long)mStartNs);
2952 mTimestampStaleTimeReported = true;
2953 }
Andy Hung3b8c6332019-04-03 19:29:36 -07002954 timestamp.mTime = convertNsToTimespec(limitNs);
2955 currentTimeNanos = limitNs;
Andy Hungcf3b7152019-04-19 18:29:21 -07002956 } else {
2957 mTimestampStaleTimeReported = false;
Andy Hung3b8c6332019-04-03 19:29:36 -07002958 }
2959
Andy Hungffa36952017-08-17 10:41:51 -07002960 // previousTimestampValid is set to false when starting after a stop or flush.
Phil Burk1b420972015-04-22 10:52:21 -07002961 if (previousTimestampValid) {
Andy Hung2b01f002017-07-05 12:01:36 -07002962 const int64_t previousTimeNanos =
2963 audio_utils_ns_from_timespec(&mPreviousTimestamp.mTime);
Andy Hungffa36952017-08-17 10:41:51 -07002964
2965 // retrograde check
Phil Burk1b420972015-04-22 10:52:21 -07002966 if (currentTimeNanos < previousTimeNanos) {
Andy Hungcf3b7152019-04-19 18:29:21 -07002967 if (!mTimestampRetrogradeTimeReported) {
2968 ALOGW("%s(%d): retrograde timestamp time corrected, %lld < %lld",
2969 __func__, mPortId,
2970 (long long)currentTimeNanos, (long long)previousTimeNanos);
2971 mTimestampRetrogradeTimeReported = true;
2972 }
Andy Hung5d313802016-10-10 15:09:39 -07002973 timestamp.mTime = mPreviousTimestamp.mTime;
Andy Hungcf3b7152019-04-19 18:29:21 -07002974 } else {
2975 mTimestampRetrogradeTimeReported = false;
Phil Burk1b420972015-04-22 10:52:21 -07002976 }
2977
2978 // Looking at signed delta will work even when the timestamps
2979 // are wrapping around.
Andy Hung90e8a972015-11-09 16:42:40 -08002980 int32_t deltaPosition = (Modulo<uint32_t>(timestamp.mPosition)
2981 - mPreviousTimestamp.mPosition).signedValue();
Phil Burk4c5a3672015-04-30 16:18:53 -07002982 if (deltaPosition < 0) {
2983 // Only report once per position instead of spamming the log.
Andy Hungcf3b7152019-04-19 18:29:21 -07002984 if (!mTimestampRetrogradePositionReported) {
Andy Hungfb8ede22018-09-12 19:03:24 -07002985 ALOGW("%s(%d): retrograde timestamp position corrected, %d = %u - %u",
Eric Laurent973db022018-11-20 14:54:31 -08002986 __func__, mPortId,
Phil Burk4c5a3672015-04-30 16:18:53 -07002987 deltaPosition,
2988 timestamp.mPosition,
2989 mPreviousTimestamp.mPosition);
Andy Hungcf3b7152019-04-19 18:29:21 -07002990 mTimestampRetrogradePositionReported = true;
Phil Burk4c5a3672015-04-30 16:18:53 -07002991 }
2992 } else {
Andy Hungcf3b7152019-04-19 18:29:21 -07002993 mTimestampRetrogradePositionReported = false;
Phil Burk4c5a3672015-04-30 16:18:53 -07002994 }
Andy Hung5d313802016-10-10 15:09:39 -07002995 if (deltaPosition < 0) {
2996 timestamp.mPosition = mPreviousTimestamp.mPosition;
2997 deltaPosition = 0;
Phil Burk1b420972015-04-22 10:52:21 -07002998 }
Andy Hung5d313802016-10-10 15:09:39 -07002999#if 0
3000 // Uncomment this to verify audio timestamp rate.
3001 const int64_t deltaTime =
Andy Hung2b01f002017-07-05 12:01:36 -07003002 audio_utils_ns_from_timespec(&timestamp.mTime) - previousTimeNanos;
Andy Hung5d313802016-10-10 15:09:39 -07003003 if (deltaTime != 0) {
3004 const int64_t computedSampleRate =
3005 deltaPosition * (long long)NANOS_PER_SECOND / deltaTime;
Andy Hungfb8ede22018-09-12 19:03:24 -07003006 ALOGD("%s(%d): computedSampleRate:%u sampleRate:%u",
Eric Laurent973db022018-11-20 14:54:31 -08003007 __func__, mPortId,
Andy Hung5d313802016-10-10 15:09:39 -07003008 (unsigned)computedSampleRate, mSampleRate);
3009 }
3010#endif
Phil Burk1b420972015-04-22 10:52:21 -07003011 }
3012 mPreviousTimestamp = timestamp;
3013 mPreviousTimestampValid = true;
3014 }
3015
Glenn Kastenfe346c72013-08-30 13:28:22 -07003016 return status;
Glenn Kastence703742013-07-19 16:33:58 -07003017}
3018
Richard Fitzgeraldad3af332013-03-25 16:54:37 +00003019String8 AudioTrack::getParameters(const String8& keys)
3020{
Glenn Kasten2c6c5292014-01-13 10:29:08 -08003021 audio_io_handle_t output = getOutput();
Glenn Kasten142f5192014-03-25 17:44:59 -07003022 if (output != AUDIO_IO_HANDLE_NONE) {
Glenn Kasten2c6c5292014-01-13 10:29:08 -08003023 return AudioSystem::getParameters(output, keys);
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +01003024 } else {
3025 return String8::empty();
3026 }
Richard Fitzgeraldad3af332013-03-25 16:54:37 +00003027}
3028
Glenn Kasten23a75452014-01-13 10:37:17 -08003029bool AudioTrack::isOffloaded() const
3030{
3031 AutoMutex lock(mLock);
3032 return isOffloaded_l();
3033}
3034
Eric Laurentab5cdba2014-06-09 17:22:27 -07003035bool AudioTrack::isDirect() const
3036{
3037 AutoMutex lock(mLock);
3038 return isDirect_l();
3039}
3040
3041bool AudioTrack::isOffloadedOrDirect() const
3042{
3043 AutoMutex lock(mLock);
3044 return isOffloadedOrDirect_l();
3045}
3046
3047
Glenn Kasten7c7be1e2013-12-19 16:34:04 -08003048status_t AudioTrack::dump(int fd, const Vector<String16>& args __unused) const
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08003049{
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08003050 String8 result;
3051
3052 result.append(" AudioTrack::dump\n");
Andy Hungfb8ede22018-09-12 19:03:24 -07003053 result.appendFormat(" id(%d) status(%d), state(%d), session Id(%d), flags(%#x)\n",
Eric Laurent973db022018-11-20 14:54:31 -08003054 mPortId, mStatus, mState, mSessionId, mFlags);
Eric Laurentd114b622017-11-27 18:37:04 -08003055 result.appendFormat(" stream type(%d), left - right volume(%f, %f)\n",
3056 (mStreamType == AUDIO_STREAM_DEFAULT) ?
François Gaffie58d4be52018-11-06 15:30:12 +01003057 AudioSystem::attributesToStreamType(mAttributes) :
3058 mStreamType,
Eric Laurentd114b622017-11-27 18:37:04 -08003059 mVolume[AUDIO_INTERLEAVE_LEFT], mVolume[AUDIO_INTERLEAVE_RIGHT]);
Glenn Kasten49f36ba2017-12-06 13:02:02 -08003060 result.appendFormat(" format(%#x), channel mask(%#x), channel count(%u)\n",
Eric Laurentd114b622017-11-27 18:37:04 -08003061 mFormat, mChannelMask, mChannelCount);
3062 result.appendFormat(" sample rate(%u), original sample rate(%u), speed(%f)\n",
3063 mSampleRate, mOriginalSampleRate, mPlaybackRate.mSpeed);
3064 result.appendFormat(" frame count(%zu), req. frame count(%zu)\n",
3065 mFrameCount, mReqFrameCount);
3066 result.appendFormat(" notif. frame count(%u), req. notif. frame count(%u),"
3067 " req. notif. per buff(%u)\n",
3068 mNotificationFramesAct, mNotificationFramesReq, mNotificationsPerBufferReq);
3069 result.appendFormat(" latency (%d), selected device Id(%d), routed device Id(%d)\n",
3070 mLatency, mSelectedDeviceId, mRoutedDeviceId);
3071 result.appendFormat(" output(%d) AF latency (%u) AF frame count(%zu) AF SampleRate(%u)\n",
3072 mOutput, mAfLatency, mAfFrameCount, mAfSampleRate);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08003073 ::write(fd, result.string(), result.size());
3074 return NO_ERROR;
3075}
3076
Phil Burk2812d9e2016-01-04 10:34:30 -08003077uint32_t AudioTrack::getUnderrunCount() const
3078{
3079 AutoMutex lock(mLock);
3080 return getUnderrunCount_l();
3081}
3082
3083uint32_t AudioTrack::getUnderrunCount_l() const
3084{
3085 return mProxy->getUnderrunCount() + mUnderrunCountOffset;
3086}
3087
Glenn Kasten9f80dd22012-12-18 15:57:32 -08003088uint32_t AudioTrack::getUnderrunFrames() const
3089{
3090 AutoMutex lock(mLock);
3091 return mProxy->getUnderrunFrames();
3092}
3093
Eric Laurent296fb132015-05-01 11:38:42 -07003094status_t AudioTrack::addAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& callback)
3095{
Eric Laurent09f1ed22019-04-24 17:45:17 -07003096
Eric Laurent296fb132015-05-01 11:38:42 -07003097 if (callback == 0) {
Eric Laurent973db022018-11-20 14:54:31 -08003098 ALOGW("%s(%d): adding NULL callback!", __func__, mPortId);
Eric Laurent296fb132015-05-01 11:38:42 -07003099 return BAD_VALUE;
3100 }
3101 AutoMutex lock(mLock);
Eric Laurentad2e7b92017-09-14 20:06:42 -07003102 if (mDeviceCallback.unsafe_get() == callback.get()) {
Eric Laurent973db022018-11-20 14:54:31 -08003103 ALOGW("%s(%d): adding same callback!", __func__, mPortId);
Eric Laurent296fb132015-05-01 11:38:42 -07003104 return INVALID_OPERATION;
3105 }
3106 status_t status = NO_ERROR;
3107 if (mOutput != AUDIO_IO_HANDLE_NONE) {
3108 if (mDeviceCallback != 0) {
Eric Laurent973db022018-11-20 14:54:31 -08003109 ALOGW("%s(%d): callback already present!", __func__, mPortId);
Eric Laurent09f1ed22019-04-24 17:45:17 -07003110 AudioSystem::removeAudioDeviceCallback(this, mOutput, mPortId);
Eric Laurent296fb132015-05-01 11:38:42 -07003111 }
Eric Laurent09f1ed22019-04-24 17:45:17 -07003112 status = AudioSystem::addAudioDeviceCallback(this, mOutput, mPortId);
Eric Laurent296fb132015-05-01 11:38:42 -07003113 }
3114 mDeviceCallback = callback;
3115 return status;
3116}
3117
3118status_t AudioTrack::removeAudioDeviceCallback(
3119 const sp<AudioSystem::AudioDeviceCallback>& callback)
3120{
3121 if (callback == 0) {
Eric Laurent973db022018-11-20 14:54:31 -08003122 ALOGW("%s(%d): removing NULL callback!", __func__, mPortId);
Eric Laurent296fb132015-05-01 11:38:42 -07003123 return BAD_VALUE;
3124 }
Eric Laurent4463ff52019-02-07 13:56:09 -08003125 AutoMutex lock(mLock);
3126 if (mDeviceCallback.unsafe_get() != callback.get()) {
3127 ALOGW("%s removing different callback!", __FUNCTION__);
3128 return INVALID_OPERATION;
Eric Laurent296fb132015-05-01 11:38:42 -07003129 }
Eric Laurent4463ff52019-02-07 13:56:09 -08003130 mDeviceCallback.clear();
Eric Laurent296fb132015-05-01 11:38:42 -07003131 if (mOutput != AUDIO_IO_HANDLE_NONE) {
Eric Laurent09f1ed22019-04-24 17:45:17 -07003132 AudioSystem::removeAudioDeviceCallback(this, mOutput, mPortId);
Eric Laurent296fb132015-05-01 11:38:42 -07003133 }
Eric Laurent296fb132015-05-01 11:38:42 -07003134 return NO_ERROR;
3135}
3136
Eric Laurentad2e7b92017-09-14 20:06:42 -07003137
3138void AudioTrack::onAudioDeviceUpdate(audio_io_handle_t audioIo,
3139 audio_port_handle_t deviceId)
3140{
3141 sp<AudioSystem::AudioDeviceCallback> callback;
3142 {
3143 AutoMutex lock(mLock);
3144 if (audioIo != mOutput) {
3145 return;
3146 }
3147 callback = mDeviceCallback.promote();
3148 // only update device if the track is active as route changes due to other use cases are
3149 // irrelevant for this client
3150 if (mState == STATE_ACTIVE) {
3151 mRoutedDeviceId = deviceId;
3152 }
3153 }
Eric Laurent09f1ed22019-04-24 17:45:17 -07003154
Eric Laurentad2e7b92017-09-14 20:06:42 -07003155 if (callback.get() != nullptr) {
3156 callback->onAudioDeviceUpdate(mOutput, mRoutedDeviceId);
3157 }
3158}
3159
Andy Hunge13f8a62016-03-30 14:20:42 -07003160status_t AudioTrack::pendingDuration(int32_t *msec, ExtendedTimestamp::Location location)
3161{
3162 if (msec == nullptr ||
3163 (location != ExtendedTimestamp::LOCATION_SERVER
3164 && location != ExtendedTimestamp::LOCATION_KERNEL)) {
3165 return BAD_VALUE;
3166 }
3167 AutoMutex lock(mLock);
3168 // inclusive of offloaded and direct tracks.
3169 //
3170 // It is possible, but not enabled, to allow duration computation for non-pcm
3171 // audio_has_proportional_frames() formats because currently they have
3172 // the drain rate equivalent to the pcm sample rate * framesize.
3173 if (!isPurePcmData_l()) {
3174 return INVALID_OPERATION;
3175 }
3176 ExtendedTimestamp ets;
3177 if (getTimestamp_l(&ets) == OK
3178 && ets.mTimeNs[location] > 0) {
3179 int64_t diff = ets.mPosition[ExtendedTimestamp::LOCATION_CLIENT]
3180 - ets.mPosition[location];
3181 if (diff < 0) {
3182 *msec = 0;
3183 } else {
3184 // ms is the playback time by frames
3185 int64_t ms = (int64_t)((double)diff * 1000 /
3186 ((double)mSampleRate * mPlaybackRate.mSpeed));
3187 // clockdiff is the timestamp age (negative)
3188 int64_t clockdiff = (mState != STATE_ACTIVE) ? 0 :
3189 ets.mTimeNs[location]
3190 + ets.mTimebaseOffset[ExtendedTimestamp::TIMEBASE_MONOTONIC]
3191 - systemTime(SYSTEM_TIME_MONOTONIC);
3192
3193 //ALOGV("ms: %lld clockdiff: %lld", (long long)ms, (long long)clockdiff);
3194 static const int NANOS_PER_MILLIS = 1000000;
3195 *msec = (int32_t)(ms + clockdiff / NANOS_PER_MILLIS);
3196 }
3197 return NO_ERROR;
3198 }
3199 if (location != ExtendedTimestamp::LOCATION_SERVER) {
3200 return INVALID_OPERATION; // LOCATION_KERNEL is not available
3201 }
3202 // use server position directly (offloaded and direct arrive here)
3203 updateAndGetPosition_l();
3204 int32_t diff = (Modulo<uint32_t>(mFramesWritten) - mPosition).signedValue();
3205 *msec = (diff <= 0) ? 0
3206 : (int32_t)((double)diff * 1000 / ((double)mSampleRate * mPlaybackRate.mSpeed));
3207 return NO_ERROR;
3208}
3209
Andy Hung65ffdfc2016-10-10 15:52:11 -07003210bool AudioTrack::hasStarted()
3211{
3212 AutoMutex lock(mLock);
3213 switch (mState) {
3214 case STATE_STOPPED:
3215 if (isOffloadedOrDirect_l()) {
3216 // check if we have started in the past to return true.
Andy Hungffa36952017-08-17 10:41:51 -07003217 return mStartFromZeroUs > 0;
Andy Hung65ffdfc2016-10-10 15:52:11 -07003218 }
3219 // A normal audio track may still be draining, so
3220 // check if stream has ended. This covers fasttrack position
3221 // instability and start/stop without any data written.
3222 if (mProxy->getStreamEndDone()) {
3223 return true;
3224 }
Chih-Hung Hsiehffe35582018-09-13 13:59:28 -07003225 FALLTHROUGH_INTENDED;
Andy Hung65ffdfc2016-10-10 15:52:11 -07003226 case STATE_ACTIVE:
3227 case STATE_STOPPING:
3228 break;
3229 case STATE_PAUSED:
3230 case STATE_PAUSED_STOPPING:
3231 case STATE_FLUSHED:
3232 return false; // we're not active
3233 default:
Eric Laurent973db022018-11-20 14:54:31 -08003234 LOG_ALWAYS_FATAL("%s(%d): Invalid mState in hasStarted(): %d", __func__, mPortId, mState);
Andy Hung65ffdfc2016-10-10 15:52:11 -07003235 break;
3236 }
3237
3238 // wait indicates whether we need to wait for a timestamp.
3239 // This is conservatively figured - if we encounter an unexpected error
3240 // then we will not wait.
3241 bool wait = false;
3242 if (isOffloadedOrDirect_l()) {
3243 AudioTimestamp ts;
3244 status_t status = getTimestamp_l(ts);
3245 if (status == WOULD_BLOCK) {
3246 wait = true;
3247 } else if (status == OK) {
3248 wait = (ts.mPosition == 0 || ts.mPosition == mStartTs.mPosition);
3249 }
Andy Hungfb8ede22018-09-12 19:03:24 -07003250 ALOGV("%s(%d): hasStarted wait:%d ts:%u start position:%lld",
Eric Laurent973db022018-11-20 14:54:31 -08003251 __func__, mPortId,
Andy Hung65ffdfc2016-10-10 15:52:11 -07003252 (int)wait,
3253 ts.mPosition,
3254 (long long)mStartTs.mPosition);
3255 } else {
3256 int location = ExtendedTimestamp::LOCATION_SERVER; // for ALOG
3257 ExtendedTimestamp ets;
3258 status_t status = getTimestamp_l(&ets);
3259 if (status == WOULD_BLOCK) { // no SERVER or KERNEL frame info in ets
3260 wait = true;
3261 } else if (status == OK) {
3262 for (location = ExtendedTimestamp::LOCATION_KERNEL;
3263 location >= ExtendedTimestamp::LOCATION_SERVER; --location) {
3264 if (ets.mTimeNs[location] < 0 || mStartEts.mTimeNs[location] < 0) {
3265 continue;
3266 }
3267 wait = ets.mPosition[location] == 0
3268 || ets.mPosition[location] == mStartEts.mPosition[location];
3269 break;
3270 }
3271 }
Andy Hungfb8ede22018-09-12 19:03:24 -07003272 ALOGV("%s(%d): hasStarted wait:%d ets:%lld start position:%lld",
Eric Laurent973db022018-11-20 14:54:31 -08003273 __func__, mPortId,
Andy Hung65ffdfc2016-10-10 15:52:11 -07003274 (int)wait,
3275 (long long)ets.mPosition[location],
3276 (long long)mStartEts.mPosition[location]);
3277 }
3278 return !wait;
3279}
3280
Glenn Kasten9f80dd22012-12-18 15:57:32 -08003281// =========================================================================
3282
Glenn Kasten7c7be1e2013-12-19 16:34:04 -08003283void AudioTrack::DeathNotifier::binderDied(const wp<IBinder>& who __unused)
Glenn Kasten9f80dd22012-12-18 15:57:32 -08003284{
3285 sp<AudioTrack> audioTrack = mAudioTrack.promote();
3286 if (audioTrack != 0) {
3287 AutoMutex lock(audioTrack->mLock);
3288 audioTrack->mProxy->binderDied();
3289 }
3290}
3291
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08003292// =========================================================================
3293
Andy Hungca353672019-03-06 11:54:38 -08003294AudioTrack::AudioTrackThread::AudioTrackThread(AudioTrack& receiver)
Andy Hungeb46cf92019-03-06 10:13:38 -08003295 : Thread(true /* bCanCallJava */) // binder recursion on restoreTrack_l() may call Java.
3296 , mReceiver(receiver), mPaused(true), mPausedInt(false), mPausedNs(0LL),
Glenn Kasten598de6c2013-10-16 17:02:13 -07003297 mIgnoreNextPausedInt(false)
Glenn Kasten3acbd052012-02-28 10:39:56 -08003298{
3299}
3300
3301AudioTrack::AudioTrackThread::~AudioTrackThread()
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08003302{
3303}
3304
3305bool AudioTrack::AudioTrackThread::threadLoop()
3306{
Glenn Kasten3acbd052012-02-28 10:39:56 -08003307 {
3308 AutoMutex _l(mMyLock);
3309 if (mPaused) {
Glenn Kasten75f79032017-05-23 11:22:44 -07003310 // TODO check return value and handle or log
Glenn Kasten3acbd052012-02-28 10:39:56 -08003311 mMyCond.wait(mMyLock);
3312 // caller will check for exitPending()
3313 return true;
3314 }
Glenn Kasten598de6c2013-10-16 17:02:13 -07003315 if (mIgnoreNextPausedInt) {
3316 mIgnoreNextPausedInt = false;
3317 mPausedInt = false;
3318 }
Glenn Kasten5a6cd222013-09-20 09:20:45 -07003319 if (mPausedInt) {
Glenn Kasten47d55172017-05-23 11:19:30 -07003320 // TODO use futex instead of condition, for event flag "or"
Glenn Kasten5a6cd222013-09-20 09:20:45 -07003321 if (mPausedNs > 0) {
Glenn Kasten75f79032017-05-23 11:22:44 -07003322 // TODO check return value and handle or log
Glenn Kasten5a6cd222013-09-20 09:20:45 -07003323 (void) mMyCond.waitRelative(mMyLock, mPausedNs);
3324 } else {
Glenn Kasten75f79032017-05-23 11:22:44 -07003325 // TODO check return value and handle or log
Glenn Kasten5a6cd222013-09-20 09:20:45 -07003326 mMyCond.wait(mMyLock);
3327 }
Eric Laurent9d2c78c2013-09-23 12:29:42 -07003328 mPausedInt = false;
Glenn Kasten5a6cd222013-09-20 09:20:45 -07003329 return true;
3330 }
Glenn Kasten3acbd052012-02-28 10:39:56 -08003331 }
Eric Laurent7985dcb2014-10-07 15:45:14 -07003332 if (exitPending()) {
3333 return false;
3334 }
Glenn Kasten7c7be1e2013-12-19 16:34:04 -08003335 nsecs_t ns = mReceiver.processAudioBuffer();
Glenn Kasten9f80dd22012-12-18 15:57:32 -08003336 switch (ns) {
3337 case 0:
3338 return true;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08003339 case NS_INACTIVE:
Glenn Kasten5a6cd222013-09-20 09:20:45 -07003340 pauseInternal();
Glenn Kasten9f80dd22012-12-18 15:57:32 -08003341 return true;
3342 case NS_NEVER:
3343 return false;
Glenn Kasten5a6cd222013-09-20 09:20:45 -07003344 case NS_WHENEVER:
Andy Hung3c09c782014-12-29 18:39:32 -08003345 // Event driven: call wake() when callback notifications conditions change.
3346 ns = INT64_MAX;
Chih-Hung Hsiehffe35582018-09-13 13:59:28 -07003347 FALLTHROUGH_INTENDED;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08003348 default:
Andy Hungfb8ede22018-09-12 19:03:24 -07003349 LOG_ALWAYS_FATAL_IF(ns < 0, "%s(%d): processAudioBuffer() returned %lld",
Eric Laurent973db022018-11-20 14:54:31 -08003350 __func__, mReceiver.mPortId, (long long)ns);
Glenn Kasten5a6cd222013-09-20 09:20:45 -07003351 pauseInternal(ns);
Glenn Kasten9f80dd22012-12-18 15:57:32 -08003352 return true;
Glenn Kastenca8b2802012-04-23 13:58:16 -07003353 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08003354}
3355
Glenn Kasten3acbd052012-02-28 10:39:56 -08003356void AudioTrack::AudioTrackThread::requestExit()
3357{
3358 // must be in this order to avoid a race condition
3359 Thread::requestExit();
Glenn Kasten598de6c2013-10-16 17:02:13 -07003360 resume();
Glenn Kasten3acbd052012-02-28 10:39:56 -08003361}
3362
3363void AudioTrack::AudioTrackThread::pause()
3364{
3365 AutoMutex _l(mMyLock);
3366 mPaused = true;
3367}
3368
3369void AudioTrack::AudioTrackThread::resume()
3370{
3371 AutoMutex _l(mMyLock);
Glenn Kasten598de6c2013-10-16 17:02:13 -07003372 mIgnoreNextPausedInt = true;
Eric Laurent9d2c78c2013-09-23 12:29:42 -07003373 if (mPaused || mPausedInt) {
Glenn Kasten3acbd052012-02-28 10:39:56 -08003374 mPaused = false;
Eric Laurent9d2c78c2013-09-23 12:29:42 -07003375 mPausedInt = false;
Glenn Kasten3acbd052012-02-28 10:39:56 -08003376 mMyCond.signal();
3377 }
3378}
3379
Andy Hung3c09c782014-12-29 18:39:32 -08003380void AudioTrack::AudioTrackThread::wake()
3381{
3382 AutoMutex _l(mMyLock);
Andy Hunga8d08902015-07-22 11:52:13 -07003383 if (!mPaused) {
3384 // wake() might be called while servicing a callback - ignore the next
3385 // pause time and call processAudioBuffer.
Andy Hung3c09c782014-12-29 18:39:32 -08003386 mIgnoreNextPausedInt = true;
Andy Hunga8d08902015-07-22 11:52:13 -07003387 if (mPausedInt && mPausedNs > 0) {
3388 // audio track is active and internally paused with timeout.
3389 mPausedInt = false;
3390 mMyCond.signal();
3391 }
Andy Hung3c09c782014-12-29 18:39:32 -08003392 }
3393}
3394
Glenn Kasten5a6cd222013-09-20 09:20:45 -07003395void AudioTrack::AudioTrackThread::pauseInternal(nsecs_t ns)
3396{
3397 AutoMutex _l(mMyLock);
3398 mPausedInt = true;
3399 mPausedNs = ns;
3400}
3401
jiabinf6eb4c32020-02-25 14:06:25 -08003402binder::Status AudioTrack::AudioTrackCallback::onCodecFormatChanged(
3403 const std::vector<uint8_t>& audioMetadata)
3404{
3405 AutoMutex _l(mAudioTrackCbLock);
3406 sp<media::IAudioTrackCallback> callback = mCallback.promote();
3407 if (callback.get() != nullptr) {
3408 callback->onCodecFormatChanged(audioMetadata);
3409 } else {
3410 mCallback.clear();
3411 }
3412 return binder::Status::ok();
3413}
3414
3415void AudioTrack::AudioTrackCallback::setAudioTrackCallback(
3416 const sp<media::IAudioTrackCallback> &callback) {
3417 AutoMutex lock(mAudioTrackCbLock);
3418 mCallback = callback;
3419}
3420
Glenn Kasten40bc9062015-03-20 09:09:33 -07003421} // namespace android