1*ec779b8eSAndroid Build Coastguard Worker /*
2*ec779b8eSAndroid Build Coastguard Worker **
3*ec779b8eSAndroid Build Coastguard Worker ** Copyright 2007, The Android Open Source Project
4*ec779b8eSAndroid Build Coastguard Worker **
5*ec779b8eSAndroid Build Coastguard Worker ** Licensed under the Apache License, Version 2.0 (the "License");
6*ec779b8eSAndroid Build Coastguard Worker ** you may not use this file except in compliance with the License.
7*ec779b8eSAndroid Build Coastguard Worker ** You may obtain a copy of the License at
8*ec779b8eSAndroid Build Coastguard Worker **
9*ec779b8eSAndroid Build Coastguard Worker ** http://www.apache.org/licenses/LICENSE-2.0
10*ec779b8eSAndroid Build Coastguard Worker **
11*ec779b8eSAndroid Build Coastguard Worker ** Unless required by applicable law or agreed to in writing, software
12*ec779b8eSAndroid Build Coastguard Worker ** distributed under the License is distributed on an "AS IS" BASIS,
13*ec779b8eSAndroid Build Coastguard Worker ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*ec779b8eSAndroid Build Coastguard Worker ** See the License for the specific language governing permissions and
15*ec779b8eSAndroid Build Coastguard Worker ** limitations under the License.
16*ec779b8eSAndroid Build Coastguard Worker */
17*ec779b8eSAndroid Build Coastguard Worker
18*ec779b8eSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
19*ec779b8eSAndroid Build Coastguard Worker #define LOG_TAG "AudioTrack"
20*ec779b8eSAndroid Build Coastguard Worker
21*ec779b8eSAndroid Build Coastguard Worker #include <inttypes.h>
22*ec779b8eSAndroid Build Coastguard Worker #include <math.h>
23*ec779b8eSAndroid Build Coastguard Worker #include <sys/resource.h>
24*ec779b8eSAndroid Build Coastguard Worker #include <thread>
25*ec779b8eSAndroid Build Coastguard Worker
26*ec779b8eSAndroid Build Coastguard Worker #include <android/media/IAudioPolicyService.h>
27*ec779b8eSAndroid Build Coastguard Worker #include <android-base/macros.h>
28*ec779b8eSAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
29*ec779b8eSAndroid Build Coastguard Worker #include <audio_utils/clock.h>
30*ec779b8eSAndroid Build Coastguard Worker #include <audio_utils/primitives.h>
31*ec779b8eSAndroid Build Coastguard Worker #include <binder/IPCThreadState.h>
32*ec779b8eSAndroid Build Coastguard Worker #include <binder/IServiceManager.h>
33*ec779b8eSAndroid Build Coastguard Worker #include <media/AudioTrack.h>
34*ec779b8eSAndroid Build Coastguard Worker #include <utils/Log.h>
35*ec779b8eSAndroid Build Coastguard Worker #include <private/media/AudioTrackShared.h>
36*ec779b8eSAndroid Build Coastguard Worker #include <processgroup/sched_policy.h>
37*ec779b8eSAndroid Build Coastguard Worker #include <media/IAudioFlinger.h>
38*ec779b8eSAndroid Build Coastguard Worker #include <media/AudioParameter.h>
39*ec779b8eSAndroid Build Coastguard Worker #include <media/AudioResamplerPublic.h>
40*ec779b8eSAndroid Build Coastguard Worker #include <media/AudioSystem.h>
41*ec779b8eSAndroid Build Coastguard Worker #include <media/MediaMetricsItem.h>
42*ec779b8eSAndroid Build Coastguard Worker #include <media/TypeConverter.h>
43*ec779b8eSAndroid Build Coastguard Worker
44*ec779b8eSAndroid Build Coastguard Worker #define WAIT_PERIOD_MS 10
45*ec779b8eSAndroid Build Coastguard Worker #define WAIT_STREAM_END_TIMEOUT_SEC 120
46*ec779b8eSAndroid Build Coastguard Worker
47*ec779b8eSAndroid Build Coastguard Worker static const int kMaxLoopCountNotifications = 32;
48*ec779b8eSAndroid Build Coastguard Worker static constexpr char kAudioServiceName[] = "audio";
49*ec779b8eSAndroid Build Coastguard Worker
50*ec779b8eSAndroid Build Coastguard Worker using ::android::aidl_utils::statusTFromBinderStatus;
51*ec779b8eSAndroid Build Coastguard Worker using ::android::base::StringPrintf;
52*ec779b8eSAndroid Build Coastguard Worker
53*ec779b8eSAndroid Build Coastguard Worker namespace android {
54*ec779b8eSAndroid Build Coastguard Worker // ---------------------------------------------------------------------------
55*ec779b8eSAndroid Build Coastguard Worker
56*ec779b8eSAndroid Build Coastguard Worker using media::VolumeShaper;
57*ec779b8eSAndroid Build Coastguard Worker using android::content::AttributionSourceState;
58*ec779b8eSAndroid Build Coastguard Worker
59*ec779b8eSAndroid Build Coastguard Worker // TODO: Move to a separate .h
60*ec779b8eSAndroid Build Coastguard Worker
61*ec779b8eSAndroid Build Coastguard Worker template <typename T>
min(const T & x,const T & y)62*ec779b8eSAndroid Build Coastguard Worker static inline const T &min(const T &x, const T &y) {
63*ec779b8eSAndroid Build Coastguard Worker return x < y ? x : y;
64*ec779b8eSAndroid Build Coastguard Worker }
65*ec779b8eSAndroid Build Coastguard Worker
66*ec779b8eSAndroid Build Coastguard Worker template <typename T>
max(const T & x,const T & y)67*ec779b8eSAndroid Build Coastguard Worker static inline const T &max(const T &x, const T &y) {
68*ec779b8eSAndroid Build Coastguard Worker return x > y ? x : y;
69*ec779b8eSAndroid Build Coastguard Worker }
70*ec779b8eSAndroid Build Coastguard Worker
framesToNanoseconds(ssize_t frames,uint32_t sampleRate,float speed)71*ec779b8eSAndroid Build Coastguard Worker static inline nsecs_t framesToNanoseconds(ssize_t frames, uint32_t sampleRate, float speed)
72*ec779b8eSAndroid Build Coastguard Worker {
73*ec779b8eSAndroid Build Coastguard Worker return ((double)frames * 1000000000) / ((double)sampleRate * speed);
74*ec779b8eSAndroid Build Coastguard Worker }
75*ec779b8eSAndroid Build Coastguard Worker
convertTimespecToUs(const struct timespec & tv)76*ec779b8eSAndroid Build Coastguard Worker static int64_t convertTimespecToUs(const struct timespec &tv)
77*ec779b8eSAndroid Build Coastguard Worker {
78*ec779b8eSAndroid Build Coastguard Worker return tv.tv_sec * 1000000LL + tv.tv_nsec / 1000;
79*ec779b8eSAndroid Build Coastguard Worker }
80*ec779b8eSAndroid Build Coastguard Worker
81*ec779b8eSAndroid Build Coastguard Worker // TODO move to audio_utils.
convertNsToTimespec(int64_t ns)82*ec779b8eSAndroid Build Coastguard Worker static inline struct timespec convertNsToTimespec(int64_t ns) {
83*ec779b8eSAndroid Build Coastguard Worker struct timespec tv;
84*ec779b8eSAndroid Build Coastguard Worker tv.tv_sec = static_cast<time_t>(ns / NANOS_PER_SECOND);
85*ec779b8eSAndroid Build Coastguard Worker tv.tv_nsec = static_cast<int64_t>(ns % NANOS_PER_SECOND);
86*ec779b8eSAndroid Build Coastguard Worker return tv;
87*ec779b8eSAndroid Build Coastguard Worker }
88*ec779b8eSAndroid Build Coastguard Worker
89*ec779b8eSAndroid Build Coastguard Worker // current monotonic time in microseconds.
getNowUs()90*ec779b8eSAndroid Build Coastguard Worker static int64_t getNowUs()
91*ec779b8eSAndroid Build Coastguard Worker {
92*ec779b8eSAndroid Build Coastguard Worker struct timespec tv;
93*ec779b8eSAndroid Build Coastguard Worker (void) clock_gettime(CLOCK_MONOTONIC, &tv);
94*ec779b8eSAndroid Build Coastguard Worker return convertTimespecToUs(tv);
95*ec779b8eSAndroid Build Coastguard Worker }
96*ec779b8eSAndroid Build Coastguard Worker
97*ec779b8eSAndroid Build Coastguard Worker // FIXME: we don't use the pitch setting in the time stretcher (not working);
98*ec779b8eSAndroid Build Coastguard Worker // instead we emulate it using our sample rate converter.
99*ec779b8eSAndroid Build Coastguard Worker static const bool kFixPitch = true; // enable pitch fix
adjustSampleRate(uint32_t sampleRate,float pitch)100*ec779b8eSAndroid Build Coastguard Worker static inline uint32_t adjustSampleRate(uint32_t sampleRate, float pitch)
101*ec779b8eSAndroid Build Coastguard Worker {
102*ec779b8eSAndroid Build Coastguard Worker return kFixPitch ? (sampleRate * pitch + 0.5) : sampleRate;
103*ec779b8eSAndroid Build Coastguard Worker }
104*ec779b8eSAndroid Build Coastguard Worker
adjustSpeed(float speed,float pitch)105*ec779b8eSAndroid Build Coastguard Worker static inline float adjustSpeed(float speed, float pitch)
106*ec779b8eSAndroid Build Coastguard Worker {
107*ec779b8eSAndroid Build Coastguard Worker return kFixPitch ? speed / max(pitch, AUDIO_TIMESTRETCH_PITCH_MIN_DELTA) : speed;
108*ec779b8eSAndroid Build Coastguard Worker }
109*ec779b8eSAndroid Build Coastguard Worker
adjustPitch(float pitch)110*ec779b8eSAndroid Build Coastguard Worker static inline float adjustPitch(float pitch)
111*ec779b8eSAndroid Build Coastguard Worker {
112*ec779b8eSAndroid Build Coastguard Worker return kFixPitch ? AUDIO_TIMESTRETCH_PITCH_NORMAL : pitch;
113*ec779b8eSAndroid Build Coastguard Worker }
114*ec779b8eSAndroid Build Coastguard Worker
115*ec779b8eSAndroid Build Coastguard Worker // static
getMinFrameCount(size_t * frameCount,audio_stream_type_t streamType,uint32_t sampleRate)116*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::getMinFrameCount(
117*ec779b8eSAndroid Build Coastguard Worker size_t* frameCount,
118*ec779b8eSAndroid Build Coastguard Worker audio_stream_type_t streamType,
119*ec779b8eSAndroid Build Coastguard Worker uint32_t sampleRate)
120*ec779b8eSAndroid Build Coastguard Worker {
121*ec779b8eSAndroid Build Coastguard Worker if (frameCount == NULL) {
122*ec779b8eSAndroid Build Coastguard Worker return BAD_VALUE;
123*ec779b8eSAndroid Build Coastguard Worker }
124*ec779b8eSAndroid Build Coastguard Worker
125*ec779b8eSAndroid Build Coastguard Worker // FIXME handle in server, like createTrack_l(), possible missing info:
126*ec779b8eSAndroid Build Coastguard Worker // audio_io_handle_t output
127*ec779b8eSAndroid Build Coastguard Worker // audio_format_t format
128*ec779b8eSAndroid Build Coastguard Worker // audio_channel_mask_t channelMask
129*ec779b8eSAndroid Build Coastguard Worker // audio_output_flags_t flags (FAST)
130*ec779b8eSAndroid Build Coastguard Worker uint32_t afSampleRate;
131*ec779b8eSAndroid Build Coastguard Worker status_t status;
132*ec779b8eSAndroid Build Coastguard Worker status = AudioSystem::getOutputSamplingRate(&afSampleRate, streamType);
133*ec779b8eSAndroid Build Coastguard Worker if (status != NO_ERROR) {
134*ec779b8eSAndroid Build Coastguard Worker ALOGE("%s(): Unable to query output sample rate for stream type %d; status %d",
135*ec779b8eSAndroid Build Coastguard Worker __func__, streamType, status);
136*ec779b8eSAndroid Build Coastguard Worker return status;
137*ec779b8eSAndroid Build Coastguard Worker }
138*ec779b8eSAndroid Build Coastguard Worker size_t afFrameCount;
139*ec779b8eSAndroid Build Coastguard Worker status = AudioSystem::getOutputFrameCount(&afFrameCount, streamType);
140*ec779b8eSAndroid Build Coastguard Worker if (status != NO_ERROR) {
141*ec779b8eSAndroid Build Coastguard Worker ALOGE("%s(): Unable to query output frame count for stream type %d; status %d",
142*ec779b8eSAndroid Build Coastguard Worker __func__, streamType, status);
143*ec779b8eSAndroid Build Coastguard Worker return status;
144*ec779b8eSAndroid Build Coastguard Worker }
145*ec779b8eSAndroid Build Coastguard Worker uint32_t afLatency;
146*ec779b8eSAndroid Build Coastguard Worker status = AudioSystem::getOutputLatency(&afLatency, streamType);
147*ec779b8eSAndroid Build Coastguard Worker if (status != NO_ERROR) {
148*ec779b8eSAndroid Build Coastguard Worker ALOGE("%s(): Unable to query output latency for stream type %d; status %d",
149*ec779b8eSAndroid Build Coastguard Worker __func__, streamType, status);
150*ec779b8eSAndroid Build Coastguard Worker return status;
151*ec779b8eSAndroid Build Coastguard Worker }
152*ec779b8eSAndroid Build Coastguard Worker
153*ec779b8eSAndroid Build Coastguard Worker // When called from createTrack, speed is 1.0f (normal speed).
154*ec779b8eSAndroid Build Coastguard Worker // This is rechecked again on setting playback rate (TODO: on setting sample rate, too).
155*ec779b8eSAndroid Build Coastguard Worker *frameCount = AudioSystem::calculateMinFrameCount(afLatency, afFrameCount, afSampleRate,
156*ec779b8eSAndroid Build Coastguard Worker sampleRate, 1.0f /*, 0 notificationsPerBufferReq*/);
157*ec779b8eSAndroid Build Coastguard Worker
158*ec779b8eSAndroid Build Coastguard Worker // The formula above should always produce a non-zero value under normal circumstances:
159*ec779b8eSAndroid Build Coastguard Worker // AudioTrack.SAMPLE_RATE_HZ_MIN <= sampleRate <= AudioTrack.SAMPLE_RATE_HZ_MAX.
160*ec779b8eSAndroid Build Coastguard Worker // Return error in the unlikely event that it does not, as that's part of the API contract.
161*ec779b8eSAndroid Build Coastguard Worker if (*frameCount == 0) {
162*ec779b8eSAndroid Build Coastguard Worker ALOGE("%s(): failed for streamType %d, sampleRate %u",
163*ec779b8eSAndroid Build Coastguard Worker __func__, streamType, sampleRate);
164*ec779b8eSAndroid Build Coastguard Worker return BAD_VALUE;
165*ec779b8eSAndroid Build Coastguard Worker }
166*ec779b8eSAndroid Build Coastguard Worker ALOGV("%s(): getMinFrameCount=%zu: afFrameCount=%zu, afSampleRate=%u, afLatency=%u",
167*ec779b8eSAndroid Build Coastguard Worker __func__, *frameCount, afFrameCount, afSampleRate, afLatency);
168*ec779b8eSAndroid Build Coastguard Worker return NO_ERROR;
169*ec779b8eSAndroid Build Coastguard Worker }
170*ec779b8eSAndroid Build Coastguard Worker
171*ec779b8eSAndroid Build Coastguard Worker // static
isDirectOutputSupported(const audio_config_base_t & config,const audio_attributes_t & attributes)172*ec779b8eSAndroid Build Coastguard Worker bool AudioTrack::isDirectOutputSupported(const audio_config_base_t& config,
173*ec779b8eSAndroid Build Coastguard Worker const audio_attributes_t& attributes) {
174*ec779b8eSAndroid Build Coastguard Worker ALOGV("%s()", __FUNCTION__);
175*ec779b8eSAndroid Build Coastguard Worker const sp<media::IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
176*ec779b8eSAndroid Build Coastguard Worker if (aps == 0) return false;
177*ec779b8eSAndroid Build Coastguard Worker
178*ec779b8eSAndroid Build Coastguard Worker auto result = [&]() -> ConversionResult<bool> {
179*ec779b8eSAndroid Build Coastguard Worker media::audio::common::AudioConfigBase configAidl = VALUE_OR_RETURN(
180*ec779b8eSAndroid Build Coastguard Worker legacy2aidl_audio_config_base_t_AudioConfigBase(config, false /*isInput*/));
181*ec779b8eSAndroid Build Coastguard Worker media::audio::common::AudioAttributes attributesAidl = VALUE_OR_RETURN(
182*ec779b8eSAndroid Build Coastguard Worker legacy2aidl_audio_attributes_t_AudioAttributes(attributes));
183*ec779b8eSAndroid Build Coastguard Worker bool retAidl;
184*ec779b8eSAndroid Build Coastguard Worker RETURN_IF_ERROR(aidl_utils::statusTFromBinderStatus(
185*ec779b8eSAndroid Build Coastguard Worker aps->isDirectOutputSupported(configAidl, attributesAidl, &retAidl)));
186*ec779b8eSAndroid Build Coastguard Worker return retAidl;
187*ec779b8eSAndroid Build Coastguard Worker }();
188*ec779b8eSAndroid Build Coastguard Worker return result.value_or(false);
189*ec779b8eSAndroid Build Coastguard Worker }
190*ec779b8eSAndroid Build Coastguard Worker
logIfErrorAndReturnStatus(status_t status,const std::string & errorMessage)191*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::logIfErrorAndReturnStatus(status_t status, const std::string& errorMessage) {
192*ec779b8eSAndroid Build Coastguard Worker if (status != NO_ERROR) {
193*ec779b8eSAndroid Build Coastguard Worker ALOGE_IF(!errorMessage.empty(), "%s", errorMessage.c_str());
194*ec779b8eSAndroid Build Coastguard Worker reportError(status, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE, errorMessage.c_str());
195*ec779b8eSAndroid Build Coastguard Worker }
196*ec779b8eSAndroid Build Coastguard Worker mStatus = status;
197*ec779b8eSAndroid Build Coastguard Worker return mStatus;
198*ec779b8eSAndroid Build Coastguard Worker }
199*ec779b8eSAndroid Build Coastguard Worker // ---------------------------------------------------------------------------
200*ec779b8eSAndroid Build Coastguard Worker
gather(const AudioTrack * track)201*ec779b8eSAndroid Build Coastguard Worker void AudioTrack::MediaMetrics::gather(const AudioTrack *track)
202*ec779b8eSAndroid Build Coastguard Worker {
203*ec779b8eSAndroid Build Coastguard Worker // only if we're in a good state...
204*ec779b8eSAndroid Build Coastguard Worker // XXX: shall we gather alternative info if failing?
205*ec779b8eSAndroid Build Coastguard Worker const status_t lstatus = track->initCheck();
206*ec779b8eSAndroid Build Coastguard Worker if (lstatus != NO_ERROR) {
207*ec779b8eSAndroid Build Coastguard Worker ALOGD("%s(): no metrics gathered, track status=%d", __func__, (int) lstatus);
208*ec779b8eSAndroid Build Coastguard Worker return;
209*ec779b8eSAndroid Build Coastguard Worker }
210*ec779b8eSAndroid Build Coastguard Worker
211*ec779b8eSAndroid Build Coastguard Worker #define MM_PREFIX "android.media.audiotrack." // avoid cut-n-paste errors.
212*ec779b8eSAndroid Build Coastguard Worker
213*ec779b8eSAndroid Build Coastguard Worker // Do not change this without changing the MediaMetricsService side.
214*ec779b8eSAndroid Build Coastguard Worker // Java API 28 entries, do not change.
215*ec779b8eSAndroid Build Coastguard Worker mMetricsItem->setCString(MM_PREFIX "streamtype", toString(track->streamType()).c_str());
216*ec779b8eSAndroid Build Coastguard Worker mMetricsItem->setCString(MM_PREFIX "type",
217*ec779b8eSAndroid Build Coastguard Worker toString(track->mAttributes.content_type).c_str());
218*ec779b8eSAndroid Build Coastguard Worker mMetricsItem->setCString(MM_PREFIX "usage", toString(track->mAttributes.usage).c_str());
219*ec779b8eSAndroid Build Coastguard Worker
220*ec779b8eSAndroid Build Coastguard Worker // Non-API entries, these can change due to a Java string mistake.
221*ec779b8eSAndroid Build Coastguard Worker mMetricsItem->setInt32(MM_PREFIX "sampleRate", (int32_t)track->mSampleRate);
222*ec779b8eSAndroid Build Coastguard Worker mMetricsItem->setInt64(MM_PREFIX "channelMask", (int64_t)track->mChannelMask);
223*ec779b8eSAndroid Build Coastguard Worker // Non-API entries, these can change.
224*ec779b8eSAndroid Build Coastguard Worker mMetricsItem->setInt32(MM_PREFIX "portId", (int32_t)track->mPortId);
225*ec779b8eSAndroid Build Coastguard Worker mMetricsItem->setCString(MM_PREFIX "encoding", toString(track->mFormat).c_str());
226*ec779b8eSAndroid Build Coastguard Worker mMetricsItem->setInt32(MM_PREFIX "frameCount", (int32_t)track->mFrameCount);
227*ec779b8eSAndroid Build Coastguard Worker mMetricsItem->setCString(MM_PREFIX "attributes", toString(track->mAttributes).c_str());
228*ec779b8eSAndroid Build Coastguard Worker mMetricsItem->setCString(MM_PREFIX "logSessionId", track->mLogSessionId.c_str());
229*ec779b8eSAndroid Build Coastguard Worker mMetricsItem->setInt32(MM_PREFIX "underrunFrames", (int32_t)track->getUnderrunFrames());
230*ec779b8eSAndroid Build Coastguard Worker }
231*ec779b8eSAndroid Build Coastguard Worker
232*ec779b8eSAndroid Build Coastguard Worker // hand the user a snapshot of the metrics.
getMetrics(mediametrics::Item * & item)233*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::getMetrics(mediametrics::Item * &item)
234*ec779b8eSAndroid Build Coastguard Worker {
235*ec779b8eSAndroid Build Coastguard Worker mMediaMetrics.gather(this);
236*ec779b8eSAndroid Build Coastguard Worker mediametrics::Item *tmp = mMediaMetrics.dup();
237*ec779b8eSAndroid Build Coastguard Worker if (tmp == nullptr) {
238*ec779b8eSAndroid Build Coastguard Worker return BAD_VALUE;
239*ec779b8eSAndroid Build Coastguard Worker }
240*ec779b8eSAndroid Build Coastguard Worker item = tmp;
241*ec779b8eSAndroid Build Coastguard Worker return NO_ERROR;
242*ec779b8eSAndroid Build Coastguard Worker }
243*ec779b8eSAndroid Build Coastguard Worker
AudioTrack(const AttributionSourceState & attributionSource)244*ec779b8eSAndroid Build Coastguard Worker AudioTrack::AudioTrack(const AttributionSourceState& attributionSource)
245*ec779b8eSAndroid Build Coastguard Worker : mClientAttributionSource(attributionSource)
246*ec779b8eSAndroid Build Coastguard Worker {
247*ec779b8eSAndroid Build Coastguard Worker }
248*ec779b8eSAndroid Build Coastguard Worker
AudioTrack(audio_stream_type_t streamType,uint32_t sampleRate,audio_format_t format,audio_channel_mask_t channelMask,size_t frameCount,audio_output_flags_t flags,const wp<IAudioTrackCallback> & callback,int32_t notificationFrames,audio_session_t sessionId,transfer_type transferType,const audio_offload_info_t * offloadInfo,const AttributionSourceState & attributionSource,const audio_attributes_t * pAttributes,bool doNotReconnect,float maxRequiredSpeed,audio_port_handle_t selectedDeviceId)249*ec779b8eSAndroid Build Coastguard Worker AudioTrack::AudioTrack(
250*ec779b8eSAndroid Build Coastguard Worker audio_stream_type_t streamType,
251*ec779b8eSAndroid Build Coastguard Worker uint32_t sampleRate,
252*ec779b8eSAndroid Build Coastguard Worker audio_format_t format,
253*ec779b8eSAndroid Build Coastguard Worker audio_channel_mask_t channelMask,
254*ec779b8eSAndroid Build Coastguard Worker size_t frameCount,
255*ec779b8eSAndroid Build Coastguard Worker audio_output_flags_t flags,
256*ec779b8eSAndroid Build Coastguard Worker const wp<IAudioTrackCallback> & callback,
257*ec779b8eSAndroid Build Coastguard Worker int32_t notificationFrames,
258*ec779b8eSAndroid Build Coastguard Worker audio_session_t sessionId,
259*ec779b8eSAndroid Build Coastguard Worker transfer_type transferType,
260*ec779b8eSAndroid Build Coastguard Worker const audio_offload_info_t *offloadInfo,
261*ec779b8eSAndroid Build Coastguard Worker const AttributionSourceState& attributionSource,
262*ec779b8eSAndroid Build Coastguard Worker const audio_attributes_t* pAttributes,
263*ec779b8eSAndroid Build Coastguard Worker bool doNotReconnect,
264*ec779b8eSAndroid Build Coastguard Worker float maxRequiredSpeed,
265*ec779b8eSAndroid Build Coastguard Worker audio_port_handle_t selectedDeviceId)
266*ec779b8eSAndroid Build Coastguard Worker {
267*ec779b8eSAndroid Build Coastguard Worker mSetParams = std::make_unique<SetParams>(
268*ec779b8eSAndroid Build Coastguard Worker streamType, sampleRate, format, channelMask, frameCount, flags, callback,
269*ec779b8eSAndroid Build Coastguard Worker notificationFrames, nullptr /*sharedBuffer*/, false /*threadCanCallJava*/,
270*ec779b8eSAndroid Build Coastguard Worker sessionId, transferType, offloadInfo, attributionSource, pAttributes,
271*ec779b8eSAndroid Build Coastguard Worker doNotReconnect, maxRequiredSpeed, selectedDeviceId);
272*ec779b8eSAndroid Build Coastguard Worker }
273*ec779b8eSAndroid Build Coastguard Worker
274*ec779b8eSAndroid Build Coastguard Worker namespace {
275*ec779b8eSAndroid Build Coastguard Worker class LegacyCallbackWrapper : public AudioTrack::IAudioTrackCallback {
276*ec779b8eSAndroid Build Coastguard Worker const AudioTrack::legacy_callback_t mCallback;
277*ec779b8eSAndroid Build Coastguard Worker void * const mData;
278*ec779b8eSAndroid Build Coastguard Worker public:
LegacyCallbackWrapper(AudioTrack::legacy_callback_t callback,void * user)279*ec779b8eSAndroid Build Coastguard Worker LegacyCallbackWrapper(AudioTrack::legacy_callback_t callback, void* user)
280*ec779b8eSAndroid Build Coastguard Worker : mCallback(callback), mData(user) {}
onMoreData(const AudioTrack::Buffer & buffer)281*ec779b8eSAndroid Build Coastguard Worker size_t onMoreData(const AudioTrack::Buffer & buffer) override {
282*ec779b8eSAndroid Build Coastguard Worker AudioTrack::Buffer copy = buffer;
283*ec779b8eSAndroid Build Coastguard Worker mCallback(AudioTrack::EVENT_MORE_DATA, mData, static_cast<void*>(©));
284*ec779b8eSAndroid Build Coastguard Worker return copy.size();
285*ec779b8eSAndroid Build Coastguard Worker }
onUnderrun()286*ec779b8eSAndroid Build Coastguard Worker void onUnderrun() override {
287*ec779b8eSAndroid Build Coastguard Worker mCallback(AudioTrack::EVENT_UNDERRUN, mData, nullptr);
288*ec779b8eSAndroid Build Coastguard Worker }
onLoopEnd(int32_t loopsRemaining)289*ec779b8eSAndroid Build Coastguard Worker void onLoopEnd(int32_t loopsRemaining) override {
290*ec779b8eSAndroid Build Coastguard Worker mCallback(AudioTrack::EVENT_LOOP_END, mData, &loopsRemaining);
291*ec779b8eSAndroid Build Coastguard Worker }
onMarker(uint32_t markerPosition)292*ec779b8eSAndroid Build Coastguard Worker void onMarker(uint32_t markerPosition) override {
293*ec779b8eSAndroid Build Coastguard Worker mCallback(AudioTrack::EVENT_MARKER, mData, &markerPosition);
294*ec779b8eSAndroid Build Coastguard Worker }
onNewPos(uint32_t newPos)295*ec779b8eSAndroid Build Coastguard Worker void onNewPos(uint32_t newPos) override {
296*ec779b8eSAndroid Build Coastguard Worker mCallback(AudioTrack::EVENT_NEW_POS, mData, &newPos);
297*ec779b8eSAndroid Build Coastguard Worker }
onBufferEnd()298*ec779b8eSAndroid Build Coastguard Worker void onBufferEnd() override {
299*ec779b8eSAndroid Build Coastguard Worker mCallback(AudioTrack::EVENT_BUFFER_END, mData, nullptr);
300*ec779b8eSAndroid Build Coastguard Worker }
onNewIAudioTrack()301*ec779b8eSAndroid Build Coastguard Worker void onNewIAudioTrack() override {
302*ec779b8eSAndroid Build Coastguard Worker mCallback(AudioTrack::EVENT_NEW_IAUDIOTRACK, mData, nullptr);
303*ec779b8eSAndroid Build Coastguard Worker }
onStreamEnd()304*ec779b8eSAndroid Build Coastguard Worker void onStreamEnd() override {
305*ec779b8eSAndroid Build Coastguard Worker mCallback(AudioTrack::EVENT_STREAM_END, mData, nullptr);
306*ec779b8eSAndroid Build Coastguard Worker }
onCanWriteMoreData(const AudioTrack::Buffer & buffer)307*ec779b8eSAndroid Build Coastguard Worker size_t onCanWriteMoreData(const AudioTrack::Buffer & buffer) override {
308*ec779b8eSAndroid Build Coastguard Worker AudioTrack::Buffer copy = buffer;
309*ec779b8eSAndroid Build Coastguard Worker mCallback(AudioTrack::EVENT_CAN_WRITE_MORE_DATA, mData, static_cast<void*>(©));
310*ec779b8eSAndroid Build Coastguard Worker return copy.size();
311*ec779b8eSAndroid Build Coastguard Worker }
312*ec779b8eSAndroid Build Coastguard Worker };
313*ec779b8eSAndroid Build Coastguard Worker }
AudioTrack(audio_stream_type_t streamType,uint32_t sampleRate,audio_format_t format,audio_channel_mask_t channelMask,const sp<IMemory> & sharedBuffer,audio_output_flags_t flags,const wp<IAudioTrackCallback> & callback,int32_t notificationFrames,audio_session_t sessionId,transfer_type transferType,const audio_offload_info_t * offloadInfo,const AttributionSourceState & attributionSource,const audio_attributes_t * pAttributes,bool doNotReconnect,float maxRequiredSpeed)314*ec779b8eSAndroid Build Coastguard Worker AudioTrack::AudioTrack(
315*ec779b8eSAndroid Build Coastguard Worker audio_stream_type_t streamType,
316*ec779b8eSAndroid Build Coastguard Worker uint32_t sampleRate,
317*ec779b8eSAndroid Build Coastguard Worker audio_format_t format,
318*ec779b8eSAndroid Build Coastguard Worker audio_channel_mask_t channelMask,
319*ec779b8eSAndroid Build Coastguard Worker const sp<IMemory>& sharedBuffer,
320*ec779b8eSAndroid Build Coastguard Worker audio_output_flags_t flags,
321*ec779b8eSAndroid Build Coastguard Worker const wp<IAudioTrackCallback>& callback,
322*ec779b8eSAndroid Build Coastguard Worker int32_t notificationFrames,
323*ec779b8eSAndroid Build Coastguard Worker audio_session_t sessionId,
324*ec779b8eSAndroid Build Coastguard Worker transfer_type transferType,
325*ec779b8eSAndroid Build Coastguard Worker const audio_offload_info_t *offloadInfo,
326*ec779b8eSAndroid Build Coastguard Worker const AttributionSourceState& attributionSource,
327*ec779b8eSAndroid Build Coastguard Worker const audio_attributes_t* pAttributes,
328*ec779b8eSAndroid Build Coastguard Worker bool doNotReconnect,
329*ec779b8eSAndroid Build Coastguard Worker float maxRequiredSpeed)
330*ec779b8eSAndroid Build Coastguard Worker {
331*ec779b8eSAndroid Build Coastguard Worker mAttributes = AUDIO_ATTRIBUTES_INITIALIZER;
332*ec779b8eSAndroid Build Coastguard Worker
333*ec779b8eSAndroid Build Coastguard Worker mSetParams = std::unique_ptr<SetParams>{
334*ec779b8eSAndroid Build Coastguard Worker new SetParams{streamType, sampleRate, format, channelMask, 0 /*frameCount*/, flags,
335*ec779b8eSAndroid Build Coastguard Worker callback, notificationFrames, sharedBuffer, false /*threadCanCallJava*/,
336*ec779b8eSAndroid Build Coastguard Worker sessionId, transferType, offloadInfo, attributionSource, pAttributes,
337*ec779b8eSAndroid Build Coastguard Worker doNotReconnect, maxRequiredSpeed, AUDIO_PORT_HANDLE_NONE}};
338*ec779b8eSAndroid Build Coastguard Worker }
339*ec779b8eSAndroid Build Coastguard Worker
onFirstRef()340*ec779b8eSAndroid Build Coastguard Worker void AudioTrack::onFirstRef() {
341*ec779b8eSAndroid Build Coastguard Worker if (mSetParams) {
342*ec779b8eSAndroid Build Coastguard Worker set(*mSetParams);
343*ec779b8eSAndroid Build Coastguard Worker mSetParams.reset();
344*ec779b8eSAndroid Build Coastguard Worker }
345*ec779b8eSAndroid Build Coastguard Worker }
346*ec779b8eSAndroid Build Coastguard Worker
~AudioTrack()347*ec779b8eSAndroid Build Coastguard Worker AudioTrack::~AudioTrack()
348*ec779b8eSAndroid Build Coastguard Worker {
349*ec779b8eSAndroid Build Coastguard Worker // pull together the numbers, before we clean up our structures
350*ec779b8eSAndroid Build Coastguard Worker mMediaMetrics.gather(this);
351*ec779b8eSAndroid Build Coastguard Worker
352*ec779b8eSAndroid Build Coastguard Worker mediametrics::LogItem(mMetricsId)
353*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_DTOR)
354*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_CALLERNAME,
355*ec779b8eSAndroid Build Coastguard Worker mCallerName.empty()
356*ec779b8eSAndroid Build Coastguard Worker ? AMEDIAMETRICS_PROP_CALLERNAME_VALUE_UNKNOWN
357*ec779b8eSAndroid Build Coastguard Worker : mCallerName.c_str())
358*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
359*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)mStatus)
360*ec779b8eSAndroid Build Coastguard Worker .record();
361*ec779b8eSAndroid Build Coastguard Worker
362*ec779b8eSAndroid Build Coastguard Worker stopAndJoinCallbacks(); // checks mStatus
363*ec779b8eSAndroid Build Coastguard Worker
364*ec779b8eSAndroid Build Coastguard Worker if (mStatus == NO_ERROR) {
365*ec779b8eSAndroid Build Coastguard Worker IInterface::asBinder(mAudioTrack)->unlinkToDeath(mDeathNotifier, this);
366*ec779b8eSAndroid Build Coastguard Worker mAudioTrack.clear();
367*ec779b8eSAndroid Build Coastguard Worker mCblkMemory.clear();
368*ec779b8eSAndroid Build Coastguard Worker mSharedBuffer.clear();
369*ec779b8eSAndroid Build Coastguard Worker IPCThreadState::self()->flushCommands();
370*ec779b8eSAndroid Build Coastguard Worker pid_t clientPid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(mClientAttributionSource.pid));
371*ec779b8eSAndroid Build Coastguard Worker ALOGV("%s(%d), releasing session id %d from %d on behalf of %d",
372*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId,
373*ec779b8eSAndroid Build Coastguard Worker mSessionId, IPCThreadState::self()->getCallingPid(), clientPid);
374*ec779b8eSAndroid Build Coastguard Worker AudioSystem::releaseAudioSessionId(mSessionId, clientPid);
375*ec779b8eSAndroid Build Coastguard Worker }
376*ec779b8eSAndroid Build Coastguard Worker
377*ec779b8eSAndroid Build Coastguard Worker if (mOutput != AUDIO_IO_HANDLE_NONE) {
378*ec779b8eSAndroid Build Coastguard Worker AudioSystem::removeAudioDeviceCallback(this, mOutput, mPortId);
379*ec779b8eSAndroid Build Coastguard Worker }
380*ec779b8eSAndroid Build Coastguard Worker }
381*ec779b8eSAndroid Build Coastguard Worker
stopAndJoinCallbacks()382*ec779b8eSAndroid Build Coastguard Worker void AudioTrack::stopAndJoinCallbacks() {
383*ec779b8eSAndroid Build Coastguard Worker // Make sure that callback function exits in the case where
384*ec779b8eSAndroid Build Coastguard Worker // it is looping on buffer full condition in obtainBuffer().
385*ec779b8eSAndroid Build Coastguard Worker // Otherwise the callback thread will never exit.
386*ec779b8eSAndroid Build Coastguard Worker stop();
387*ec779b8eSAndroid Build Coastguard Worker if (mAudioTrackThread != 0) { // not thread safe
388*ec779b8eSAndroid Build Coastguard Worker mAudioTrackThread->requestExit(); // see comment in AudioTrack.h
389*ec779b8eSAndroid Build Coastguard Worker mProxy->interrupt();
390*ec779b8eSAndroid Build Coastguard Worker mAudioTrackThread->requestExitAndWait();
391*ec779b8eSAndroid Build Coastguard Worker mAudioTrackThread.clear();
392*ec779b8eSAndroid Build Coastguard Worker }
393*ec779b8eSAndroid Build Coastguard Worker
394*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
395*ec779b8eSAndroid Build Coastguard Worker if (mDeviceCallback != 0 && mOutput != AUDIO_IO_HANDLE_NONE) {
396*ec779b8eSAndroid Build Coastguard Worker // This may not stop all of these device callbacks!
397*ec779b8eSAndroid Build Coastguard Worker // TODO: Add some sort of protection.
398*ec779b8eSAndroid Build Coastguard Worker AudioSystem::removeAudioDeviceCallback(this, mOutput, mPortId);
399*ec779b8eSAndroid Build Coastguard Worker mDeviceCallback.clear();
400*ec779b8eSAndroid Build Coastguard Worker }
401*ec779b8eSAndroid Build Coastguard Worker }
set(audio_stream_type_t streamType,uint32_t sampleRate,audio_format_t format,audio_channel_mask_t channelMask,size_t frameCount,audio_output_flags_t flags,const wp<IAudioTrackCallback> & callback,int32_t notificationFrames,const sp<IMemory> & sharedBuffer,bool threadCanCallJava,audio_session_t sessionId,transfer_type transferType,const audio_offload_info_t * offloadInfo,const AttributionSourceState & attributionSource,const audio_attributes_t * pAttributes,bool doNotReconnect,float maxRequiredSpeed,audio_port_handle_t selectedDeviceId)402*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::set(
403*ec779b8eSAndroid Build Coastguard Worker audio_stream_type_t streamType,
404*ec779b8eSAndroid Build Coastguard Worker uint32_t sampleRate,
405*ec779b8eSAndroid Build Coastguard Worker audio_format_t format,
406*ec779b8eSAndroid Build Coastguard Worker audio_channel_mask_t channelMask,
407*ec779b8eSAndroid Build Coastguard Worker size_t frameCount,
408*ec779b8eSAndroid Build Coastguard Worker audio_output_flags_t flags,
409*ec779b8eSAndroid Build Coastguard Worker const wp<IAudioTrackCallback>& callback,
410*ec779b8eSAndroid Build Coastguard Worker int32_t notificationFrames,
411*ec779b8eSAndroid Build Coastguard Worker const sp<IMemory>& sharedBuffer,
412*ec779b8eSAndroid Build Coastguard Worker bool threadCanCallJava,
413*ec779b8eSAndroid Build Coastguard Worker audio_session_t sessionId,
414*ec779b8eSAndroid Build Coastguard Worker transfer_type transferType,
415*ec779b8eSAndroid Build Coastguard Worker const audio_offload_info_t *offloadInfo,
416*ec779b8eSAndroid Build Coastguard Worker const AttributionSourceState& attributionSource,
417*ec779b8eSAndroid Build Coastguard Worker const audio_attributes_t* pAttributes,
418*ec779b8eSAndroid Build Coastguard Worker bool doNotReconnect,
419*ec779b8eSAndroid Build Coastguard Worker float maxRequiredSpeed,
420*ec779b8eSAndroid Build Coastguard Worker audio_port_handle_t selectedDeviceId)
421*ec779b8eSAndroid Build Coastguard Worker {
422*ec779b8eSAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(mInitialized, "%s: should not be called twice", __func__);
423*ec779b8eSAndroid Build Coastguard Worker mInitialized = true;
424*ec779b8eSAndroid Build Coastguard Worker status_t status;
425*ec779b8eSAndroid Build Coastguard Worker uint32_t channelCount;
426*ec779b8eSAndroid Build Coastguard Worker pid_t callingPid;
427*ec779b8eSAndroid Build Coastguard Worker pid_t myPid;
428*ec779b8eSAndroid Build Coastguard Worker auto uid = aidl2legacy_int32_t_uid_t(attributionSource.uid);
429*ec779b8eSAndroid Build Coastguard Worker auto pid = aidl2legacy_int32_t_pid_t(attributionSource.pid);
430*ec779b8eSAndroid Build Coastguard Worker if (!uid.ok()) {
431*ec779b8eSAndroid Build Coastguard Worker return logIfErrorAndReturnStatus(
432*ec779b8eSAndroid Build Coastguard Worker BAD_VALUE, StringPrintf("%s: received invalid attribution source uid", __func__));
433*ec779b8eSAndroid Build Coastguard Worker }
434*ec779b8eSAndroid Build Coastguard Worker if (!pid.ok()) {
435*ec779b8eSAndroid Build Coastguard Worker return logIfErrorAndReturnStatus(
436*ec779b8eSAndroid Build Coastguard Worker BAD_VALUE, StringPrintf("%s: received invalid attribution source pid", __func__));
437*ec779b8eSAndroid Build Coastguard Worker }
438*ec779b8eSAndroid Build Coastguard Worker // Note mPortId is not valid until the track is created, so omit mPortId in ALOG for set.
439*ec779b8eSAndroid Build Coastguard Worker ALOGV("%s(): streamType %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, "
440*ec779b8eSAndroid Build Coastguard Worker "flags %#x, notificationFrames %d, sessionId %d, transferType %d, uid %d, pid %d",
441*ec779b8eSAndroid Build Coastguard Worker __func__,
442*ec779b8eSAndroid Build Coastguard Worker streamType, sampleRate, format, channelMask, frameCount, flags, notificationFrames,
443*ec779b8eSAndroid Build Coastguard Worker sessionId, transferType, attributionSource.uid, attributionSource.pid);
444*ec779b8eSAndroid Build Coastguard Worker
445*ec779b8eSAndroid Build Coastguard Worker mThreadCanCallJava = threadCanCallJava;
446*ec779b8eSAndroid Build Coastguard Worker
447*ec779b8eSAndroid Build Coastguard Worker // These variables are pulled in an error report, so we initialize them early.
448*ec779b8eSAndroid Build Coastguard Worker mSelectedDeviceId = selectedDeviceId;
449*ec779b8eSAndroid Build Coastguard Worker mSessionId = sessionId;
450*ec779b8eSAndroid Build Coastguard Worker mChannelMask = channelMask;
451*ec779b8eSAndroid Build Coastguard Worker mReqFrameCount = mFrameCount = frameCount;
452*ec779b8eSAndroid Build Coastguard Worker mSampleRate = sampleRate;
453*ec779b8eSAndroid Build Coastguard Worker mOriginalSampleRate = sampleRate;
454*ec779b8eSAndroid Build Coastguard Worker mAttributes = pAttributes != nullptr ? *pAttributes : AUDIO_ATTRIBUTES_INITIALIZER;
455*ec779b8eSAndroid Build Coastguard Worker mPlaybackRate = AUDIO_PLAYBACK_RATE_DEFAULT;
456*ec779b8eSAndroid Build Coastguard Worker
457*ec779b8eSAndroid Build Coastguard Worker // update format and flags before storing them in mFormat, mOrigFlags and mFlags
458*ec779b8eSAndroid Build Coastguard Worker if (pAttributes != NULL) {
459*ec779b8eSAndroid Build Coastguard Worker // stream type shouldn't be looked at, this track has audio attributes
460*ec779b8eSAndroid Build Coastguard Worker ALOGV("%s(): Building AudioTrack with attributes:"
461*ec779b8eSAndroid Build Coastguard Worker " usage=%d content=%d flags=0x%x tags=[%s]",
462*ec779b8eSAndroid Build Coastguard Worker __func__,
463*ec779b8eSAndroid Build Coastguard Worker mAttributes.usage, mAttributes.content_type, mAttributes.flags, mAttributes.tags);
464*ec779b8eSAndroid Build Coastguard Worker audio_flags_to_audio_output_flags(mAttributes.flags, &flags);
465*ec779b8eSAndroid Build Coastguard Worker }
466*ec779b8eSAndroid Build Coastguard Worker
467*ec779b8eSAndroid Build Coastguard Worker // these below should probably come from the audioFlinger too...
468*ec779b8eSAndroid Build Coastguard Worker if (format == AUDIO_FORMAT_DEFAULT) {
469*ec779b8eSAndroid Build Coastguard Worker format = AUDIO_FORMAT_PCM_16_BIT;
470*ec779b8eSAndroid Build Coastguard Worker } else if (format == AUDIO_FORMAT_IEC61937) { // HDMI pass-through?
471*ec779b8eSAndroid Build Coastguard Worker flags = static_cast<audio_output_flags_t>(flags | AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO);
472*ec779b8eSAndroid Build Coastguard Worker }
473*ec779b8eSAndroid Build Coastguard Worker
474*ec779b8eSAndroid Build Coastguard Worker // force direct flag if format is not linear PCM
475*ec779b8eSAndroid Build Coastguard Worker // or offload was requested
476*ec779b8eSAndroid Build Coastguard Worker if ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)
477*ec779b8eSAndroid Build Coastguard Worker || !audio_is_linear_pcm(format)) {
478*ec779b8eSAndroid Build Coastguard Worker ALOGV( (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)
479*ec779b8eSAndroid Build Coastguard Worker ? "%s(): Offload request, forcing to Direct Output"
480*ec779b8eSAndroid Build Coastguard Worker : "%s(): Not linear PCM, forcing to Direct Output",
481*ec779b8eSAndroid Build Coastguard Worker __func__);
482*ec779b8eSAndroid Build Coastguard Worker flags = (audio_output_flags_t)
483*ec779b8eSAndroid Build Coastguard Worker // FIXME why can't we allow direct AND fast?
484*ec779b8eSAndroid Build Coastguard Worker ((flags | AUDIO_OUTPUT_FLAG_DIRECT) & ~AUDIO_OUTPUT_FLAG_FAST);
485*ec779b8eSAndroid Build Coastguard Worker }
486*ec779b8eSAndroid Build Coastguard Worker
487*ec779b8eSAndroid Build Coastguard Worker // force direct flag if HW A/V sync requested
488*ec779b8eSAndroid Build Coastguard Worker if ((flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC) != 0) {
489*ec779b8eSAndroid Build Coastguard Worker flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_DIRECT);
490*ec779b8eSAndroid Build Coastguard Worker }
491*ec779b8eSAndroid Build Coastguard Worker
492*ec779b8eSAndroid Build Coastguard Worker mFormat = format;
493*ec779b8eSAndroid Build Coastguard Worker mOrigFlags = mFlags = flags;
494*ec779b8eSAndroid Build Coastguard Worker
495*ec779b8eSAndroid Build Coastguard Worker switch (transferType) {
496*ec779b8eSAndroid Build Coastguard Worker case TRANSFER_DEFAULT:
497*ec779b8eSAndroid Build Coastguard Worker if (sharedBuffer != 0) {
498*ec779b8eSAndroid Build Coastguard Worker transferType = TRANSFER_SHARED;
499*ec779b8eSAndroid Build Coastguard Worker } else if (callback == nullptr|| threadCanCallJava) {
500*ec779b8eSAndroid Build Coastguard Worker transferType = TRANSFER_SYNC;
501*ec779b8eSAndroid Build Coastguard Worker } else {
502*ec779b8eSAndroid Build Coastguard Worker transferType = TRANSFER_CALLBACK;
503*ec779b8eSAndroid Build Coastguard Worker }
504*ec779b8eSAndroid Build Coastguard Worker break;
505*ec779b8eSAndroid Build Coastguard Worker case TRANSFER_CALLBACK:
506*ec779b8eSAndroid Build Coastguard Worker case TRANSFER_SYNC_NOTIF_CALLBACK:
507*ec779b8eSAndroid Build Coastguard Worker if (callback == nullptr || sharedBuffer != 0) {
508*ec779b8eSAndroid Build Coastguard Worker return logIfErrorAndReturnStatus(
509*ec779b8eSAndroid Build Coastguard Worker BAD_VALUE,
510*ec779b8eSAndroid Build Coastguard Worker StringPrintf(
511*ec779b8eSAndroid Build Coastguard Worker "%s: Transfer type %s but callback == nullptr || sharedBuffer != 0",
512*ec779b8eSAndroid Build Coastguard Worker convertTransferToText(transferType), __func__));
513*ec779b8eSAndroid Build Coastguard Worker }
514*ec779b8eSAndroid Build Coastguard Worker break;
515*ec779b8eSAndroid Build Coastguard Worker case TRANSFER_OBTAIN:
516*ec779b8eSAndroid Build Coastguard Worker case TRANSFER_SYNC:
517*ec779b8eSAndroid Build Coastguard Worker if (sharedBuffer != 0) {
518*ec779b8eSAndroid Build Coastguard Worker return logIfErrorAndReturnStatus(
519*ec779b8eSAndroid Build Coastguard Worker BAD_VALUE,
520*ec779b8eSAndroid Build Coastguard Worker StringPrintf("%s: Transfer type TRANSFER_OBTAIN but sharedBuffer != 0",
521*ec779b8eSAndroid Build Coastguard Worker __func__));
522*ec779b8eSAndroid Build Coastguard Worker }
523*ec779b8eSAndroid Build Coastguard Worker break;
524*ec779b8eSAndroid Build Coastguard Worker case TRANSFER_SHARED:
525*ec779b8eSAndroid Build Coastguard Worker if (sharedBuffer == 0) {
526*ec779b8eSAndroid Build Coastguard Worker return logIfErrorAndReturnStatus(
527*ec779b8eSAndroid Build Coastguard Worker BAD_VALUE,
528*ec779b8eSAndroid Build Coastguard Worker StringPrintf("%s: Transfer type TRANSFER_SHARED but sharedBuffer == 0",
529*ec779b8eSAndroid Build Coastguard Worker __func__));
530*ec779b8eSAndroid Build Coastguard Worker }
531*ec779b8eSAndroid Build Coastguard Worker break;
532*ec779b8eSAndroid Build Coastguard Worker default:
533*ec779b8eSAndroid Build Coastguard Worker return logIfErrorAndReturnStatus(
534*ec779b8eSAndroid Build Coastguard Worker BAD_VALUE, StringPrintf("%s: Invalid transfer type %d", __func__, transferType));
535*ec779b8eSAndroid Build Coastguard Worker }
536*ec779b8eSAndroid Build Coastguard Worker mSharedBuffer = sharedBuffer;
537*ec779b8eSAndroid Build Coastguard Worker mTransfer = transferType;
538*ec779b8eSAndroid Build Coastguard Worker mDoNotReconnect = doNotReconnect;
539*ec779b8eSAndroid Build Coastguard Worker
540*ec779b8eSAndroid Build Coastguard Worker ALOGV_IF(sharedBuffer != 0, "%s(): sharedBuffer: %p, size: %zu",
541*ec779b8eSAndroid Build Coastguard Worker __func__, sharedBuffer->unsecurePointer(), sharedBuffer->size());
542*ec779b8eSAndroid Build Coastguard Worker
543*ec779b8eSAndroid Build Coastguard Worker // invariant that mAudioTrack != 0 is true only after set() returns successfully
544*ec779b8eSAndroid Build Coastguard Worker if (mAudioTrack != 0) {
545*ec779b8eSAndroid Build Coastguard Worker return logIfErrorAndReturnStatus(INVALID_OPERATION,
546*ec779b8eSAndroid Build Coastguard Worker StringPrintf("%s: Track already in use", __func__));
547*ec779b8eSAndroid Build Coastguard Worker }
548*ec779b8eSAndroid Build Coastguard Worker
549*ec779b8eSAndroid Build Coastguard Worker // handle default values first.
550*ec779b8eSAndroid Build Coastguard Worker if (streamType == AUDIO_STREAM_DEFAULT) {
551*ec779b8eSAndroid Build Coastguard Worker streamType = AUDIO_STREAM_MUSIC;
552*ec779b8eSAndroid Build Coastguard Worker }
553*ec779b8eSAndroid Build Coastguard Worker if (pAttributes == NULL) {
554*ec779b8eSAndroid Build Coastguard Worker if (uint32_t(streamType) >= AUDIO_STREAM_PUBLIC_CNT) {
555*ec779b8eSAndroid Build Coastguard Worker return logIfErrorAndReturnStatus(
556*ec779b8eSAndroid Build Coastguard Worker BAD_VALUE, StringPrintf("%s: Invalid stream type %d", __func__, streamType));
557*ec779b8eSAndroid Build Coastguard Worker }
558*ec779b8eSAndroid Build Coastguard Worker mOriginalStreamType = streamType;
559*ec779b8eSAndroid Build Coastguard Worker } else {
560*ec779b8eSAndroid Build Coastguard Worker mOriginalStreamType = AUDIO_STREAM_DEFAULT;
561*ec779b8eSAndroid Build Coastguard Worker }
562*ec779b8eSAndroid Build Coastguard Worker
563*ec779b8eSAndroid Build Coastguard Worker // validate parameters
564*ec779b8eSAndroid Build Coastguard Worker if (!audio_is_valid_format(format)) {
565*ec779b8eSAndroid Build Coastguard Worker return logIfErrorAndReturnStatus(BAD_VALUE,
566*ec779b8eSAndroid Build Coastguard Worker StringPrintf("%s: Invalid format %#x", __func__, format));
567*ec779b8eSAndroid Build Coastguard Worker }
568*ec779b8eSAndroid Build Coastguard Worker
569*ec779b8eSAndroid Build Coastguard Worker if (!audio_is_output_channel(channelMask)) {
570*ec779b8eSAndroid Build Coastguard Worker return logIfErrorAndReturnStatus(
571*ec779b8eSAndroid Build Coastguard Worker BAD_VALUE, StringPrintf("%s: Invalid channel mask %#x", __func__, channelMask));
572*ec779b8eSAndroid Build Coastguard Worker }
573*ec779b8eSAndroid Build Coastguard Worker channelCount = audio_channel_count_from_out_mask(channelMask);
574*ec779b8eSAndroid Build Coastguard Worker mChannelCount = channelCount;
575*ec779b8eSAndroid Build Coastguard Worker
576*ec779b8eSAndroid Build Coastguard Worker if (!(mFlags & AUDIO_OUTPUT_FLAG_DIRECT)) {
577*ec779b8eSAndroid Build Coastguard Worker // createTrack will return an error if PCM format is not supported by server,
578*ec779b8eSAndroid Build Coastguard Worker // so no need to check for specific PCM formats here
579*ec779b8eSAndroid Build Coastguard Worker ALOGW_IF(!audio_has_proportional_frames(format), "%s(): no direct flag for format 0x%x",
580*ec779b8eSAndroid Build Coastguard Worker __func__, format);
581*ec779b8eSAndroid Build Coastguard Worker }
582*ec779b8eSAndroid Build Coastguard Worker mFrameSize = audio_bytes_per_frame(channelCount, format);
583*ec779b8eSAndroid Build Coastguard Worker
584*ec779b8eSAndroid Build Coastguard Worker // sampling rate must be specified for direct outputs
585*ec779b8eSAndroid Build Coastguard Worker if (sampleRate == 0 && (mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
586*ec779b8eSAndroid Build Coastguard Worker return logIfErrorAndReturnStatus(
587*ec779b8eSAndroid Build Coastguard Worker BAD_VALUE,
588*ec779b8eSAndroid Build Coastguard Worker StringPrintf("%s: sample rate must be specified for direct outputs", __func__));
589*ec779b8eSAndroid Build Coastguard Worker }
590*ec779b8eSAndroid Build Coastguard Worker // 1.0 <= mMaxRequiredSpeed <= AUDIO_TIMESTRETCH_SPEED_MAX
591*ec779b8eSAndroid Build Coastguard Worker mMaxRequiredSpeed = min(max(maxRequiredSpeed, 1.0f), AUDIO_TIMESTRETCH_SPEED_MAX);
592*ec779b8eSAndroid Build Coastguard Worker
593*ec779b8eSAndroid Build Coastguard Worker // Make copy of input parameter offloadInfo so that in the future:
594*ec779b8eSAndroid Build Coastguard Worker // (a) createTrack_l doesn't need it as an input parameter
595*ec779b8eSAndroid Build Coastguard Worker // (b) we can support re-creation of offloaded tracks
596*ec779b8eSAndroid Build Coastguard Worker if (offloadInfo != NULL) {
597*ec779b8eSAndroid Build Coastguard Worker mOffloadInfoCopy = *offloadInfo;
598*ec779b8eSAndroid Build Coastguard Worker } else {
599*ec779b8eSAndroid Build Coastguard Worker memset(&mOffloadInfoCopy, 0, sizeof(audio_offload_info_t));
600*ec779b8eSAndroid Build Coastguard Worker mOffloadInfoCopy = AUDIO_INFO_INITIALIZER;
601*ec779b8eSAndroid Build Coastguard Worker mOffloadInfoCopy.format = format;
602*ec779b8eSAndroid Build Coastguard Worker mOffloadInfoCopy.sample_rate = sampleRate;
603*ec779b8eSAndroid Build Coastguard Worker mOffloadInfoCopy.channel_mask = channelMask;
604*ec779b8eSAndroid Build Coastguard Worker mOffloadInfoCopy.stream_type = streamType;
605*ec779b8eSAndroid Build Coastguard Worker }
606*ec779b8eSAndroid Build Coastguard Worker
607*ec779b8eSAndroid Build Coastguard Worker mVolume[AUDIO_INTERLEAVE_LEFT] = 1.0f;
608*ec779b8eSAndroid Build Coastguard Worker mVolume[AUDIO_INTERLEAVE_RIGHT] = 1.0f;
609*ec779b8eSAndroid Build Coastguard Worker mSendLevel = 0.0f;
610*ec779b8eSAndroid Build Coastguard Worker // mFrameCount is initialized in createTrack_l
611*ec779b8eSAndroid Build Coastguard Worker if (notificationFrames >= 0) {
612*ec779b8eSAndroid Build Coastguard Worker mNotificationFramesReq = notificationFrames;
613*ec779b8eSAndroid Build Coastguard Worker mNotificationsPerBufferReq = 0;
614*ec779b8eSAndroid Build Coastguard Worker } else {
615*ec779b8eSAndroid Build Coastguard Worker if (!(mFlags & AUDIO_OUTPUT_FLAG_FAST)) {
616*ec779b8eSAndroid Build Coastguard Worker return logIfErrorAndReturnStatus(
617*ec779b8eSAndroid Build Coastguard Worker BAD_VALUE,
618*ec779b8eSAndroid Build Coastguard Worker StringPrintf("%s: notificationFrames=%d not permitted for non-fast track",
619*ec779b8eSAndroid Build Coastguard Worker __func__, notificationFrames));
620*ec779b8eSAndroid Build Coastguard Worker }
621*ec779b8eSAndroid Build Coastguard Worker if (frameCount > 0) {
622*ec779b8eSAndroid Build Coastguard Worker return logIfErrorAndReturnStatus(
623*ec779b8eSAndroid Build Coastguard Worker BAD_VALUE, StringPrintf("%s(): notificationFrames=%d not permitted "
624*ec779b8eSAndroid Build Coastguard Worker "with non-zero frameCount=%zu",
625*ec779b8eSAndroid Build Coastguard Worker __func__, notificationFrames, frameCount));
626*ec779b8eSAndroid Build Coastguard Worker }
627*ec779b8eSAndroid Build Coastguard Worker mNotificationFramesReq = 0;
628*ec779b8eSAndroid Build Coastguard Worker const uint32_t minNotificationsPerBuffer = 1;
629*ec779b8eSAndroid Build Coastguard Worker const uint32_t maxNotificationsPerBuffer = 8;
630*ec779b8eSAndroid Build Coastguard Worker mNotificationsPerBufferReq = min(maxNotificationsPerBuffer,
631*ec779b8eSAndroid Build Coastguard Worker max((uint32_t) -notificationFrames, minNotificationsPerBuffer));
632*ec779b8eSAndroid Build Coastguard Worker ALOGW_IF(mNotificationsPerBufferReq != (uint32_t) -notificationFrames,
633*ec779b8eSAndroid Build Coastguard Worker "%s(): notificationFrames=%d clamped to the range -%u to -%u",
634*ec779b8eSAndroid Build Coastguard Worker __func__,
635*ec779b8eSAndroid Build Coastguard Worker notificationFrames, minNotificationsPerBuffer, maxNotificationsPerBuffer);
636*ec779b8eSAndroid Build Coastguard Worker }
637*ec779b8eSAndroid Build Coastguard Worker mNotificationFramesAct = 0;
638*ec779b8eSAndroid Build Coastguard Worker // TODO b/182392553: refactor or remove
639*ec779b8eSAndroid Build Coastguard Worker mClientAttributionSource = AttributionSourceState(attributionSource);
640*ec779b8eSAndroid Build Coastguard Worker callingPid = IPCThreadState::self()->getCallingPid();
641*ec779b8eSAndroid Build Coastguard Worker myPid = getpid();
642*ec779b8eSAndroid Build Coastguard Worker if (uid.value() == -1 || (callingPid != myPid)) {
643*ec779b8eSAndroid Build Coastguard Worker auto clientAttributionSourceUid =
644*ec779b8eSAndroid Build Coastguard Worker legacy2aidl_uid_t_int32_t(IPCThreadState::self()->getCallingUid());
645*ec779b8eSAndroid Build Coastguard Worker if (!clientAttributionSourceUid.ok()) {
646*ec779b8eSAndroid Build Coastguard Worker return logIfErrorAndReturnStatus(
647*ec779b8eSAndroid Build Coastguard Worker BAD_VALUE,
648*ec779b8eSAndroid Build Coastguard Worker StringPrintf("%s: received invalid client attribution source uid", __func__));
649*ec779b8eSAndroid Build Coastguard Worker }
650*ec779b8eSAndroid Build Coastguard Worker mClientAttributionSource.uid = clientAttributionSourceUid.value();
651*ec779b8eSAndroid Build Coastguard Worker }
652*ec779b8eSAndroid Build Coastguard Worker if (pid.value() == (pid_t)-1 || (callingPid != myPid)) {
653*ec779b8eSAndroid Build Coastguard Worker auto clientAttributionSourcePid = legacy2aidl_uid_t_int32_t(callingPid);
654*ec779b8eSAndroid Build Coastguard Worker if (!clientAttributionSourcePid.ok()) {
655*ec779b8eSAndroid Build Coastguard Worker return logIfErrorAndReturnStatus(
656*ec779b8eSAndroid Build Coastguard Worker BAD_VALUE,
657*ec779b8eSAndroid Build Coastguard Worker StringPrintf("%s: received invalid client attribution source pid", __func__));
658*ec779b8eSAndroid Build Coastguard Worker }
659*ec779b8eSAndroid Build Coastguard Worker mClientAttributionSource.pid = clientAttributionSourcePid.value();
660*ec779b8eSAndroid Build Coastguard Worker }
661*ec779b8eSAndroid Build Coastguard Worker mAuxEffectId = 0;
662*ec779b8eSAndroid Build Coastguard Worker mCallback = callback;
663*ec779b8eSAndroid Build Coastguard Worker
664*ec779b8eSAndroid Build Coastguard Worker if (callback != nullptr) {
665*ec779b8eSAndroid Build Coastguard Worker mAudioTrackThread = sp<AudioTrackThread>::make(*this);
666*ec779b8eSAndroid Build Coastguard Worker mAudioTrackThread->run("AudioTrack", ANDROID_PRIORITY_AUDIO, 0 /*stack*/);
667*ec779b8eSAndroid Build Coastguard Worker // thread begins in paused state, and will not reference us until start()
668*ec779b8eSAndroid Build Coastguard Worker }
669*ec779b8eSAndroid Build Coastguard Worker
670*ec779b8eSAndroid Build Coastguard Worker // create the IAudioTrack
671*ec779b8eSAndroid Build Coastguard Worker {
672*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
673*ec779b8eSAndroid Build Coastguard Worker status = createTrack_l();
674*ec779b8eSAndroid Build Coastguard Worker }
675*ec779b8eSAndroid Build Coastguard Worker if (status != NO_ERROR) {
676*ec779b8eSAndroid Build Coastguard Worker if (mAudioTrackThread != 0) {
677*ec779b8eSAndroid Build Coastguard Worker mAudioTrackThread->requestExit(); // see comment in AudioTrack.h
678*ec779b8eSAndroid Build Coastguard Worker mAudioTrackThread->requestExitAndWait();
679*ec779b8eSAndroid Build Coastguard Worker mAudioTrackThread.clear();
680*ec779b8eSAndroid Build Coastguard Worker }
681*ec779b8eSAndroid Build Coastguard Worker // We do not goto error to prevent double-logging errors.
682*ec779b8eSAndroid Build Coastguard Worker mStatus = status;
683*ec779b8eSAndroid Build Coastguard Worker return mStatus;
684*ec779b8eSAndroid Build Coastguard Worker }
685*ec779b8eSAndroid Build Coastguard Worker
686*ec779b8eSAndroid Build Coastguard Worker mLoopCount = 0;
687*ec779b8eSAndroid Build Coastguard Worker mLoopStart = 0;
688*ec779b8eSAndroid Build Coastguard Worker mLoopEnd = 0;
689*ec779b8eSAndroid Build Coastguard Worker mLoopCountNotified = 0;
690*ec779b8eSAndroid Build Coastguard Worker mMarkerPosition = 0;
691*ec779b8eSAndroid Build Coastguard Worker mMarkerReached = false;
692*ec779b8eSAndroid Build Coastguard Worker mNewPosition = 0;
693*ec779b8eSAndroid Build Coastguard Worker mUpdatePeriod = 0;
694*ec779b8eSAndroid Build Coastguard Worker mPosition = 0;
695*ec779b8eSAndroid Build Coastguard Worker mReleased = 0;
696*ec779b8eSAndroid Build Coastguard Worker mStartNs = 0;
697*ec779b8eSAndroid Build Coastguard Worker mStartFromZeroUs = 0;
698*ec779b8eSAndroid Build Coastguard Worker AudioSystem::acquireAudioSessionId(mSessionId, pid.value(), uid.value());
699*ec779b8eSAndroid Build Coastguard Worker mSequence = 1;
700*ec779b8eSAndroid Build Coastguard Worker mObservedSequence = mSequence;
701*ec779b8eSAndroid Build Coastguard Worker mInUnderrun = false;
702*ec779b8eSAndroid Build Coastguard Worker mPreviousTimestampValid = false;
703*ec779b8eSAndroid Build Coastguard Worker mTimestampStartupGlitchReported = false;
704*ec779b8eSAndroid Build Coastguard Worker mTimestampRetrogradePositionReported = false;
705*ec779b8eSAndroid Build Coastguard Worker mTimestampRetrogradeTimeReported = false;
706*ec779b8eSAndroid Build Coastguard Worker mTimestampStallReported = false;
707*ec779b8eSAndroid Build Coastguard Worker mTimestampStaleTimeReported = false;
708*ec779b8eSAndroid Build Coastguard Worker mPreviousLocation = ExtendedTimestamp::LOCATION_INVALID;
709*ec779b8eSAndroid Build Coastguard Worker mStartTs.mPosition = 0;
710*ec779b8eSAndroid Build Coastguard Worker mUnderrunCountOffset = 0;
711*ec779b8eSAndroid Build Coastguard Worker mFramesWritten = 0;
712*ec779b8eSAndroid Build Coastguard Worker mFramesWrittenServerOffset = 0;
713*ec779b8eSAndroid Build Coastguard Worker mFramesWrittenAtRestore = -1; // -1 is a unique initializer.
714*ec779b8eSAndroid Build Coastguard Worker mVolumeHandler = new media::VolumeHandler();
715*ec779b8eSAndroid Build Coastguard Worker
716*ec779b8eSAndroid Build Coastguard Worker return logIfErrorAndReturnStatus(status, "");
717*ec779b8eSAndroid Build Coastguard Worker }
718*ec779b8eSAndroid Build Coastguard Worker
719*ec779b8eSAndroid Build Coastguard Worker
set(audio_stream_type_t streamType,uint32_t sampleRate,audio_format_t format,uint32_t channelMask,size_t frameCount,audio_output_flags_t flags,legacy_callback_t callback,void * user,int32_t notificationFrames,const sp<IMemory> & sharedBuffer,bool threadCanCallJava,audio_session_t sessionId,transfer_type transferType,const audio_offload_info_t * offloadInfo,uid_t uid,pid_t pid,const audio_attributes_t * pAttributes,bool doNotReconnect,float maxRequiredSpeed,audio_port_handle_t selectedDeviceId)720*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::set(
721*ec779b8eSAndroid Build Coastguard Worker audio_stream_type_t streamType,
722*ec779b8eSAndroid Build Coastguard Worker uint32_t sampleRate,
723*ec779b8eSAndroid Build Coastguard Worker audio_format_t format,
724*ec779b8eSAndroid Build Coastguard Worker uint32_t channelMask,
725*ec779b8eSAndroid Build Coastguard Worker size_t frameCount,
726*ec779b8eSAndroid Build Coastguard Worker audio_output_flags_t flags,
727*ec779b8eSAndroid Build Coastguard Worker legacy_callback_t callback,
728*ec779b8eSAndroid Build Coastguard Worker void* user,
729*ec779b8eSAndroid Build Coastguard Worker int32_t notificationFrames,
730*ec779b8eSAndroid Build Coastguard Worker const sp<IMemory>& sharedBuffer,
731*ec779b8eSAndroid Build Coastguard Worker bool threadCanCallJava,
732*ec779b8eSAndroid Build Coastguard Worker audio_session_t sessionId,
733*ec779b8eSAndroid Build Coastguard Worker transfer_type transferType,
734*ec779b8eSAndroid Build Coastguard Worker const audio_offload_info_t *offloadInfo,
735*ec779b8eSAndroid Build Coastguard Worker uid_t uid,
736*ec779b8eSAndroid Build Coastguard Worker pid_t pid,
737*ec779b8eSAndroid Build Coastguard Worker const audio_attributes_t* pAttributes,
738*ec779b8eSAndroid Build Coastguard Worker bool doNotReconnect,
739*ec779b8eSAndroid Build Coastguard Worker float maxRequiredSpeed,
740*ec779b8eSAndroid Build Coastguard Worker audio_port_handle_t selectedDeviceId)
741*ec779b8eSAndroid Build Coastguard Worker {
742*ec779b8eSAndroid Build Coastguard Worker AttributionSourceState attributionSource;
743*ec779b8eSAndroid Build Coastguard Worker auto attributionSourceUid = legacy2aidl_uid_t_int32_t(uid);
744*ec779b8eSAndroid Build Coastguard Worker if (!attributionSourceUid.ok()) {
745*ec779b8eSAndroid Build Coastguard Worker return logIfErrorAndReturnStatus(
746*ec779b8eSAndroid Build Coastguard Worker BAD_VALUE,
747*ec779b8eSAndroid Build Coastguard Worker StringPrintf("%s: received invalid attribution source uid, uid: %d, session id: %d",
748*ec779b8eSAndroid Build Coastguard Worker __func__, uid, sessionId));
749*ec779b8eSAndroid Build Coastguard Worker }
750*ec779b8eSAndroid Build Coastguard Worker attributionSource.uid = attributionSourceUid.value();
751*ec779b8eSAndroid Build Coastguard Worker auto attributionSourcePid = legacy2aidl_pid_t_int32_t(pid);
752*ec779b8eSAndroid Build Coastguard Worker if (!attributionSourcePid.ok()) {
753*ec779b8eSAndroid Build Coastguard Worker return logIfErrorAndReturnStatus(
754*ec779b8eSAndroid Build Coastguard Worker BAD_VALUE,
755*ec779b8eSAndroid Build Coastguard Worker StringPrintf("%s: received invalid attribution source pid, pid: %d, sessionId: %d",
756*ec779b8eSAndroid Build Coastguard Worker __func__, pid, sessionId));
757*ec779b8eSAndroid Build Coastguard Worker }
758*ec779b8eSAndroid Build Coastguard Worker attributionSource.pid = attributionSourcePid.value();
759*ec779b8eSAndroid Build Coastguard Worker attributionSource.token = sp<BBinder>::make();
760*ec779b8eSAndroid Build Coastguard Worker if (callback) {
761*ec779b8eSAndroid Build Coastguard Worker mLegacyCallbackWrapper = sp<LegacyCallbackWrapper>::make(callback, user);
762*ec779b8eSAndroid Build Coastguard Worker } else if (user) {
763*ec779b8eSAndroid Build Coastguard Worker LOG_ALWAYS_FATAL("Callback data provided without callback pointer!");
764*ec779b8eSAndroid Build Coastguard Worker }
765*ec779b8eSAndroid Build Coastguard Worker return set(streamType, sampleRate, format, static_cast<audio_channel_mask_t>(channelMask),
766*ec779b8eSAndroid Build Coastguard Worker frameCount, flags, mLegacyCallbackWrapper, notificationFrames, sharedBuffer,
767*ec779b8eSAndroid Build Coastguard Worker threadCanCallJava, sessionId, transferType, offloadInfo, attributionSource,
768*ec779b8eSAndroid Build Coastguard Worker pAttributes, doNotReconnect, maxRequiredSpeed, selectedDeviceId);
769*ec779b8eSAndroid Build Coastguard Worker }
770*ec779b8eSAndroid Build Coastguard Worker
771*ec779b8eSAndroid Build Coastguard Worker // -------------------------------------------------------------------------
772*ec779b8eSAndroid Build Coastguard Worker
start()773*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::start()
774*ec779b8eSAndroid Build Coastguard Worker {
775*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
776*ec779b8eSAndroid Build Coastguard Worker
777*ec779b8eSAndroid Build Coastguard Worker if (mState == STATE_ACTIVE) {
778*ec779b8eSAndroid Build Coastguard Worker return INVALID_OPERATION;
779*ec779b8eSAndroid Build Coastguard Worker }
780*ec779b8eSAndroid Build Coastguard Worker
781*ec779b8eSAndroid Build Coastguard Worker ALOGV("%s(%d): prior state:%s", __func__, mPortId, stateToString(mState));
782*ec779b8eSAndroid Build Coastguard Worker
783*ec779b8eSAndroid Build Coastguard Worker // Defer logging here due to OpenSL ES repeated start calls.
784*ec779b8eSAndroid Build Coastguard Worker // TODO(b/154868033) after fix, restore this logging back to the beginning of start().
785*ec779b8eSAndroid Build Coastguard Worker const int64_t beginNs = systemTime();
786*ec779b8eSAndroid Build Coastguard Worker status_t status = NO_ERROR; // logged: make sure to set this before returning.
787*ec779b8eSAndroid Build Coastguard Worker mediametrics::Defer defer([&] {
788*ec779b8eSAndroid Build Coastguard Worker mediametrics::LogItem(mMetricsId)
789*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_CALLERNAME,
790*ec779b8eSAndroid Build Coastguard Worker mCallerName.empty()
791*ec779b8eSAndroid Build Coastguard Worker ? AMEDIAMETRICS_PROP_CALLERNAME_VALUE_UNKNOWN
792*ec779b8eSAndroid Build Coastguard Worker : mCallerName.c_str())
793*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_START)
794*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(systemTime() - beginNs))
795*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
796*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)status)
797*ec779b8eSAndroid Build Coastguard Worker .record(); });
798*ec779b8eSAndroid Build Coastguard Worker
799*ec779b8eSAndroid Build Coastguard Worker
800*ec779b8eSAndroid Build Coastguard Worker mInUnderrun = true;
801*ec779b8eSAndroid Build Coastguard Worker
802*ec779b8eSAndroid Build Coastguard Worker State previousState = mState;
803*ec779b8eSAndroid Build Coastguard Worker if (previousState == STATE_PAUSED_STOPPING) {
804*ec779b8eSAndroid Build Coastguard Worker mState = STATE_STOPPING;
805*ec779b8eSAndroid Build Coastguard Worker } else {
806*ec779b8eSAndroid Build Coastguard Worker mState = STATE_ACTIVE;
807*ec779b8eSAndroid Build Coastguard Worker }
808*ec779b8eSAndroid Build Coastguard Worker (void) updateAndGetPosition_l();
809*ec779b8eSAndroid Build Coastguard Worker
810*ec779b8eSAndroid Build Coastguard Worker // save start timestamp
811*ec779b8eSAndroid Build Coastguard Worker if (isAfTrackOffloadedOrDirect_l()) {
812*ec779b8eSAndroid Build Coastguard Worker if (getTimestamp_l(mStartTs) != OK) {
813*ec779b8eSAndroid Build Coastguard Worker mStartTs.mPosition = 0;
814*ec779b8eSAndroid Build Coastguard Worker }
815*ec779b8eSAndroid Build Coastguard Worker } else {
816*ec779b8eSAndroid Build Coastguard Worker if (getTimestamp_l(&mStartEts) != OK) {
817*ec779b8eSAndroid Build Coastguard Worker mStartEts.clear();
818*ec779b8eSAndroid Build Coastguard Worker }
819*ec779b8eSAndroid Build Coastguard Worker }
820*ec779b8eSAndroid Build Coastguard Worker mStartNs = systemTime(); // save this for timestamp adjustment after starting.
821*ec779b8eSAndroid Build Coastguard Worker if (previousState == STATE_STOPPED || previousState == STATE_FLUSHED) {
822*ec779b8eSAndroid Build Coastguard Worker // reset current position as seen by client to 0
823*ec779b8eSAndroid Build Coastguard Worker mPosition = 0;
824*ec779b8eSAndroid Build Coastguard Worker mPreviousTimestampValid = false;
825*ec779b8eSAndroid Build Coastguard Worker mTimestampStartupGlitchReported = false;
826*ec779b8eSAndroid Build Coastguard Worker mTimestampRetrogradePositionReported = false;
827*ec779b8eSAndroid Build Coastguard Worker mTimestampRetrogradeTimeReported = false;
828*ec779b8eSAndroid Build Coastguard Worker mTimestampStallReported = false;
829*ec779b8eSAndroid Build Coastguard Worker mTimestampStaleTimeReported = false;
830*ec779b8eSAndroid Build Coastguard Worker mPreviousLocation = ExtendedTimestamp::LOCATION_INVALID;
831*ec779b8eSAndroid Build Coastguard Worker
832*ec779b8eSAndroid Build Coastguard Worker if (!isAfTrackOffloadedOrDirect_l()
833*ec779b8eSAndroid Build Coastguard Worker && mStartEts.mTimeNs[ExtendedTimestamp::LOCATION_SERVER] > 0) {
834*ec779b8eSAndroid Build Coastguard Worker // Server side has consumed something, but is it finished consuming?
835*ec779b8eSAndroid Build Coastguard Worker // It is possible since flush and stop are asynchronous that the server
836*ec779b8eSAndroid Build Coastguard Worker // is still active at this point.
837*ec779b8eSAndroid Build Coastguard Worker ALOGV("%s(%d): server read:%lld cumulative flushed:%lld client written:%lld",
838*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId,
839*ec779b8eSAndroid Build Coastguard Worker (long long)(mFramesWrittenServerOffset
840*ec779b8eSAndroid Build Coastguard Worker + mStartEts.mPosition[ExtendedTimestamp::LOCATION_SERVER]),
841*ec779b8eSAndroid Build Coastguard Worker (long long)mStartEts.mFlushed,
842*ec779b8eSAndroid Build Coastguard Worker (long long)mFramesWritten);
843*ec779b8eSAndroid Build Coastguard Worker // mStartEts is already adjusted by mFramesWrittenServerOffset, so we delta adjust.
844*ec779b8eSAndroid Build Coastguard Worker mFramesWrittenServerOffset -= mStartEts.mPosition[ExtendedTimestamp::LOCATION_SERVER];
845*ec779b8eSAndroid Build Coastguard Worker }
846*ec779b8eSAndroid Build Coastguard Worker mFramesWritten = 0;
847*ec779b8eSAndroid Build Coastguard Worker mProxy->clearTimestamp(); // need new server push for valid timestamp
848*ec779b8eSAndroid Build Coastguard Worker mMarkerReached = false;
849*ec779b8eSAndroid Build Coastguard Worker
850*ec779b8eSAndroid Build Coastguard Worker // For offloaded tracks, we don't know if the hardware counters are really zero here,
851*ec779b8eSAndroid Build Coastguard Worker // since the flush is asynchronous and stop may not fully drain.
852*ec779b8eSAndroid Build Coastguard Worker // We save the time when the track is started to later verify whether
853*ec779b8eSAndroid Build Coastguard Worker // the counters are realistic (i.e. start from zero after this time).
854*ec779b8eSAndroid Build Coastguard Worker mStartFromZeroUs = mStartNs / 1000;
855*ec779b8eSAndroid Build Coastguard Worker
856*ec779b8eSAndroid Build Coastguard Worker // force refresh of remaining frames by processAudioBuffer() as last
857*ec779b8eSAndroid Build Coastguard Worker // write before stop could be partial.
858*ec779b8eSAndroid Build Coastguard Worker mRefreshRemaining = true;
859*ec779b8eSAndroid Build Coastguard Worker
860*ec779b8eSAndroid Build Coastguard Worker // for static track, clear the old flags when starting from stopped state
861*ec779b8eSAndroid Build Coastguard Worker if (mSharedBuffer != 0) {
862*ec779b8eSAndroid Build Coastguard Worker android_atomic_and(
863*ec779b8eSAndroid Build Coastguard Worker ~(CBLK_LOOP_CYCLE | CBLK_LOOP_FINAL | CBLK_BUFFER_END),
864*ec779b8eSAndroid Build Coastguard Worker &mCblk->mFlags);
865*ec779b8eSAndroid Build Coastguard Worker }
866*ec779b8eSAndroid Build Coastguard Worker }
867*ec779b8eSAndroid Build Coastguard Worker mNewPosition = mPosition + mUpdatePeriod;
868*ec779b8eSAndroid Build Coastguard Worker int32_t flags = android_atomic_and(~(CBLK_STREAM_END_DONE | CBLK_DISABLED), &mCblk->mFlags);
869*ec779b8eSAndroid Build Coastguard Worker
870*ec779b8eSAndroid Build Coastguard Worker if (!(flags & CBLK_INVALID)) {
871*ec779b8eSAndroid Build Coastguard Worker mAudioTrack->start(&status);
872*ec779b8eSAndroid Build Coastguard Worker if (status == DEAD_OBJECT) {
873*ec779b8eSAndroid Build Coastguard Worker flags |= CBLK_INVALID;
874*ec779b8eSAndroid Build Coastguard Worker }
875*ec779b8eSAndroid Build Coastguard Worker }
876*ec779b8eSAndroid Build Coastguard Worker if (flags & CBLK_INVALID) {
877*ec779b8eSAndroid Build Coastguard Worker status = restoreTrack_l("start");
878*ec779b8eSAndroid Build Coastguard Worker }
879*ec779b8eSAndroid Build Coastguard Worker
880*ec779b8eSAndroid Build Coastguard Worker // resume or pause the callback thread as needed.
881*ec779b8eSAndroid Build Coastguard Worker sp<AudioTrackThread> t = mAudioTrackThread;
882*ec779b8eSAndroid Build Coastguard Worker if (status == NO_ERROR) {
883*ec779b8eSAndroid Build Coastguard Worker if (t != 0) {
884*ec779b8eSAndroid Build Coastguard Worker if (previousState == STATE_STOPPING) {
885*ec779b8eSAndroid Build Coastguard Worker mProxy->interrupt();
886*ec779b8eSAndroid Build Coastguard Worker } else {
887*ec779b8eSAndroid Build Coastguard Worker t->resume();
888*ec779b8eSAndroid Build Coastguard Worker }
889*ec779b8eSAndroid Build Coastguard Worker } else {
890*ec779b8eSAndroid Build Coastguard Worker mPreviousPriority = getpriority(PRIO_PROCESS, 0);
891*ec779b8eSAndroid Build Coastguard Worker get_sched_policy(0, &mPreviousSchedulingGroup);
892*ec779b8eSAndroid Build Coastguard Worker androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
893*ec779b8eSAndroid Build Coastguard Worker }
894*ec779b8eSAndroid Build Coastguard Worker
895*ec779b8eSAndroid Build Coastguard Worker // Start our local VolumeHandler for restoration purposes.
896*ec779b8eSAndroid Build Coastguard Worker mVolumeHandler->setStarted();
897*ec779b8eSAndroid Build Coastguard Worker } else {
898*ec779b8eSAndroid Build Coastguard Worker ALOGE("%s(%d): status %d", __func__, mPortId, status);
899*ec779b8eSAndroid Build Coastguard Worker mState = previousState;
900*ec779b8eSAndroid Build Coastguard Worker if (t != 0) {
901*ec779b8eSAndroid Build Coastguard Worker if (previousState != STATE_STOPPING) {
902*ec779b8eSAndroid Build Coastguard Worker t->pause();
903*ec779b8eSAndroid Build Coastguard Worker }
904*ec779b8eSAndroid Build Coastguard Worker } else {
905*ec779b8eSAndroid Build Coastguard Worker setpriority(PRIO_PROCESS, 0, mPreviousPriority);
906*ec779b8eSAndroid Build Coastguard Worker set_sched_policy(0, mPreviousSchedulingGroup);
907*ec779b8eSAndroid Build Coastguard Worker }
908*ec779b8eSAndroid Build Coastguard Worker }
909*ec779b8eSAndroid Build Coastguard Worker
910*ec779b8eSAndroid Build Coastguard Worker return status;
911*ec779b8eSAndroid Build Coastguard Worker }
912*ec779b8eSAndroid Build Coastguard Worker
stop()913*ec779b8eSAndroid Build Coastguard Worker void AudioTrack::stop()
914*ec779b8eSAndroid Build Coastguard Worker {
915*ec779b8eSAndroid Build Coastguard Worker const int64_t beginNs = systemTime();
916*ec779b8eSAndroid Build Coastguard Worker
917*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
918*ec779b8eSAndroid Build Coastguard Worker if (mProxy == nullptr) return; // not successfully initialized.
919*ec779b8eSAndroid Build Coastguard Worker mediametrics::Defer defer([&]() {
920*ec779b8eSAndroid Build Coastguard Worker mediametrics::LogItem(mMetricsId)
921*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_STOP)
922*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(systemTime() - beginNs))
923*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
924*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_BUFFERSIZEFRAMES, (int32_t)mProxy->getBufferSizeInFrames())
925*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_UNDERRUN, (int32_t) getUnderrunCount_l())
926*ec779b8eSAndroid Build Coastguard Worker .record();
927*ec779b8eSAndroid Build Coastguard Worker });
928*ec779b8eSAndroid Build Coastguard Worker
929*ec779b8eSAndroid Build Coastguard Worker ALOGV("%s(%d): prior state:%s", __func__, mPortId, stateToString(mState));
930*ec779b8eSAndroid Build Coastguard Worker
931*ec779b8eSAndroid Build Coastguard Worker if (mState != STATE_ACTIVE && mState != STATE_PAUSED) {
932*ec779b8eSAndroid Build Coastguard Worker return;
933*ec779b8eSAndroid Build Coastguard Worker }
934*ec779b8eSAndroid Build Coastguard Worker
935*ec779b8eSAndroid Build Coastguard Worker if (isOffloaded_l()) {
936*ec779b8eSAndroid Build Coastguard Worker mState = STATE_STOPPING;
937*ec779b8eSAndroid Build Coastguard Worker } else {
938*ec779b8eSAndroid Build Coastguard Worker mState = STATE_STOPPED;
939*ec779b8eSAndroid Build Coastguard Worker ALOGD_IF(mSharedBuffer == nullptr,
940*ec779b8eSAndroid Build Coastguard Worker "%s(%d): called with %u frames delivered", __func__, mPortId, mReleased.value());
941*ec779b8eSAndroid Build Coastguard Worker mReleased = 0;
942*ec779b8eSAndroid Build Coastguard Worker }
943*ec779b8eSAndroid Build Coastguard Worker
944*ec779b8eSAndroid Build Coastguard Worker mProxy->stop(); // notify server not to read beyond current client position until start().
945*ec779b8eSAndroid Build Coastguard Worker mProxy->interrupt();
946*ec779b8eSAndroid Build Coastguard Worker mAudioTrack->stop();
947*ec779b8eSAndroid Build Coastguard Worker
948*ec779b8eSAndroid Build Coastguard Worker // Note: legacy handling - stop does not clear playback marker
949*ec779b8eSAndroid Build Coastguard Worker // and periodic update counter, but flush does for streaming tracks.
950*ec779b8eSAndroid Build Coastguard Worker
951*ec779b8eSAndroid Build Coastguard Worker if (mSharedBuffer != 0) {
952*ec779b8eSAndroid Build Coastguard Worker // clear buffer position and loop count.
953*ec779b8eSAndroid Build Coastguard Worker mStaticProxy->setBufferPositionAndLoop(0 /* position */,
954*ec779b8eSAndroid Build Coastguard Worker 0 /* loopStart */, 0 /* loopEnd */, 0 /* loopCount */);
955*ec779b8eSAndroid Build Coastguard Worker }
956*ec779b8eSAndroid Build Coastguard Worker
957*ec779b8eSAndroid Build Coastguard Worker sp<AudioTrackThread> t = mAudioTrackThread;
958*ec779b8eSAndroid Build Coastguard Worker if (t != 0) {
959*ec779b8eSAndroid Build Coastguard Worker if (!isOffloaded_l()) {
960*ec779b8eSAndroid Build Coastguard Worker t->pause();
961*ec779b8eSAndroid Build Coastguard Worker } else if (mTransfer == TRANSFER_SYNC_NOTIF_CALLBACK) {
962*ec779b8eSAndroid Build Coastguard Worker // causes wake up of the playback thread, that will callback the client for
963*ec779b8eSAndroid Build Coastguard Worker // EVENT_STREAM_END in processAudioBuffer()
964*ec779b8eSAndroid Build Coastguard Worker t->wake();
965*ec779b8eSAndroid Build Coastguard Worker }
966*ec779b8eSAndroid Build Coastguard Worker } else {
967*ec779b8eSAndroid Build Coastguard Worker setpriority(PRIO_PROCESS, 0, mPreviousPriority);
968*ec779b8eSAndroid Build Coastguard Worker set_sched_policy(0, mPreviousSchedulingGroup);
969*ec779b8eSAndroid Build Coastguard Worker }
970*ec779b8eSAndroid Build Coastguard Worker }
971*ec779b8eSAndroid Build Coastguard Worker
stopped() const972*ec779b8eSAndroid Build Coastguard Worker bool AudioTrack::stopped() const
973*ec779b8eSAndroid Build Coastguard Worker {
974*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
975*ec779b8eSAndroid Build Coastguard Worker return mState != STATE_ACTIVE;
976*ec779b8eSAndroid Build Coastguard Worker }
977*ec779b8eSAndroid Build Coastguard Worker
flush()978*ec779b8eSAndroid Build Coastguard Worker void AudioTrack::flush()
979*ec779b8eSAndroid Build Coastguard Worker {
980*ec779b8eSAndroid Build Coastguard Worker const int64_t beginNs = systemTime();
981*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
982*ec779b8eSAndroid Build Coastguard Worker mediametrics::Defer defer([&]() {
983*ec779b8eSAndroid Build Coastguard Worker mediametrics::LogItem(mMetricsId)
984*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_FLUSH)
985*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(systemTime() - beginNs))
986*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
987*ec779b8eSAndroid Build Coastguard Worker .record(); });
988*ec779b8eSAndroid Build Coastguard Worker
989*ec779b8eSAndroid Build Coastguard Worker ALOGV("%s(%d): prior state:%s", __func__, mPortId, stateToString(mState));
990*ec779b8eSAndroid Build Coastguard Worker
991*ec779b8eSAndroid Build Coastguard Worker if (mSharedBuffer != 0) {
992*ec779b8eSAndroid Build Coastguard Worker return;
993*ec779b8eSAndroid Build Coastguard Worker }
994*ec779b8eSAndroid Build Coastguard Worker if (mState == STATE_ACTIVE) {
995*ec779b8eSAndroid Build Coastguard Worker return;
996*ec779b8eSAndroid Build Coastguard Worker }
997*ec779b8eSAndroid Build Coastguard Worker flush_l();
998*ec779b8eSAndroid Build Coastguard Worker }
999*ec779b8eSAndroid Build Coastguard Worker
flush_l()1000*ec779b8eSAndroid Build Coastguard Worker void AudioTrack::flush_l()
1001*ec779b8eSAndroid Build Coastguard Worker {
1002*ec779b8eSAndroid Build Coastguard Worker ALOG_ASSERT(mState != STATE_ACTIVE);
1003*ec779b8eSAndroid Build Coastguard Worker
1004*ec779b8eSAndroid Build Coastguard Worker // clear playback marker and periodic update counter
1005*ec779b8eSAndroid Build Coastguard Worker mMarkerPosition = 0;
1006*ec779b8eSAndroid Build Coastguard Worker mMarkerReached = false;
1007*ec779b8eSAndroid Build Coastguard Worker mUpdatePeriod = 0;
1008*ec779b8eSAndroid Build Coastguard Worker mRefreshRemaining = true;
1009*ec779b8eSAndroid Build Coastguard Worker
1010*ec779b8eSAndroid Build Coastguard Worker mState = STATE_FLUSHED;
1011*ec779b8eSAndroid Build Coastguard Worker mReleased = 0;
1012*ec779b8eSAndroid Build Coastguard Worker if (isOffloaded_l()) {
1013*ec779b8eSAndroid Build Coastguard Worker mProxy->interrupt();
1014*ec779b8eSAndroid Build Coastguard Worker }
1015*ec779b8eSAndroid Build Coastguard Worker mProxy->flush();
1016*ec779b8eSAndroid Build Coastguard Worker mAudioTrack->flush();
1017*ec779b8eSAndroid Build Coastguard Worker }
1018*ec779b8eSAndroid Build Coastguard Worker
pauseAndWait(const std::chrono::milliseconds & timeout)1019*ec779b8eSAndroid Build Coastguard Worker bool AudioTrack::pauseAndWait(const std::chrono::milliseconds& timeout)
1020*ec779b8eSAndroid Build Coastguard Worker {
1021*ec779b8eSAndroid Build Coastguard Worker using namespace std::chrono_literals;
1022*ec779b8eSAndroid Build Coastguard Worker
1023*ec779b8eSAndroid Build Coastguard Worker // We use atomic access here for state variables - these are used as hints
1024*ec779b8eSAndroid Build Coastguard Worker // to ensure we have ramped down audio.
1025*ec779b8eSAndroid Build Coastguard Worker const int priorState = mProxy->getState();
1026*ec779b8eSAndroid Build Coastguard Worker const uint32_t priorPosition = mProxy->getPosition().unsignedValue();
1027*ec779b8eSAndroid Build Coastguard Worker
1028*ec779b8eSAndroid Build Coastguard Worker pause();
1029*ec779b8eSAndroid Build Coastguard Worker
1030*ec779b8eSAndroid Build Coastguard Worker // Only if we were previously active, do we wait to ramp down the audio.
1031*ec779b8eSAndroid Build Coastguard Worker if (priorState != CBLK_STATE_ACTIVE) return true;
1032*ec779b8eSAndroid Build Coastguard Worker
1033*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
1034*ec779b8eSAndroid Build Coastguard Worker // offload and direct tracks do not wait because pause volume ramp is handled by hardware.
1035*ec779b8eSAndroid Build Coastguard Worker if (isOffloadedOrDirect_l()) return true;
1036*ec779b8eSAndroid Build Coastguard Worker
1037*ec779b8eSAndroid Build Coastguard Worker // Wait for the track state to be anything besides pausing.
1038*ec779b8eSAndroid Build Coastguard Worker // This ensures that the volume has ramped down.
1039*ec779b8eSAndroid Build Coastguard Worker constexpr auto SLEEP_INTERVAL_MS = 10ms;
1040*ec779b8eSAndroid Build Coastguard Worker constexpr auto POSITION_TIMEOUT_MS = 40ms; // don't wait longer than this for position change.
1041*ec779b8eSAndroid Build Coastguard Worker auto begin = std::chrono::steady_clock::now();
1042*ec779b8eSAndroid Build Coastguard Worker while (true) {
1043*ec779b8eSAndroid Build Coastguard Worker // Wait for state and position to change.
1044*ec779b8eSAndroid Build Coastguard Worker // After pause() the server state should be PAUSING, but that may immediately
1045*ec779b8eSAndroid Build Coastguard Worker // convert to PAUSED by prepareTracks before data is read into the mixer.
1046*ec779b8eSAndroid Build Coastguard Worker // Hence we check that the state is not PAUSING and that the server position
1047*ec779b8eSAndroid Build Coastguard Worker // has advanced to be a more reliable estimate that the volume ramp has completed.
1048*ec779b8eSAndroid Build Coastguard Worker const int state = mProxy->getState();
1049*ec779b8eSAndroid Build Coastguard Worker const uint32_t position = mProxy->getPosition().unsignedValue();
1050*ec779b8eSAndroid Build Coastguard Worker
1051*ec779b8eSAndroid Build Coastguard Worker mLock.unlock(); // only local variables accessed until lock.
1052*ec779b8eSAndroid Build Coastguard Worker auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
1053*ec779b8eSAndroid Build Coastguard Worker std::chrono::steady_clock::now() - begin);
1054*ec779b8eSAndroid Build Coastguard Worker if (state != CBLK_STATE_PAUSING &&
1055*ec779b8eSAndroid Build Coastguard Worker (elapsed >= POSITION_TIMEOUT_MS || position != priorPosition)) {
1056*ec779b8eSAndroid Build Coastguard Worker ALOGV("%s: success state:%d, position:%u after %lld ms"
1057*ec779b8eSAndroid Build Coastguard Worker " (prior state:%d prior position:%u)",
1058*ec779b8eSAndroid Build Coastguard Worker __func__, state, position, elapsed.count(), priorState, priorPosition);
1059*ec779b8eSAndroid Build Coastguard Worker return true;
1060*ec779b8eSAndroid Build Coastguard Worker }
1061*ec779b8eSAndroid Build Coastguard Worker std::chrono::milliseconds remaining = timeout - elapsed;
1062*ec779b8eSAndroid Build Coastguard Worker if (remaining.count() <= 0) {
1063*ec779b8eSAndroid Build Coastguard Worker ALOGW("%s: timeout expired state:%d still pausing:%d after %lld ms",
1064*ec779b8eSAndroid Build Coastguard Worker __func__, state, CBLK_STATE_PAUSING, elapsed.count());
1065*ec779b8eSAndroid Build Coastguard Worker return false;
1066*ec779b8eSAndroid Build Coastguard Worker }
1067*ec779b8eSAndroid Build Coastguard Worker // It is conceivable that the track is restored while sleeping;
1068*ec779b8eSAndroid Build Coastguard Worker // as this logic is advisory, we allow that.
1069*ec779b8eSAndroid Build Coastguard Worker std::this_thread::sleep_for(std::min(remaining, SLEEP_INTERVAL_MS));
1070*ec779b8eSAndroid Build Coastguard Worker mLock.lock();
1071*ec779b8eSAndroid Build Coastguard Worker }
1072*ec779b8eSAndroid Build Coastguard Worker }
1073*ec779b8eSAndroid Build Coastguard Worker
pause()1074*ec779b8eSAndroid Build Coastguard Worker void AudioTrack::pause()
1075*ec779b8eSAndroid Build Coastguard Worker {
1076*ec779b8eSAndroid Build Coastguard Worker const int64_t beginNs = systemTime();
1077*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
1078*ec779b8eSAndroid Build Coastguard Worker mediametrics::Defer defer([&]() {
1079*ec779b8eSAndroid Build Coastguard Worker mediametrics::LogItem(mMetricsId)
1080*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_PAUSE)
1081*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(systemTime() - beginNs))
1082*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
1083*ec779b8eSAndroid Build Coastguard Worker .record(); });
1084*ec779b8eSAndroid Build Coastguard Worker
1085*ec779b8eSAndroid Build Coastguard Worker ALOGV("%s(%d): prior state:%s", __func__, mPortId, stateToString(mState));
1086*ec779b8eSAndroid Build Coastguard Worker
1087*ec779b8eSAndroid Build Coastguard Worker if (mState == STATE_ACTIVE) {
1088*ec779b8eSAndroid Build Coastguard Worker mState = STATE_PAUSED;
1089*ec779b8eSAndroid Build Coastguard Worker } else if (mState == STATE_STOPPING) {
1090*ec779b8eSAndroid Build Coastguard Worker mState = STATE_PAUSED_STOPPING;
1091*ec779b8eSAndroid Build Coastguard Worker } else {
1092*ec779b8eSAndroid Build Coastguard Worker return;
1093*ec779b8eSAndroid Build Coastguard Worker }
1094*ec779b8eSAndroid Build Coastguard Worker mProxy->interrupt();
1095*ec779b8eSAndroid Build Coastguard Worker mAudioTrack->pause();
1096*ec779b8eSAndroid Build Coastguard Worker
1097*ec779b8eSAndroid Build Coastguard Worker if (isOffloaded_l()) {
1098*ec779b8eSAndroid Build Coastguard Worker if (mOutput != AUDIO_IO_HANDLE_NONE) {
1099*ec779b8eSAndroid Build Coastguard Worker // An offload output can be re-used between two audio tracks having
1100*ec779b8eSAndroid Build Coastguard Worker // the same configuration. A timestamp query for a paused track
1101*ec779b8eSAndroid Build Coastguard Worker // while the other is running would return an incorrect time.
1102*ec779b8eSAndroid Build Coastguard Worker // To fix this, cache the playback position on a pause() and return
1103*ec779b8eSAndroid Build Coastguard Worker // this time when requested until the track is resumed.
1104*ec779b8eSAndroid Build Coastguard Worker
1105*ec779b8eSAndroid Build Coastguard Worker // OffloadThread sends HAL pause in its threadLoop. Time saved
1106*ec779b8eSAndroid Build Coastguard Worker // here can be slightly off.
1107*ec779b8eSAndroid Build Coastguard Worker
1108*ec779b8eSAndroid Build Coastguard Worker // TODO: check return code for getRenderPosition.
1109*ec779b8eSAndroid Build Coastguard Worker
1110*ec779b8eSAndroid Build Coastguard Worker uint32_t halFrames;
1111*ec779b8eSAndroid Build Coastguard Worker AudioSystem::getRenderPosition(mOutput, &halFrames, &mPausedPosition);
1112*ec779b8eSAndroid Build Coastguard Worker ALOGV("%s(%d): for offload, cache current position %u",
1113*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId, mPausedPosition);
1114*ec779b8eSAndroid Build Coastguard Worker }
1115*ec779b8eSAndroid Build Coastguard Worker }
1116*ec779b8eSAndroid Build Coastguard Worker }
1117*ec779b8eSAndroid Build Coastguard Worker
setVolume(float left,float right)1118*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::setVolume(float left, float right)
1119*ec779b8eSAndroid Build Coastguard Worker {
1120*ec779b8eSAndroid Build Coastguard Worker // This duplicates a test by AudioTrack JNI, but that is not the only caller
1121*ec779b8eSAndroid Build Coastguard Worker if (isnanf(left) || left < GAIN_FLOAT_ZERO || left > GAIN_FLOAT_UNITY ||
1122*ec779b8eSAndroid Build Coastguard Worker isnanf(right) || right < GAIN_FLOAT_ZERO || right > GAIN_FLOAT_UNITY) {
1123*ec779b8eSAndroid Build Coastguard Worker return BAD_VALUE;
1124*ec779b8eSAndroid Build Coastguard Worker }
1125*ec779b8eSAndroid Build Coastguard Worker
1126*ec779b8eSAndroid Build Coastguard Worker mediametrics::LogItem(mMetricsId)
1127*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOLUME)
1128*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_VOLUME_LEFT, (double)left)
1129*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_VOLUME_RIGHT, (double)right)
1130*ec779b8eSAndroid Build Coastguard Worker .record();
1131*ec779b8eSAndroid Build Coastguard Worker
1132*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
1133*ec779b8eSAndroid Build Coastguard Worker mVolume[AUDIO_INTERLEAVE_LEFT] = left;
1134*ec779b8eSAndroid Build Coastguard Worker mVolume[AUDIO_INTERLEAVE_RIGHT] = right;
1135*ec779b8eSAndroid Build Coastguard Worker
1136*ec779b8eSAndroid Build Coastguard Worker mProxy->setVolumeLR(gain_minifloat_pack(gain_from_float(left), gain_from_float(right)));
1137*ec779b8eSAndroid Build Coastguard Worker
1138*ec779b8eSAndroid Build Coastguard Worker if (isOffloaded_l()) {
1139*ec779b8eSAndroid Build Coastguard Worker mAudioTrack->signal();
1140*ec779b8eSAndroid Build Coastguard Worker }
1141*ec779b8eSAndroid Build Coastguard Worker return NO_ERROR;
1142*ec779b8eSAndroid Build Coastguard Worker }
1143*ec779b8eSAndroid Build Coastguard Worker
setVolume(float volume)1144*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::setVolume(float volume)
1145*ec779b8eSAndroid Build Coastguard Worker {
1146*ec779b8eSAndroid Build Coastguard Worker return setVolume(volume, volume);
1147*ec779b8eSAndroid Build Coastguard Worker }
1148*ec779b8eSAndroid Build Coastguard Worker
setAuxEffectSendLevel(float level)1149*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::setAuxEffectSendLevel(float level)
1150*ec779b8eSAndroid Build Coastguard Worker {
1151*ec779b8eSAndroid Build Coastguard Worker // This duplicates a test by AudioTrack JNI, but that is not the only caller
1152*ec779b8eSAndroid Build Coastguard Worker if (isnanf(level) || level < GAIN_FLOAT_ZERO || level > GAIN_FLOAT_UNITY) {
1153*ec779b8eSAndroid Build Coastguard Worker return BAD_VALUE;
1154*ec779b8eSAndroid Build Coastguard Worker }
1155*ec779b8eSAndroid Build Coastguard Worker
1156*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
1157*ec779b8eSAndroid Build Coastguard Worker mSendLevel = level;
1158*ec779b8eSAndroid Build Coastguard Worker mProxy->setSendLevel(level);
1159*ec779b8eSAndroid Build Coastguard Worker
1160*ec779b8eSAndroid Build Coastguard Worker return NO_ERROR;
1161*ec779b8eSAndroid Build Coastguard Worker }
1162*ec779b8eSAndroid Build Coastguard Worker
getAuxEffectSendLevel(float * level) const1163*ec779b8eSAndroid Build Coastguard Worker void AudioTrack::getAuxEffectSendLevel(float* level) const
1164*ec779b8eSAndroid Build Coastguard Worker {
1165*ec779b8eSAndroid Build Coastguard Worker if (level != NULL) {
1166*ec779b8eSAndroid Build Coastguard Worker *level = mSendLevel;
1167*ec779b8eSAndroid Build Coastguard Worker }
1168*ec779b8eSAndroid Build Coastguard Worker }
1169*ec779b8eSAndroid Build Coastguard Worker
setSampleRate(uint32_t rate)1170*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::setSampleRate(uint32_t rate)
1171*ec779b8eSAndroid Build Coastguard Worker {
1172*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
1173*ec779b8eSAndroid Build Coastguard Worker ALOGV("%s(%d): prior state:%s rate:%u", __func__, mPortId, stateToString(mState), rate);
1174*ec779b8eSAndroid Build Coastguard Worker
1175*ec779b8eSAndroid Build Coastguard Worker if (rate == mSampleRate) {
1176*ec779b8eSAndroid Build Coastguard Worker return NO_ERROR;
1177*ec779b8eSAndroid Build Coastguard Worker }
1178*ec779b8eSAndroid Build Coastguard Worker if (isOffloadedOrDirect_l() || (mFlags & AUDIO_OUTPUT_FLAG_FAST)
1179*ec779b8eSAndroid Build Coastguard Worker || (mChannelMask & AUDIO_CHANNEL_HAPTIC_ALL)) {
1180*ec779b8eSAndroid Build Coastguard Worker return INVALID_OPERATION;
1181*ec779b8eSAndroid Build Coastguard Worker }
1182*ec779b8eSAndroid Build Coastguard Worker if (mOutput == AUDIO_IO_HANDLE_NONE) {
1183*ec779b8eSAndroid Build Coastguard Worker return NO_INIT;
1184*ec779b8eSAndroid Build Coastguard Worker }
1185*ec779b8eSAndroid Build Coastguard Worker // NOTE: it is theoretically possible, but highly unlikely, that a device change
1186*ec779b8eSAndroid Build Coastguard Worker // could mean a previously allowed sampling rate is no longer allowed.
1187*ec779b8eSAndroid Build Coastguard Worker uint32_t afSamplingRate;
1188*ec779b8eSAndroid Build Coastguard Worker if (AudioSystem::getSamplingRate(mOutput, &afSamplingRate) != NO_ERROR) {
1189*ec779b8eSAndroid Build Coastguard Worker return NO_INIT;
1190*ec779b8eSAndroid Build Coastguard Worker }
1191*ec779b8eSAndroid Build Coastguard Worker // pitch is emulated by adjusting speed and sampleRate
1192*ec779b8eSAndroid Build Coastguard Worker const uint32_t effectiveSampleRate = adjustSampleRate(rate, mPlaybackRate.mPitch);
1193*ec779b8eSAndroid Build Coastguard Worker if (rate == 0 || effectiveSampleRate > afSamplingRate * AUDIO_RESAMPLER_DOWN_RATIO_MAX) {
1194*ec779b8eSAndroid Build Coastguard Worker return BAD_VALUE;
1195*ec779b8eSAndroid Build Coastguard Worker }
1196*ec779b8eSAndroid Build Coastguard Worker // TODO: Should we also check if the buffer size is compatible?
1197*ec779b8eSAndroid Build Coastguard Worker
1198*ec779b8eSAndroid Build Coastguard Worker mSampleRate = rate;
1199*ec779b8eSAndroid Build Coastguard Worker mProxy->setSampleRate(effectiveSampleRate);
1200*ec779b8eSAndroid Build Coastguard Worker
1201*ec779b8eSAndroid Build Coastguard Worker mediametrics::LogItem(mMetricsId)
1202*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_SETSAMPLERATE)
1203*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_PREFIX_EFFECTIVE AMEDIAMETRICS_PROP_SAMPLERATE,
1204*ec779b8eSAndroid Build Coastguard Worker static_cast<int32_t>(effectiveSampleRate))
1205*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_SAMPLERATE, static_cast<int32_t>(rate))
1206*ec779b8eSAndroid Build Coastguard Worker .record();
1207*ec779b8eSAndroid Build Coastguard Worker
1208*ec779b8eSAndroid Build Coastguard Worker return NO_ERROR;
1209*ec779b8eSAndroid Build Coastguard Worker }
1210*ec779b8eSAndroid Build Coastguard Worker
getSampleRate() const1211*ec779b8eSAndroid Build Coastguard Worker uint32_t AudioTrack::getSampleRate() const
1212*ec779b8eSAndroid Build Coastguard Worker {
1213*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
1214*ec779b8eSAndroid Build Coastguard Worker
1215*ec779b8eSAndroid Build Coastguard Worker // sample rate can be updated during playback by the offloaded decoder so we need to
1216*ec779b8eSAndroid Build Coastguard Worker // query the HAL and update if needed.
1217*ec779b8eSAndroid Build Coastguard Worker // FIXME use Proxy return channel to update the rate from server and avoid polling here
1218*ec779b8eSAndroid Build Coastguard Worker if (isOffloadedOrDirect_l()) {
1219*ec779b8eSAndroid Build Coastguard Worker if (mOutput != AUDIO_IO_HANDLE_NONE) {
1220*ec779b8eSAndroid Build Coastguard Worker uint32_t sampleRate = 0;
1221*ec779b8eSAndroid Build Coastguard Worker status_t status = AudioSystem::getSamplingRate(mOutput, &sampleRate);
1222*ec779b8eSAndroid Build Coastguard Worker if (status == NO_ERROR) {
1223*ec779b8eSAndroid Build Coastguard Worker mSampleRate = sampleRate;
1224*ec779b8eSAndroid Build Coastguard Worker }
1225*ec779b8eSAndroid Build Coastguard Worker }
1226*ec779b8eSAndroid Build Coastguard Worker }
1227*ec779b8eSAndroid Build Coastguard Worker return mSampleRate;
1228*ec779b8eSAndroid Build Coastguard Worker }
1229*ec779b8eSAndroid Build Coastguard Worker
getOriginalSampleRate() const1230*ec779b8eSAndroid Build Coastguard Worker uint32_t AudioTrack::getOriginalSampleRate() const
1231*ec779b8eSAndroid Build Coastguard Worker {
1232*ec779b8eSAndroid Build Coastguard Worker return mOriginalSampleRate;
1233*ec779b8eSAndroid Build Coastguard Worker }
1234*ec779b8eSAndroid Build Coastguard Worker
getHalSampleRate() const1235*ec779b8eSAndroid Build Coastguard Worker uint32_t AudioTrack::getHalSampleRate() const
1236*ec779b8eSAndroid Build Coastguard Worker {
1237*ec779b8eSAndroid Build Coastguard Worker return mAfSampleRate;
1238*ec779b8eSAndroid Build Coastguard Worker }
1239*ec779b8eSAndroid Build Coastguard Worker
getHalChannelCount() const1240*ec779b8eSAndroid Build Coastguard Worker uint32_t AudioTrack::getHalChannelCount() const
1241*ec779b8eSAndroid Build Coastguard Worker {
1242*ec779b8eSAndroid Build Coastguard Worker return mAfChannelCount;
1243*ec779b8eSAndroid Build Coastguard Worker }
1244*ec779b8eSAndroid Build Coastguard Worker
getHalFormat() const1245*ec779b8eSAndroid Build Coastguard Worker audio_format_t AudioTrack::getHalFormat() const
1246*ec779b8eSAndroid Build Coastguard Worker {
1247*ec779b8eSAndroid Build Coastguard Worker return mAfFormat;
1248*ec779b8eSAndroid Build Coastguard Worker }
1249*ec779b8eSAndroid Build Coastguard Worker
setDualMonoMode(audio_dual_mono_mode_t mode)1250*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::setDualMonoMode(audio_dual_mono_mode_t mode)
1251*ec779b8eSAndroid Build Coastguard Worker {
1252*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
1253*ec779b8eSAndroid Build Coastguard Worker return setDualMonoMode_l(mode);
1254*ec779b8eSAndroid Build Coastguard Worker }
1255*ec779b8eSAndroid Build Coastguard Worker
setDualMonoMode_l(audio_dual_mono_mode_t mode)1256*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::setDualMonoMode_l(audio_dual_mono_mode_t mode)
1257*ec779b8eSAndroid Build Coastguard Worker {
1258*ec779b8eSAndroid Build Coastguard Worker const status_t status = statusTFromBinderStatus(
1259*ec779b8eSAndroid Build Coastguard Worker mAudioTrack->setDualMonoMode(VALUE_OR_RETURN_STATUS(
1260*ec779b8eSAndroid Build Coastguard Worker legacy2aidl_audio_dual_mono_mode_t_AudioDualMonoMode(mode))));
1261*ec779b8eSAndroid Build Coastguard Worker if (status == NO_ERROR) mDualMonoMode = mode;
1262*ec779b8eSAndroid Build Coastguard Worker return status;
1263*ec779b8eSAndroid Build Coastguard Worker }
1264*ec779b8eSAndroid Build Coastguard Worker
getDualMonoMode(audio_dual_mono_mode_t * mode) const1265*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::getDualMonoMode(audio_dual_mono_mode_t* mode) const
1266*ec779b8eSAndroid Build Coastguard Worker {
1267*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
1268*ec779b8eSAndroid Build Coastguard Worker media::audio::common::AudioDualMonoMode mediaMode;
1269*ec779b8eSAndroid Build Coastguard Worker const status_t status = statusTFromBinderStatus(mAudioTrack->getDualMonoMode(&mediaMode));
1270*ec779b8eSAndroid Build Coastguard Worker if (status == NO_ERROR) {
1271*ec779b8eSAndroid Build Coastguard Worker *mode = VALUE_OR_RETURN_STATUS(
1272*ec779b8eSAndroid Build Coastguard Worker aidl2legacy_AudioDualMonoMode_audio_dual_mono_mode_t(mediaMode));
1273*ec779b8eSAndroid Build Coastguard Worker }
1274*ec779b8eSAndroid Build Coastguard Worker return status;
1275*ec779b8eSAndroid Build Coastguard Worker }
1276*ec779b8eSAndroid Build Coastguard Worker
setAudioDescriptionMixLevel(float leveldB)1277*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::setAudioDescriptionMixLevel(float leveldB)
1278*ec779b8eSAndroid Build Coastguard Worker {
1279*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
1280*ec779b8eSAndroid Build Coastguard Worker return setAudioDescriptionMixLevel_l(leveldB);
1281*ec779b8eSAndroid Build Coastguard Worker }
1282*ec779b8eSAndroid Build Coastguard Worker
setAudioDescriptionMixLevel_l(float leveldB)1283*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::setAudioDescriptionMixLevel_l(float leveldB)
1284*ec779b8eSAndroid Build Coastguard Worker {
1285*ec779b8eSAndroid Build Coastguard Worker const status_t status = statusTFromBinderStatus(
1286*ec779b8eSAndroid Build Coastguard Worker mAudioTrack->setAudioDescriptionMixLevel(leveldB));
1287*ec779b8eSAndroid Build Coastguard Worker if (status == NO_ERROR) mAudioDescriptionMixLeveldB = leveldB;
1288*ec779b8eSAndroid Build Coastguard Worker return status;
1289*ec779b8eSAndroid Build Coastguard Worker }
1290*ec779b8eSAndroid Build Coastguard Worker
getAudioDescriptionMixLevel(float * leveldB) const1291*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::getAudioDescriptionMixLevel(float* leveldB) const
1292*ec779b8eSAndroid Build Coastguard Worker {
1293*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
1294*ec779b8eSAndroid Build Coastguard Worker return statusTFromBinderStatus(mAudioTrack->getAudioDescriptionMixLevel(leveldB));
1295*ec779b8eSAndroid Build Coastguard Worker }
1296*ec779b8eSAndroid Build Coastguard Worker
setPlaybackRate(const AudioPlaybackRate & playbackRate)1297*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::setPlaybackRate(const AudioPlaybackRate &playbackRate)
1298*ec779b8eSAndroid Build Coastguard Worker {
1299*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
1300*ec779b8eSAndroid Build Coastguard Worker if (isAudioPlaybackRateEqual(playbackRate, mPlaybackRate)) {
1301*ec779b8eSAndroid Build Coastguard Worker return NO_ERROR;
1302*ec779b8eSAndroid Build Coastguard Worker }
1303*ec779b8eSAndroid Build Coastguard Worker if (isAfTrackOffloadedOrDirect_l()) {
1304*ec779b8eSAndroid Build Coastguard Worker const status_t status = statusTFromBinderStatus(mAudioTrack->setPlaybackRateParameters(
1305*ec779b8eSAndroid Build Coastguard Worker VALUE_OR_RETURN_STATUS(
1306*ec779b8eSAndroid Build Coastguard Worker legacy2aidl_audio_playback_rate_t_AudioPlaybackRate(playbackRate))));
1307*ec779b8eSAndroid Build Coastguard Worker if (status == NO_ERROR) {
1308*ec779b8eSAndroid Build Coastguard Worker mPlaybackRate = playbackRate;
1309*ec779b8eSAndroid Build Coastguard Worker } else if (status == INVALID_OPERATION
1310*ec779b8eSAndroid Build Coastguard Worker && playbackRate.mSpeed == 1.0f && mPlaybackRate.mPitch == 1.0f) {
1311*ec779b8eSAndroid Build Coastguard Worker mPlaybackRate = playbackRate;
1312*ec779b8eSAndroid Build Coastguard Worker return NO_ERROR;
1313*ec779b8eSAndroid Build Coastguard Worker }
1314*ec779b8eSAndroid Build Coastguard Worker return status;
1315*ec779b8eSAndroid Build Coastguard Worker }
1316*ec779b8eSAndroid Build Coastguard Worker if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
1317*ec779b8eSAndroid Build Coastguard Worker return INVALID_OPERATION;
1318*ec779b8eSAndroid Build Coastguard Worker }
1319*ec779b8eSAndroid Build Coastguard Worker
1320*ec779b8eSAndroid Build Coastguard Worker ALOGV("%s(%d): mSampleRate:%u mSpeed:%f mPitch:%f",
1321*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId, mSampleRate, playbackRate.mSpeed, playbackRate.mPitch);
1322*ec779b8eSAndroid Build Coastguard Worker // pitch is emulated by adjusting speed and sampleRate
1323*ec779b8eSAndroid Build Coastguard Worker const uint32_t effectiveRate = adjustSampleRate(mSampleRate, playbackRate.mPitch);
1324*ec779b8eSAndroid Build Coastguard Worker const float effectiveSpeed = adjustSpeed(playbackRate.mSpeed, playbackRate.mPitch);
1325*ec779b8eSAndroid Build Coastguard Worker const float effectivePitch = adjustPitch(playbackRate.mPitch);
1326*ec779b8eSAndroid Build Coastguard Worker AudioPlaybackRate playbackRateTemp = playbackRate;
1327*ec779b8eSAndroid Build Coastguard Worker playbackRateTemp.mSpeed = effectiveSpeed;
1328*ec779b8eSAndroid Build Coastguard Worker playbackRateTemp.mPitch = effectivePitch;
1329*ec779b8eSAndroid Build Coastguard Worker
1330*ec779b8eSAndroid Build Coastguard Worker ALOGV("%s(%d) (effective) mSampleRate:%u mSpeed:%f mPitch:%f",
1331*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId, effectiveRate, effectiveSpeed, effectivePitch);
1332*ec779b8eSAndroid Build Coastguard Worker
1333*ec779b8eSAndroid Build Coastguard Worker if (!isAudioPlaybackRateValid(playbackRateTemp)) {
1334*ec779b8eSAndroid Build Coastguard Worker ALOGW("%s(%d) (%f, %f) failed (effective rate out of bounds)",
1335*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId, playbackRate.mSpeed, playbackRate.mPitch);
1336*ec779b8eSAndroid Build Coastguard Worker return BAD_VALUE;
1337*ec779b8eSAndroid Build Coastguard Worker }
1338*ec779b8eSAndroid Build Coastguard Worker // Check if the buffer size is compatible.
1339*ec779b8eSAndroid Build Coastguard Worker if (!isSampleRateSpeedAllowed_l(effectiveRate, effectiveSpeed)) {
1340*ec779b8eSAndroid Build Coastguard Worker ALOGW("%s(%d) (%f, %f) failed (buffer size)",
1341*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId, playbackRate.mSpeed, playbackRate.mPitch);
1342*ec779b8eSAndroid Build Coastguard Worker return BAD_VALUE;
1343*ec779b8eSAndroid Build Coastguard Worker }
1344*ec779b8eSAndroid Build Coastguard Worker
1345*ec779b8eSAndroid Build Coastguard Worker // Check resampler ratios are within bounds
1346*ec779b8eSAndroid Build Coastguard Worker if ((uint64_t)effectiveRate > (uint64_t)mSampleRate *
1347*ec779b8eSAndroid Build Coastguard Worker (uint64_t)AUDIO_RESAMPLER_DOWN_RATIO_MAX) {
1348*ec779b8eSAndroid Build Coastguard Worker ALOGW("%s(%d) (%f, %f) failed. Resample rate exceeds max accepted value",
1349*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId, playbackRate.mSpeed, playbackRate.mPitch);
1350*ec779b8eSAndroid Build Coastguard Worker return BAD_VALUE;
1351*ec779b8eSAndroid Build Coastguard Worker }
1352*ec779b8eSAndroid Build Coastguard Worker
1353*ec779b8eSAndroid Build Coastguard Worker if ((uint64_t)effectiveRate * (uint64_t)AUDIO_RESAMPLER_UP_RATIO_MAX < (uint64_t)mSampleRate) {
1354*ec779b8eSAndroid Build Coastguard Worker ALOGW("%s(%d) (%f, %f) failed. Resample rate below min accepted value",
1355*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId, playbackRate.mSpeed, playbackRate.mPitch);
1356*ec779b8eSAndroid Build Coastguard Worker return BAD_VALUE;
1357*ec779b8eSAndroid Build Coastguard Worker }
1358*ec779b8eSAndroid Build Coastguard Worker mPlaybackRate = playbackRate;
1359*ec779b8eSAndroid Build Coastguard Worker //set effective rates
1360*ec779b8eSAndroid Build Coastguard Worker mProxy->setPlaybackRate(playbackRateTemp);
1361*ec779b8eSAndroid Build Coastguard Worker mProxy->setSampleRate(effectiveRate); // FIXME: not quite "atomic" with setPlaybackRate
1362*ec779b8eSAndroid Build Coastguard Worker
1363*ec779b8eSAndroid Build Coastguard Worker mediametrics::LogItem(mMetricsId)
1364*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_SETPLAYBACKPARAM)
1365*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_SAMPLERATE, (int32_t)mSampleRate)
1366*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_PLAYBACK_SPEED, (double)mPlaybackRate.mSpeed)
1367*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_PLAYBACK_PITCH, (double)mPlaybackRate.mPitch)
1368*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_PREFIX_EFFECTIVE
1369*ec779b8eSAndroid Build Coastguard Worker AMEDIAMETRICS_PROP_SAMPLERATE, (int32_t)effectiveRate)
1370*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_PREFIX_EFFECTIVE
1371*ec779b8eSAndroid Build Coastguard Worker AMEDIAMETRICS_PROP_PLAYBACK_SPEED, (double)playbackRateTemp.mSpeed)
1372*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_PREFIX_EFFECTIVE
1373*ec779b8eSAndroid Build Coastguard Worker AMEDIAMETRICS_PROP_PLAYBACK_PITCH, (double)playbackRateTemp.mPitch)
1374*ec779b8eSAndroid Build Coastguard Worker .record();
1375*ec779b8eSAndroid Build Coastguard Worker
1376*ec779b8eSAndroid Build Coastguard Worker return NO_ERROR;
1377*ec779b8eSAndroid Build Coastguard Worker }
1378*ec779b8eSAndroid Build Coastguard Worker
getPlaybackRate()1379*ec779b8eSAndroid Build Coastguard Worker const AudioPlaybackRate& AudioTrack::getPlaybackRate()
1380*ec779b8eSAndroid Build Coastguard Worker {
1381*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
1382*ec779b8eSAndroid Build Coastguard Worker if (isOffloadedOrDirect_l()) {
1383*ec779b8eSAndroid Build Coastguard Worker media::audio::common::AudioPlaybackRate playbackRateTemp;
1384*ec779b8eSAndroid Build Coastguard Worker const status_t status = statusTFromBinderStatus(
1385*ec779b8eSAndroid Build Coastguard Worker mAudioTrack->getPlaybackRateParameters(&playbackRateTemp));
1386*ec779b8eSAndroid Build Coastguard Worker if (status == NO_ERROR) { // update local version if changed.
1387*ec779b8eSAndroid Build Coastguard Worker mPlaybackRate =
1388*ec779b8eSAndroid Build Coastguard Worker aidl2legacy_AudioPlaybackRate_audio_playback_rate_t(playbackRateTemp).value();
1389*ec779b8eSAndroid Build Coastguard Worker }
1390*ec779b8eSAndroid Build Coastguard Worker }
1391*ec779b8eSAndroid Build Coastguard Worker return mPlaybackRate;
1392*ec779b8eSAndroid Build Coastguard Worker }
1393*ec779b8eSAndroid Build Coastguard Worker
getBufferSizeInFrames()1394*ec779b8eSAndroid Build Coastguard Worker ssize_t AudioTrack::getBufferSizeInFrames()
1395*ec779b8eSAndroid Build Coastguard Worker {
1396*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
1397*ec779b8eSAndroid Build Coastguard Worker if (mOutput == AUDIO_IO_HANDLE_NONE || mProxy.get() == 0) {
1398*ec779b8eSAndroid Build Coastguard Worker return NO_INIT;
1399*ec779b8eSAndroid Build Coastguard Worker }
1400*ec779b8eSAndroid Build Coastguard Worker
1401*ec779b8eSAndroid Build Coastguard Worker return (ssize_t) mProxy->getBufferSizeInFrames();
1402*ec779b8eSAndroid Build Coastguard Worker }
1403*ec779b8eSAndroid Build Coastguard Worker
getBufferDurationInUs(int64_t * duration)1404*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::getBufferDurationInUs(int64_t *duration)
1405*ec779b8eSAndroid Build Coastguard Worker {
1406*ec779b8eSAndroid Build Coastguard Worker if (duration == nullptr) {
1407*ec779b8eSAndroid Build Coastguard Worker return BAD_VALUE;
1408*ec779b8eSAndroid Build Coastguard Worker }
1409*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
1410*ec779b8eSAndroid Build Coastguard Worker if (mOutput == AUDIO_IO_HANDLE_NONE || mProxy.get() == 0) {
1411*ec779b8eSAndroid Build Coastguard Worker return NO_INIT;
1412*ec779b8eSAndroid Build Coastguard Worker }
1413*ec779b8eSAndroid Build Coastguard Worker ssize_t bufferSizeInFrames = (ssize_t) mProxy->getBufferSizeInFrames();
1414*ec779b8eSAndroid Build Coastguard Worker if (bufferSizeInFrames < 0) {
1415*ec779b8eSAndroid Build Coastguard Worker return (status_t)bufferSizeInFrames;
1416*ec779b8eSAndroid Build Coastguard Worker }
1417*ec779b8eSAndroid Build Coastguard Worker *duration = (int64_t)((double)bufferSizeInFrames * 1000000
1418*ec779b8eSAndroid Build Coastguard Worker / ((double)mSampleRate * mPlaybackRate.mSpeed));
1419*ec779b8eSAndroid Build Coastguard Worker return NO_ERROR;
1420*ec779b8eSAndroid Build Coastguard Worker }
1421*ec779b8eSAndroid Build Coastguard Worker
setBufferSizeInFrames(size_t bufferSizeInFrames)1422*ec779b8eSAndroid Build Coastguard Worker ssize_t AudioTrack::setBufferSizeInFrames(size_t bufferSizeInFrames)
1423*ec779b8eSAndroid Build Coastguard Worker {
1424*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
1425*ec779b8eSAndroid Build Coastguard Worker if (mOutput == AUDIO_IO_HANDLE_NONE || mProxy.get() == 0) {
1426*ec779b8eSAndroid Build Coastguard Worker return NO_INIT;
1427*ec779b8eSAndroid Build Coastguard Worker }
1428*ec779b8eSAndroid Build Coastguard Worker
1429*ec779b8eSAndroid Build Coastguard Worker ssize_t originalBufferSize = mProxy->getBufferSizeInFrames();
1430*ec779b8eSAndroid Build Coastguard Worker ssize_t finalBufferSize = mProxy->setBufferSizeInFrames((uint32_t) bufferSizeInFrames);
1431*ec779b8eSAndroid Build Coastguard Worker if (originalBufferSize != finalBufferSize) {
1432*ec779b8eSAndroid Build Coastguard Worker android::mediametrics::LogItem(mMetricsId)
1433*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_SETBUFFERSIZE)
1434*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_BUFFERSIZEFRAMES, (int32_t)mProxy->getBufferSizeInFrames())
1435*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_UNDERRUN, (int32_t)getUnderrunCount_l())
1436*ec779b8eSAndroid Build Coastguard Worker .record();
1437*ec779b8eSAndroid Build Coastguard Worker }
1438*ec779b8eSAndroid Build Coastguard Worker return finalBufferSize;
1439*ec779b8eSAndroid Build Coastguard Worker }
1440*ec779b8eSAndroid Build Coastguard Worker
getStartThresholdInFrames() const1441*ec779b8eSAndroid Build Coastguard Worker ssize_t AudioTrack::getStartThresholdInFrames() const
1442*ec779b8eSAndroid Build Coastguard Worker {
1443*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
1444*ec779b8eSAndroid Build Coastguard Worker if (mOutput == AUDIO_IO_HANDLE_NONE || mProxy.get() == 0) {
1445*ec779b8eSAndroid Build Coastguard Worker return NO_INIT;
1446*ec779b8eSAndroid Build Coastguard Worker }
1447*ec779b8eSAndroid Build Coastguard Worker return (ssize_t) mProxy->getStartThresholdInFrames();
1448*ec779b8eSAndroid Build Coastguard Worker }
1449*ec779b8eSAndroid Build Coastguard Worker
setStartThresholdInFrames(size_t startThresholdInFrames)1450*ec779b8eSAndroid Build Coastguard Worker ssize_t AudioTrack::setStartThresholdInFrames(size_t startThresholdInFrames)
1451*ec779b8eSAndroid Build Coastguard Worker {
1452*ec779b8eSAndroid Build Coastguard Worker if (startThresholdInFrames > INT32_MAX || startThresholdInFrames == 0) {
1453*ec779b8eSAndroid Build Coastguard Worker // contractually we could simply return the current threshold in frames
1454*ec779b8eSAndroid Build Coastguard Worker // to indicate the request was ignored, but we return an error here.
1455*ec779b8eSAndroid Build Coastguard Worker return BAD_VALUE;
1456*ec779b8eSAndroid Build Coastguard Worker }
1457*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
1458*ec779b8eSAndroid Build Coastguard Worker // We do not permit calling setStartThresholdInFrames() between the AudioTrack
1459*ec779b8eSAndroid Build Coastguard Worker // default ctor AudioTrack() and set(...) but rather fail such an attempt.
1460*ec779b8eSAndroid Build Coastguard Worker // (To do so would require a cached mOrigStartThresholdInFrames and we may
1461*ec779b8eSAndroid Build Coastguard Worker // not have proper validation for the actual set value).
1462*ec779b8eSAndroid Build Coastguard Worker if (mOutput == AUDIO_IO_HANDLE_NONE || mProxy.get() == 0) {
1463*ec779b8eSAndroid Build Coastguard Worker return NO_INIT;
1464*ec779b8eSAndroid Build Coastguard Worker }
1465*ec779b8eSAndroid Build Coastguard Worker const uint32_t original = mProxy->getStartThresholdInFrames();
1466*ec779b8eSAndroid Build Coastguard Worker const uint32_t final = mProxy->setStartThresholdInFrames(startThresholdInFrames);
1467*ec779b8eSAndroid Build Coastguard Worker if (original != final) {
1468*ec779b8eSAndroid Build Coastguard Worker android::mediametrics::LogItem(mMetricsId)
1469*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_SETSTARTTHRESHOLD)
1470*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_STARTTHRESHOLDFRAMES, (int32_t)final)
1471*ec779b8eSAndroid Build Coastguard Worker .record();
1472*ec779b8eSAndroid Build Coastguard Worker if (original > final) {
1473*ec779b8eSAndroid Build Coastguard Worker // restart track if it was disabled by audioflinger due to previous underrun
1474*ec779b8eSAndroid Build Coastguard Worker // and we reduced the number of frames for the threshold.
1475*ec779b8eSAndroid Build Coastguard Worker restartIfDisabled();
1476*ec779b8eSAndroid Build Coastguard Worker }
1477*ec779b8eSAndroid Build Coastguard Worker }
1478*ec779b8eSAndroid Build Coastguard Worker return final;
1479*ec779b8eSAndroid Build Coastguard Worker }
1480*ec779b8eSAndroid Build Coastguard Worker
setLoop(uint32_t loopStart,uint32_t loopEnd,int loopCount)1481*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount)
1482*ec779b8eSAndroid Build Coastguard Worker {
1483*ec779b8eSAndroid Build Coastguard Worker if (mSharedBuffer == 0 || isOffloadedOrDirect()) {
1484*ec779b8eSAndroid Build Coastguard Worker return INVALID_OPERATION;
1485*ec779b8eSAndroid Build Coastguard Worker }
1486*ec779b8eSAndroid Build Coastguard Worker
1487*ec779b8eSAndroid Build Coastguard Worker if (loopCount == 0) {
1488*ec779b8eSAndroid Build Coastguard Worker ;
1489*ec779b8eSAndroid Build Coastguard Worker } else if (loopCount >= -1 && loopStart < loopEnd && loopEnd <= mFrameCount &&
1490*ec779b8eSAndroid Build Coastguard Worker loopEnd - loopStart >= MIN_LOOP) {
1491*ec779b8eSAndroid Build Coastguard Worker ;
1492*ec779b8eSAndroid Build Coastguard Worker } else {
1493*ec779b8eSAndroid Build Coastguard Worker return BAD_VALUE;
1494*ec779b8eSAndroid Build Coastguard Worker }
1495*ec779b8eSAndroid Build Coastguard Worker
1496*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
1497*ec779b8eSAndroid Build Coastguard Worker // See setPosition() regarding setting parameters such as loop points or position while active
1498*ec779b8eSAndroid Build Coastguard Worker if (mState == STATE_ACTIVE) {
1499*ec779b8eSAndroid Build Coastguard Worker return INVALID_OPERATION;
1500*ec779b8eSAndroid Build Coastguard Worker }
1501*ec779b8eSAndroid Build Coastguard Worker setLoop_l(loopStart, loopEnd, loopCount);
1502*ec779b8eSAndroid Build Coastguard Worker return NO_ERROR;
1503*ec779b8eSAndroid Build Coastguard Worker }
1504*ec779b8eSAndroid Build Coastguard Worker
setLoop_l(uint32_t loopStart,uint32_t loopEnd,int loopCount)1505*ec779b8eSAndroid Build Coastguard Worker void AudioTrack::setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCount)
1506*ec779b8eSAndroid Build Coastguard Worker {
1507*ec779b8eSAndroid Build Coastguard Worker // We do not update the periodic notification point.
1508*ec779b8eSAndroid Build Coastguard Worker // mNewPosition = updateAndGetPosition_l() + mUpdatePeriod;
1509*ec779b8eSAndroid Build Coastguard Worker mLoopCount = loopCount;
1510*ec779b8eSAndroid Build Coastguard Worker mLoopEnd = loopEnd;
1511*ec779b8eSAndroid Build Coastguard Worker mLoopStart = loopStart;
1512*ec779b8eSAndroid Build Coastguard Worker mLoopCountNotified = loopCount;
1513*ec779b8eSAndroid Build Coastguard Worker mStaticProxy->setLoop(loopStart, loopEnd, loopCount);
1514*ec779b8eSAndroid Build Coastguard Worker
1515*ec779b8eSAndroid Build Coastguard Worker // Waking the AudioTrackThread is not needed as this cannot be called when active.
1516*ec779b8eSAndroid Build Coastguard Worker }
1517*ec779b8eSAndroid Build Coastguard Worker
setMarkerPosition(uint32_t marker)1518*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::setMarkerPosition(uint32_t marker)
1519*ec779b8eSAndroid Build Coastguard Worker {
1520*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
1521*ec779b8eSAndroid Build Coastguard Worker // The only purpose of setting marker position is to get a callback
1522*ec779b8eSAndroid Build Coastguard Worker if (!mCallback.promote() || isOffloadedOrDirect_l()) {
1523*ec779b8eSAndroid Build Coastguard Worker return INVALID_OPERATION;
1524*ec779b8eSAndroid Build Coastguard Worker }
1525*ec779b8eSAndroid Build Coastguard Worker
1526*ec779b8eSAndroid Build Coastguard Worker mMarkerPosition = marker;
1527*ec779b8eSAndroid Build Coastguard Worker mMarkerReached = false;
1528*ec779b8eSAndroid Build Coastguard Worker
1529*ec779b8eSAndroid Build Coastguard Worker sp<AudioTrackThread> t = mAudioTrackThread;
1530*ec779b8eSAndroid Build Coastguard Worker if (t != 0) {
1531*ec779b8eSAndroid Build Coastguard Worker t->wake();
1532*ec779b8eSAndroid Build Coastguard Worker }
1533*ec779b8eSAndroid Build Coastguard Worker return NO_ERROR;
1534*ec779b8eSAndroid Build Coastguard Worker }
1535*ec779b8eSAndroid Build Coastguard Worker
getMarkerPosition(uint32_t * marker) const1536*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::getMarkerPosition(uint32_t *marker) const
1537*ec779b8eSAndroid Build Coastguard Worker {
1538*ec779b8eSAndroid Build Coastguard Worker if (isOffloadedOrDirect()) {
1539*ec779b8eSAndroid Build Coastguard Worker return INVALID_OPERATION;
1540*ec779b8eSAndroid Build Coastguard Worker }
1541*ec779b8eSAndroid Build Coastguard Worker if (marker == NULL) {
1542*ec779b8eSAndroid Build Coastguard Worker return BAD_VALUE;
1543*ec779b8eSAndroid Build Coastguard Worker }
1544*ec779b8eSAndroid Build Coastguard Worker
1545*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
1546*ec779b8eSAndroid Build Coastguard Worker mMarkerPosition.getValue(marker);
1547*ec779b8eSAndroid Build Coastguard Worker
1548*ec779b8eSAndroid Build Coastguard Worker return NO_ERROR;
1549*ec779b8eSAndroid Build Coastguard Worker }
1550*ec779b8eSAndroid Build Coastguard Worker
setPositionUpdatePeriod(uint32_t updatePeriod)1551*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::setPositionUpdatePeriod(uint32_t updatePeriod)
1552*ec779b8eSAndroid Build Coastguard Worker {
1553*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
1554*ec779b8eSAndroid Build Coastguard Worker // The only purpose of setting position update period is to get a callback
1555*ec779b8eSAndroid Build Coastguard Worker if (!mCallback.promote() || isOffloadedOrDirect_l()) {
1556*ec779b8eSAndroid Build Coastguard Worker return INVALID_OPERATION;
1557*ec779b8eSAndroid Build Coastguard Worker }
1558*ec779b8eSAndroid Build Coastguard Worker
1559*ec779b8eSAndroid Build Coastguard Worker mNewPosition = updateAndGetPosition_l() + updatePeriod;
1560*ec779b8eSAndroid Build Coastguard Worker mUpdatePeriod = updatePeriod;
1561*ec779b8eSAndroid Build Coastguard Worker
1562*ec779b8eSAndroid Build Coastguard Worker sp<AudioTrackThread> t = mAudioTrackThread;
1563*ec779b8eSAndroid Build Coastguard Worker if (t != 0) {
1564*ec779b8eSAndroid Build Coastguard Worker t->wake();
1565*ec779b8eSAndroid Build Coastguard Worker }
1566*ec779b8eSAndroid Build Coastguard Worker return NO_ERROR;
1567*ec779b8eSAndroid Build Coastguard Worker }
1568*ec779b8eSAndroid Build Coastguard Worker
getPositionUpdatePeriod(uint32_t * updatePeriod) const1569*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::getPositionUpdatePeriod(uint32_t *updatePeriod) const
1570*ec779b8eSAndroid Build Coastguard Worker {
1571*ec779b8eSAndroid Build Coastguard Worker if (isOffloadedOrDirect()) {
1572*ec779b8eSAndroid Build Coastguard Worker return INVALID_OPERATION;
1573*ec779b8eSAndroid Build Coastguard Worker }
1574*ec779b8eSAndroid Build Coastguard Worker if (updatePeriod == NULL) {
1575*ec779b8eSAndroid Build Coastguard Worker return BAD_VALUE;
1576*ec779b8eSAndroid Build Coastguard Worker }
1577*ec779b8eSAndroid Build Coastguard Worker
1578*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
1579*ec779b8eSAndroid Build Coastguard Worker *updatePeriod = mUpdatePeriod;
1580*ec779b8eSAndroid Build Coastguard Worker
1581*ec779b8eSAndroid Build Coastguard Worker return NO_ERROR;
1582*ec779b8eSAndroid Build Coastguard Worker }
1583*ec779b8eSAndroid Build Coastguard Worker
setPosition(uint32_t position)1584*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::setPosition(uint32_t position)
1585*ec779b8eSAndroid Build Coastguard Worker {
1586*ec779b8eSAndroid Build Coastguard Worker if (mSharedBuffer == 0 || isOffloadedOrDirect()) {
1587*ec779b8eSAndroid Build Coastguard Worker return INVALID_OPERATION;
1588*ec779b8eSAndroid Build Coastguard Worker }
1589*ec779b8eSAndroid Build Coastguard Worker if (position > mFrameCount) {
1590*ec779b8eSAndroid Build Coastguard Worker return BAD_VALUE;
1591*ec779b8eSAndroid Build Coastguard Worker }
1592*ec779b8eSAndroid Build Coastguard Worker
1593*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
1594*ec779b8eSAndroid Build Coastguard Worker // Currently we require that the player is inactive before setting parameters such as position
1595*ec779b8eSAndroid Build Coastguard Worker // or loop points. Otherwise, there could be a race condition: the application could read the
1596*ec779b8eSAndroid Build Coastguard Worker // current position, compute a new position or loop parameters, and then set that position or
1597*ec779b8eSAndroid Build Coastguard Worker // loop parameters but it would do the "wrong" thing since the position has continued to advance
1598*ec779b8eSAndroid Build Coastguard Worker // in the mean time. If we ever provide a sequencer in server, we could allow a way for the app
1599*ec779b8eSAndroid Build Coastguard Worker // to specify how it wants to handle such scenarios.
1600*ec779b8eSAndroid Build Coastguard Worker if (mState == STATE_ACTIVE) {
1601*ec779b8eSAndroid Build Coastguard Worker return INVALID_OPERATION;
1602*ec779b8eSAndroid Build Coastguard Worker }
1603*ec779b8eSAndroid Build Coastguard Worker // After setting the position, use full update period before notification.
1604*ec779b8eSAndroid Build Coastguard Worker mNewPosition = updateAndGetPosition_l() + mUpdatePeriod;
1605*ec779b8eSAndroid Build Coastguard Worker mStaticProxy->setBufferPosition(position);
1606*ec779b8eSAndroid Build Coastguard Worker
1607*ec779b8eSAndroid Build Coastguard Worker // Waking the AudioTrackThread is not needed as this cannot be called when active.
1608*ec779b8eSAndroid Build Coastguard Worker return NO_ERROR;
1609*ec779b8eSAndroid Build Coastguard Worker }
1610*ec779b8eSAndroid Build Coastguard Worker
getPosition(uint32_t * position)1611*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::getPosition(uint32_t *position)
1612*ec779b8eSAndroid Build Coastguard Worker {
1613*ec779b8eSAndroid Build Coastguard Worker if (position == NULL) {
1614*ec779b8eSAndroid Build Coastguard Worker return BAD_VALUE;
1615*ec779b8eSAndroid Build Coastguard Worker }
1616*ec779b8eSAndroid Build Coastguard Worker
1617*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
1618*ec779b8eSAndroid Build Coastguard Worker // IAudioTrack::stop() isn't synchronous; we don't know when presentation completes
1619*ec779b8eSAndroid Build Coastguard Worker if (mState == STATE_STOPPED || mState == STATE_FLUSHED) {
1620*ec779b8eSAndroid Build Coastguard Worker *position = 0;
1621*ec779b8eSAndroid Build Coastguard Worker return NO_ERROR;
1622*ec779b8eSAndroid Build Coastguard Worker }
1623*ec779b8eSAndroid Build Coastguard Worker // FIXME: offloaded and direct tracks call into the HAL for render positions
1624*ec779b8eSAndroid Build Coastguard Worker // for compressed/synced data; however, we use proxy position for pure linear pcm data
1625*ec779b8eSAndroid Build Coastguard Worker // as we do not know the capability of the HAL for pcm position support and standby.
1626*ec779b8eSAndroid Build Coastguard Worker // There may be some latency differences between the HAL position and the proxy position.
1627*ec779b8eSAndroid Build Coastguard Worker if (isOffloadedOrDirect_l() && !isPurePcmData_l()) {
1628*ec779b8eSAndroid Build Coastguard Worker if (isOffloaded_l() && ((mState == STATE_PAUSED) || (mState == STATE_PAUSED_STOPPING))) {
1629*ec779b8eSAndroid Build Coastguard Worker ALOGV("%s(%d): called in paused state, return cached position %u",
1630*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId, mPausedPosition);
1631*ec779b8eSAndroid Build Coastguard Worker *position = mPausedPosition;
1632*ec779b8eSAndroid Build Coastguard Worker return NO_ERROR;
1633*ec779b8eSAndroid Build Coastguard Worker }
1634*ec779b8eSAndroid Build Coastguard Worker
1635*ec779b8eSAndroid Build Coastguard Worker uint32_t dspFrames = 0;
1636*ec779b8eSAndroid Build Coastguard Worker if (mOutput != AUDIO_IO_HANDLE_NONE) {
1637*ec779b8eSAndroid Build Coastguard Worker uint32_t halFrames; // actually unused
1638*ec779b8eSAndroid Build Coastguard Worker // FIXME: on getRenderPosition() error, we return OK with frame position 0.
1639*ec779b8eSAndroid Build Coastguard Worker if (AudioSystem::getRenderPosition(mOutput, &halFrames, &dspFrames) != NO_ERROR) {
1640*ec779b8eSAndroid Build Coastguard Worker *position = 0;
1641*ec779b8eSAndroid Build Coastguard Worker return NO_ERROR;
1642*ec779b8eSAndroid Build Coastguard Worker }
1643*ec779b8eSAndroid Build Coastguard Worker }
1644*ec779b8eSAndroid Build Coastguard Worker *position = dspFrames;
1645*ec779b8eSAndroid Build Coastguard Worker } else {
1646*ec779b8eSAndroid Build Coastguard Worker if (mCblk->mFlags & CBLK_INVALID) {
1647*ec779b8eSAndroid Build Coastguard Worker (void) restoreTrack_l("getPosition");
1648*ec779b8eSAndroid Build Coastguard Worker // FIXME: for compatibility with the Java API we ignore the restoreTrack_l()
1649*ec779b8eSAndroid Build Coastguard Worker // error here (e.g. DEAD_OBJECT) and return OK with the last recorded server position.
1650*ec779b8eSAndroid Build Coastguard Worker }
1651*ec779b8eSAndroid Build Coastguard Worker *position = updateAndGetPosition_l().value();
1652*ec779b8eSAndroid Build Coastguard Worker }
1653*ec779b8eSAndroid Build Coastguard Worker
1654*ec779b8eSAndroid Build Coastguard Worker return NO_ERROR;
1655*ec779b8eSAndroid Build Coastguard Worker }
1656*ec779b8eSAndroid Build Coastguard Worker
getBufferPosition(uint32_t * position)1657*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::getBufferPosition(uint32_t *position)
1658*ec779b8eSAndroid Build Coastguard Worker {
1659*ec779b8eSAndroid Build Coastguard Worker if (mSharedBuffer == 0) {
1660*ec779b8eSAndroid Build Coastguard Worker return INVALID_OPERATION;
1661*ec779b8eSAndroid Build Coastguard Worker }
1662*ec779b8eSAndroid Build Coastguard Worker if (position == NULL) {
1663*ec779b8eSAndroid Build Coastguard Worker return BAD_VALUE;
1664*ec779b8eSAndroid Build Coastguard Worker }
1665*ec779b8eSAndroid Build Coastguard Worker
1666*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
1667*ec779b8eSAndroid Build Coastguard Worker *position = mStaticProxy->getBufferPosition();
1668*ec779b8eSAndroid Build Coastguard Worker return NO_ERROR;
1669*ec779b8eSAndroid Build Coastguard Worker }
1670*ec779b8eSAndroid Build Coastguard Worker
reload()1671*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::reload()
1672*ec779b8eSAndroid Build Coastguard Worker {
1673*ec779b8eSAndroid Build Coastguard Worker if (mSharedBuffer == 0 || isOffloadedOrDirect()) {
1674*ec779b8eSAndroid Build Coastguard Worker return INVALID_OPERATION;
1675*ec779b8eSAndroid Build Coastguard Worker }
1676*ec779b8eSAndroid Build Coastguard Worker
1677*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
1678*ec779b8eSAndroid Build Coastguard Worker // See setPosition() regarding setting parameters such as loop points or position while active
1679*ec779b8eSAndroid Build Coastguard Worker if (mState == STATE_ACTIVE) {
1680*ec779b8eSAndroid Build Coastguard Worker return INVALID_OPERATION;
1681*ec779b8eSAndroid Build Coastguard Worker }
1682*ec779b8eSAndroid Build Coastguard Worker mNewPosition = mUpdatePeriod;
1683*ec779b8eSAndroid Build Coastguard Worker (void) updateAndGetPosition_l();
1684*ec779b8eSAndroid Build Coastguard Worker mPosition = 0;
1685*ec779b8eSAndroid Build Coastguard Worker mPreviousTimestampValid = false;
1686*ec779b8eSAndroid Build Coastguard Worker #if 0
1687*ec779b8eSAndroid Build Coastguard Worker // The documentation is not clear on the behavior of reload() and the restoration
1688*ec779b8eSAndroid Build Coastguard Worker // of loop count. Historically we have not restored loop count, start, end,
1689*ec779b8eSAndroid Build Coastguard Worker // but it makes sense if one desires to repeat playing a particular sound.
1690*ec779b8eSAndroid Build Coastguard Worker if (mLoopCount != 0) {
1691*ec779b8eSAndroid Build Coastguard Worker mLoopCountNotified = mLoopCount;
1692*ec779b8eSAndroid Build Coastguard Worker mStaticProxy->setLoop(mLoopStart, mLoopEnd, mLoopCount);
1693*ec779b8eSAndroid Build Coastguard Worker }
1694*ec779b8eSAndroid Build Coastguard Worker #endif
1695*ec779b8eSAndroid Build Coastguard Worker mStaticProxy->setBufferPosition(0);
1696*ec779b8eSAndroid Build Coastguard Worker return NO_ERROR;
1697*ec779b8eSAndroid Build Coastguard Worker }
1698*ec779b8eSAndroid Build Coastguard Worker
getOutput() const1699*ec779b8eSAndroid Build Coastguard Worker audio_io_handle_t AudioTrack::getOutput() const
1700*ec779b8eSAndroid Build Coastguard Worker {
1701*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
1702*ec779b8eSAndroid Build Coastguard Worker return mOutput;
1703*ec779b8eSAndroid Build Coastguard Worker }
1704*ec779b8eSAndroid Build Coastguard Worker
setOutputDevice(audio_port_handle_t deviceId)1705*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::setOutputDevice(audio_port_handle_t deviceId) {
1706*ec779b8eSAndroid Build Coastguard Worker status_t result = NO_ERROR;
1707*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
1708*ec779b8eSAndroid Build Coastguard Worker ALOGV("%s(%d): deviceId=%d mSelectedDeviceId=%d",
1709*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId, deviceId, mSelectedDeviceId);
1710*ec779b8eSAndroid Build Coastguard Worker const int64_t beginNs = systemTime();
1711*ec779b8eSAndroid Build Coastguard Worker mediametrics::Defer defer([&] {
1712*ec779b8eSAndroid Build Coastguard Worker mediametrics::LogItem(mMetricsId)
1713*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_CALLERNAME,
1714*ec779b8eSAndroid Build Coastguard Worker mCallerName.empty()
1715*ec779b8eSAndroid Build Coastguard Worker ? AMEDIAMETRICS_PROP_CALLERNAME_VALUE_UNKNOWN
1716*ec779b8eSAndroid Build Coastguard Worker : mCallerName.c_str())
1717*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_SETPREFERREDDEVICE)
1718*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(systemTime() - beginNs))
1719*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_SELECTEDDEVICEID, (int32_t)deviceId)
1720*ec779b8eSAndroid Build Coastguard Worker .record(); });
1721*ec779b8eSAndroid Build Coastguard Worker
1722*ec779b8eSAndroid Build Coastguard Worker if (mSelectedDeviceId != deviceId) {
1723*ec779b8eSAndroid Build Coastguard Worker mSelectedDeviceId = deviceId;
1724*ec779b8eSAndroid Build Coastguard Worker if (mStatus == NO_ERROR) {
1725*ec779b8eSAndroid Build Coastguard Worker if (isOffloadedOrDirect_l()) {
1726*ec779b8eSAndroid Build Coastguard Worker if (isPlaying_l()) {
1727*ec779b8eSAndroid Build Coastguard Worker ALOGW("%s(%d). Offloaded or Direct track is not STOPPED or FLUSHED. "
1728*ec779b8eSAndroid Build Coastguard Worker "State: %s.",
1729*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId, stateToString(mState));
1730*ec779b8eSAndroid Build Coastguard Worker result = INVALID_OPERATION;
1731*ec779b8eSAndroid Build Coastguard Worker } else {
1732*ec779b8eSAndroid Build Coastguard Worker ALOGD("%s(%d): creating a new AudioTrack", __func__, mPortId);
1733*ec779b8eSAndroid Build Coastguard Worker result = restoreTrack_l("setOutputDevice", true /* forceRestore */);
1734*ec779b8eSAndroid Build Coastguard Worker }
1735*ec779b8eSAndroid Build Coastguard Worker } else {
1736*ec779b8eSAndroid Build Coastguard Worker // allow track invalidation when track is not playing to propagate
1737*ec779b8eSAndroid Build Coastguard Worker // the updated mSelectedDeviceId
1738*ec779b8eSAndroid Build Coastguard Worker if (isPlaying_l()) {
1739*ec779b8eSAndroid Build Coastguard Worker if (getFirstDeviceId(mRoutedDeviceIds) != mSelectedDeviceId) {
1740*ec779b8eSAndroid Build Coastguard Worker android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
1741*ec779b8eSAndroid Build Coastguard Worker mProxy->interrupt();
1742*ec779b8eSAndroid Build Coastguard Worker }
1743*ec779b8eSAndroid Build Coastguard Worker } else {
1744*ec779b8eSAndroid Build Coastguard Worker // if the track is idle, try to restore now and
1745*ec779b8eSAndroid Build Coastguard Worker // defer to next start if not possible
1746*ec779b8eSAndroid Build Coastguard Worker if (restoreTrack_l("setOutputDevice") != OK) {
1747*ec779b8eSAndroid Build Coastguard Worker android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
1748*ec779b8eSAndroid Build Coastguard Worker }
1749*ec779b8eSAndroid Build Coastguard Worker }
1750*ec779b8eSAndroid Build Coastguard Worker }
1751*ec779b8eSAndroid Build Coastguard Worker }
1752*ec779b8eSAndroid Build Coastguard Worker }
1753*ec779b8eSAndroid Build Coastguard Worker return result;
1754*ec779b8eSAndroid Build Coastguard Worker }
1755*ec779b8eSAndroid Build Coastguard Worker
getOutputDevice()1756*ec779b8eSAndroid Build Coastguard Worker audio_port_handle_t AudioTrack::getOutputDevice() {
1757*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
1758*ec779b8eSAndroid Build Coastguard Worker return mSelectedDeviceId;
1759*ec779b8eSAndroid Build Coastguard Worker }
1760*ec779b8eSAndroid Build Coastguard Worker
1761*ec779b8eSAndroid Build Coastguard Worker // must be called with mLock held
updateRoutedDeviceIds_l()1762*ec779b8eSAndroid Build Coastguard Worker void AudioTrack::updateRoutedDeviceIds_l()
1763*ec779b8eSAndroid Build Coastguard Worker {
1764*ec779b8eSAndroid Build Coastguard Worker // if the track is inactive, do not update actual device as the output stream maybe routed
1765*ec779b8eSAndroid Build Coastguard Worker // to a device not relevant to this client because of other active use cases.
1766*ec779b8eSAndroid Build Coastguard Worker if (mState != STATE_ACTIVE) {
1767*ec779b8eSAndroid Build Coastguard Worker return;
1768*ec779b8eSAndroid Build Coastguard Worker }
1769*ec779b8eSAndroid Build Coastguard Worker if (mOutput != AUDIO_IO_HANDLE_NONE) {
1770*ec779b8eSAndroid Build Coastguard Worker DeviceIdVector deviceIds;
1771*ec779b8eSAndroid Build Coastguard Worker status_t result = AudioSystem::getDeviceIdsForIo(mOutput, deviceIds);
1772*ec779b8eSAndroid Build Coastguard Worker if (result != OK) {
1773*ec779b8eSAndroid Build Coastguard Worker ALOGW("%s: getDeviceIdsForIo returned: %d", __func__, result);
1774*ec779b8eSAndroid Build Coastguard Worker }
1775*ec779b8eSAndroid Build Coastguard Worker if (!deviceIds.empty()) {
1776*ec779b8eSAndroid Build Coastguard Worker mRoutedDeviceIds = deviceIds;
1777*ec779b8eSAndroid Build Coastguard Worker }
1778*ec779b8eSAndroid Build Coastguard Worker }
1779*ec779b8eSAndroid Build Coastguard Worker }
1780*ec779b8eSAndroid Build Coastguard Worker
getRoutedDeviceIds()1781*ec779b8eSAndroid Build Coastguard Worker DeviceIdVector AudioTrack::getRoutedDeviceIds() {
1782*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
1783*ec779b8eSAndroid Build Coastguard Worker updateRoutedDeviceIds_l();
1784*ec779b8eSAndroid Build Coastguard Worker return mRoutedDeviceIds;
1785*ec779b8eSAndroid Build Coastguard Worker }
1786*ec779b8eSAndroid Build Coastguard Worker
attachAuxEffect(int effectId)1787*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::attachAuxEffect(int effectId)
1788*ec779b8eSAndroid Build Coastguard Worker {
1789*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
1790*ec779b8eSAndroid Build Coastguard Worker status_t status;
1791*ec779b8eSAndroid Build Coastguard Worker mAudioTrack->attachAuxEffect(effectId, &status);
1792*ec779b8eSAndroid Build Coastguard Worker if (status == NO_ERROR) {
1793*ec779b8eSAndroid Build Coastguard Worker mAuxEffectId = effectId;
1794*ec779b8eSAndroid Build Coastguard Worker }
1795*ec779b8eSAndroid Build Coastguard Worker return status;
1796*ec779b8eSAndroid Build Coastguard Worker }
1797*ec779b8eSAndroid Build Coastguard Worker
streamType() const1798*ec779b8eSAndroid Build Coastguard Worker audio_stream_type_t AudioTrack::streamType() const
1799*ec779b8eSAndroid Build Coastguard Worker {
1800*ec779b8eSAndroid Build Coastguard Worker return mStreamType;
1801*ec779b8eSAndroid Build Coastguard Worker }
1802*ec779b8eSAndroid Build Coastguard Worker
latency()1803*ec779b8eSAndroid Build Coastguard Worker uint32_t AudioTrack::latency()
1804*ec779b8eSAndroid Build Coastguard Worker {
1805*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
1806*ec779b8eSAndroid Build Coastguard Worker updateLatency_l();
1807*ec779b8eSAndroid Build Coastguard Worker return mLatency;
1808*ec779b8eSAndroid Build Coastguard Worker }
1809*ec779b8eSAndroid Build Coastguard Worker
1810*ec779b8eSAndroid Build Coastguard Worker // -------------------------------------------------------------------------
1811*ec779b8eSAndroid Build Coastguard Worker
1812*ec779b8eSAndroid Build Coastguard Worker // must be called with mLock held
updateLatency_l()1813*ec779b8eSAndroid Build Coastguard Worker void AudioTrack::updateLatency_l()
1814*ec779b8eSAndroid Build Coastguard Worker {
1815*ec779b8eSAndroid Build Coastguard Worker status_t status = AudioSystem::getLatency(mOutput, &mAfLatency);
1816*ec779b8eSAndroid Build Coastguard Worker if (status != NO_ERROR) {
1817*ec779b8eSAndroid Build Coastguard Worker ALOGW("%s(%d): getLatency(%d) failed status %d", __func__, mPortId, mOutput, status);
1818*ec779b8eSAndroid Build Coastguard Worker } else {
1819*ec779b8eSAndroid Build Coastguard Worker // FIXME don't believe this lie
1820*ec779b8eSAndroid Build Coastguard Worker mLatency = mAfLatency + (1000LL * mFrameCount) / mSampleRate;
1821*ec779b8eSAndroid Build Coastguard Worker }
1822*ec779b8eSAndroid Build Coastguard Worker }
1823*ec779b8eSAndroid Build Coastguard Worker
1824*ec779b8eSAndroid Build Coastguard Worker // TODO Move this macro to a common header file for enum to string conversion in audio framework.
1825*ec779b8eSAndroid Build Coastguard Worker #define MEDIA_CASE_ENUM(name) case name: return #name
convertTransferToText(transfer_type transferType)1826*ec779b8eSAndroid Build Coastguard Worker const char * AudioTrack::convertTransferToText(transfer_type transferType) {
1827*ec779b8eSAndroid Build Coastguard Worker switch (transferType) {
1828*ec779b8eSAndroid Build Coastguard Worker MEDIA_CASE_ENUM(TRANSFER_DEFAULT);
1829*ec779b8eSAndroid Build Coastguard Worker MEDIA_CASE_ENUM(TRANSFER_CALLBACK);
1830*ec779b8eSAndroid Build Coastguard Worker MEDIA_CASE_ENUM(TRANSFER_OBTAIN);
1831*ec779b8eSAndroid Build Coastguard Worker MEDIA_CASE_ENUM(TRANSFER_SYNC);
1832*ec779b8eSAndroid Build Coastguard Worker MEDIA_CASE_ENUM(TRANSFER_SHARED);
1833*ec779b8eSAndroid Build Coastguard Worker MEDIA_CASE_ENUM(TRANSFER_SYNC_NOTIF_CALLBACK);
1834*ec779b8eSAndroid Build Coastguard Worker default:
1835*ec779b8eSAndroid Build Coastguard Worker return "UNRECOGNIZED";
1836*ec779b8eSAndroid Build Coastguard Worker }
1837*ec779b8eSAndroid Build Coastguard Worker }
1838*ec779b8eSAndroid Build Coastguard Worker
createTrack_l()1839*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::createTrack_l()
1840*ec779b8eSAndroid Build Coastguard Worker {
1841*ec779b8eSAndroid Build Coastguard Worker status_t status;
1842*ec779b8eSAndroid Build Coastguard Worker
1843*ec779b8eSAndroid Build Coastguard Worker const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
1844*ec779b8eSAndroid Build Coastguard Worker if (audioFlinger == 0) {
1845*ec779b8eSAndroid Build Coastguard Worker return logIfErrorAndReturnStatus(
1846*ec779b8eSAndroid Build Coastguard Worker DEAD_OBJECT, StringPrintf("%s(%d): Could not get audioflinger", __func__, mPortId));
1847*ec779b8eSAndroid Build Coastguard Worker }
1848*ec779b8eSAndroid Build Coastguard Worker
1849*ec779b8eSAndroid Build Coastguard Worker {
1850*ec779b8eSAndroid Build Coastguard Worker // mFlags (not mOrigFlags) is modified depending on whether fast request is accepted.
1851*ec779b8eSAndroid Build Coastguard Worker // After fast request is denied, we will request again if IAudioTrack is re-created.
1852*ec779b8eSAndroid Build Coastguard Worker // Client can only express a preference for FAST. Server will perform additional tests.
1853*ec779b8eSAndroid Build Coastguard Worker if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
1854*ec779b8eSAndroid Build Coastguard Worker // either of these use cases:
1855*ec779b8eSAndroid Build Coastguard Worker // use case 1: shared buffer
1856*ec779b8eSAndroid Build Coastguard Worker bool sharedBuffer = mSharedBuffer != 0;
1857*ec779b8eSAndroid Build Coastguard Worker bool transferAllowed =
1858*ec779b8eSAndroid Build Coastguard Worker // use case 2: callback transfer mode
1859*ec779b8eSAndroid Build Coastguard Worker (mTransfer == TRANSFER_CALLBACK) ||
1860*ec779b8eSAndroid Build Coastguard Worker // use case 3: obtain/release mode
1861*ec779b8eSAndroid Build Coastguard Worker (mTransfer == TRANSFER_OBTAIN) ||
1862*ec779b8eSAndroid Build Coastguard Worker // use case 4: synchronous write
1863*ec779b8eSAndroid Build Coastguard Worker ((mTransfer == TRANSFER_SYNC || mTransfer == TRANSFER_SYNC_NOTIF_CALLBACK)
1864*ec779b8eSAndroid Build Coastguard Worker && mThreadCanCallJava);
1865*ec779b8eSAndroid Build Coastguard Worker
1866*ec779b8eSAndroid Build Coastguard Worker bool fastAllowed = sharedBuffer || transferAllowed;
1867*ec779b8eSAndroid Build Coastguard Worker if (!fastAllowed) {
1868*ec779b8eSAndroid Build Coastguard Worker ALOGW("%s(%d): AUDIO_OUTPUT_FLAG_FAST denied by client,"
1869*ec779b8eSAndroid Build Coastguard Worker " not shared buffer and transfer = %s",
1870*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId,
1871*ec779b8eSAndroid Build Coastguard Worker convertTransferToText(mTransfer));
1872*ec779b8eSAndroid Build Coastguard Worker mFlags = (audio_output_flags_t) (mFlags & ~AUDIO_OUTPUT_FLAG_FAST);
1873*ec779b8eSAndroid Build Coastguard Worker }
1874*ec779b8eSAndroid Build Coastguard Worker }
1875*ec779b8eSAndroid Build Coastguard Worker
1876*ec779b8eSAndroid Build Coastguard Worker IAudioFlinger::CreateTrackInput input;
1877*ec779b8eSAndroid Build Coastguard Worker if (mOriginalStreamType != AUDIO_STREAM_DEFAULT) {
1878*ec779b8eSAndroid Build Coastguard Worker // Legacy: This is based on original parameters even if the track is recreated.
1879*ec779b8eSAndroid Build Coastguard Worker input.attr = AudioSystem::streamTypeToAttributes(mOriginalStreamType);
1880*ec779b8eSAndroid Build Coastguard Worker } else {
1881*ec779b8eSAndroid Build Coastguard Worker input.attr = mAttributes;
1882*ec779b8eSAndroid Build Coastguard Worker }
1883*ec779b8eSAndroid Build Coastguard Worker input.config = AUDIO_CONFIG_INITIALIZER;
1884*ec779b8eSAndroid Build Coastguard Worker input.config.sample_rate = mSampleRate;
1885*ec779b8eSAndroid Build Coastguard Worker input.config.channel_mask = mChannelMask;
1886*ec779b8eSAndroid Build Coastguard Worker input.config.format = mFormat;
1887*ec779b8eSAndroid Build Coastguard Worker input.config.offload_info = mOffloadInfoCopy;
1888*ec779b8eSAndroid Build Coastguard Worker input.clientInfo.attributionSource = mClientAttributionSource;
1889*ec779b8eSAndroid Build Coastguard Worker input.clientInfo.clientTid = -1;
1890*ec779b8eSAndroid Build Coastguard Worker if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
1891*ec779b8eSAndroid Build Coastguard Worker // It is currently meaningless to request SCHED_FIFO for a Java thread. Even if the
1892*ec779b8eSAndroid Build Coastguard Worker // application-level code follows all non-blocking design rules, the language runtime
1893*ec779b8eSAndroid Build Coastguard Worker // doesn't also follow those rules, so the thread will not benefit overall.
1894*ec779b8eSAndroid Build Coastguard Worker if (mAudioTrackThread != 0 && !mThreadCanCallJava) {
1895*ec779b8eSAndroid Build Coastguard Worker input.clientInfo.clientTid = mAudioTrackThread->getTid();
1896*ec779b8eSAndroid Build Coastguard Worker }
1897*ec779b8eSAndroid Build Coastguard Worker }
1898*ec779b8eSAndroid Build Coastguard Worker input.sharedBuffer = mSharedBuffer;
1899*ec779b8eSAndroid Build Coastguard Worker input.notificationsPerBuffer = mNotificationsPerBufferReq;
1900*ec779b8eSAndroid Build Coastguard Worker input.speed = 1.0;
1901*ec779b8eSAndroid Build Coastguard Worker if (audio_has_proportional_frames(mFormat) && mSharedBuffer == 0 &&
1902*ec779b8eSAndroid Build Coastguard Worker (mFlags & AUDIO_OUTPUT_FLAG_FAST) == 0) {
1903*ec779b8eSAndroid Build Coastguard Worker input.speed = !isPurePcmData_l() || isOffloadedOrDirect_l() ? 1.0f :
1904*ec779b8eSAndroid Build Coastguard Worker max(mMaxRequiredSpeed, mPlaybackRate.mSpeed);
1905*ec779b8eSAndroid Build Coastguard Worker }
1906*ec779b8eSAndroid Build Coastguard Worker input.flags = mFlags;
1907*ec779b8eSAndroid Build Coastguard Worker input.frameCount = mReqFrameCount;
1908*ec779b8eSAndroid Build Coastguard Worker input.notificationFrameCount = mNotificationFramesReq;
1909*ec779b8eSAndroid Build Coastguard Worker input.selectedDeviceId = mSelectedDeviceId;
1910*ec779b8eSAndroid Build Coastguard Worker input.sessionId = mSessionId;
1911*ec779b8eSAndroid Build Coastguard Worker input.audioTrackCallback = mAudioTrackCallback;
1912*ec779b8eSAndroid Build Coastguard Worker
1913*ec779b8eSAndroid Build Coastguard Worker media::CreateTrackResponse response;
1914*ec779b8eSAndroid Build Coastguard Worker auto aidlInput = input.toAidl();
1915*ec779b8eSAndroid Build Coastguard Worker if (!aidlInput.ok()) {
1916*ec779b8eSAndroid Build Coastguard Worker return logIfErrorAndReturnStatus(
1917*ec779b8eSAndroid Build Coastguard Worker BAD_VALUE, StringPrintf("%s(%d): Could not create track due to invalid input",
1918*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId));
1919*ec779b8eSAndroid Build Coastguard Worker }
1920*ec779b8eSAndroid Build Coastguard Worker status = audioFlinger->createTrack(aidlInput.value(), response);
1921*ec779b8eSAndroid Build Coastguard Worker
1922*ec779b8eSAndroid Build Coastguard Worker IAudioFlinger::CreateTrackOutput output{};
1923*ec779b8eSAndroid Build Coastguard Worker if (status == NO_ERROR) {
1924*ec779b8eSAndroid Build Coastguard Worker auto trackOutput = IAudioFlinger::CreateTrackOutput::fromAidl(response);
1925*ec779b8eSAndroid Build Coastguard Worker if (!trackOutput.ok()) {
1926*ec779b8eSAndroid Build Coastguard Worker return logIfErrorAndReturnStatus(
1927*ec779b8eSAndroid Build Coastguard Worker BAD_VALUE,
1928*ec779b8eSAndroid Build Coastguard Worker StringPrintf("%s(%d): Could not create track output due to invalid response",
1929*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId));
1930*ec779b8eSAndroid Build Coastguard Worker }
1931*ec779b8eSAndroid Build Coastguard Worker output = trackOutput.value();
1932*ec779b8eSAndroid Build Coastguard Worker }
1933*ec779b8eSAndroid Build Coastguard Worker
1934*ec779b8eSAndroid Build Coastguard Worker if (status != NO_ERROR || output.outputId == AUDIO_IO_HANDLE_NONE) {
1935*ec779b8eSAndroid Build Coastguard Worker return logIfErrorAndReturnStatus(
1936*ec779b8eSAndroid Build Coastguard Worker status == NO_ERROR ? INVALID_OPERATION : status, // device not ready
1937*ec779b8eSAndroid Build Coastguard Worker StringPrintf("%s(%d): AudioFlinger could not create track, status: %d output %d",
1938*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId, status, output.outputId));
1939*ec779b8eSAndroid Build Coastguard Worker }
1940*ec779b8eSAndroid Build Coastguard Worker ALOG_ASSERT(output.audioTrack != 0);
1941*ec779b8eSAndroid Build Coastguard Worker
1942*ec779b8eSAndroid Build Coastguard Worker mFrameCount = output.frameCount;
1943*ec779b8eSAndroid Build Coastguard Worker mNotificationFramesAct = (uint32_t)output.notificationFrameCount;
1944*ec779b8eSAndroid Build Coastguard Worker mRoutedDeviceIds = output.selectedDeviceIds;
1945*ec779b8eSAndroid Build Coastguard Worker mSessionId = output.sessionId;
1946*ec779b8eSAndroid Build Coastguard Worker mStreamType = output.streamType;
1947*ec779b8eSAndroid Build Coastguard Worker
1948*ec779b8eSAndroid Build Coastguard Worker mSampleRate = output.sampleRate;
1949*ec779b8eSAndroid Build Coastguard Worker if (mOriginalSampleRate == 0) {
1950*ec779b8eSAndroid Build Coastguard Worker mOriginalSampleRate = mSampleRate;
1951*ec779b8eSAndroid Build Coastguard Worker }
1952*ec779b8eSAndroid Build Coastguard Worker
1953*ec779b8eSAndroid Build Coastguard Worker mAfFrameCount = output.afFrameCount;
1954*ec779b8eSAndroid Build Coastguard Worker mAfSampleRate = output.afSampleRate;
1955*ec779b8eSAndroid Build Coastguard Worker mAfChannelCount = audio_channel_count_from_out_mask(output.afChannelMask);
1956*ec779b8eSAndroid Build Coastguard Worker mAfFormat = output.afFormat;
1957*ec779b8eSAndroid Build Coastguard Worker mAfLatency = output.afLatencyMs;
1958*ec779b8eSAndroid Build Coastguard Worker mAfTrackFlags = output.afTrackFlags;
1959*ec779b8eSAndroid Build Coastguard Worker
1960*ec779b8eSAndroid Build Coastguard Worker mLatency = mAfLatency + (1000LL * mFrameCount) / mSampleRate;
1961*ec779b8eSAndroid Build Coastguard Worker
1962*ec779b8eSAndroid Build Coastguard Worker // AudioFlinger now owns the reference to the I/O handle,
1963*ec779b8eSAndroid Build Coastguard Worker // so we are no longer responsible for releasing it.
1964*ec779b8eSAndroid Build Coastguard Worker
1965*ec779b8eSAndroid Build Coastguard Worker // FIXME compare to AudioRecord
1966*ec779b8eSAndroid Build Coastguard Worker std::optional<media::SharedFileRegion> sfr;
1967*ec779b8eSAndroid Build Coastguard Worker output.audioTrack->getCblk(&sfr);
1968*ec779b8eSAndroid Build Coastguard Worker auto iMemory = aidl2legacy_NullableSharedFileRegion_IMemory(sfr);
1969*ec779b8eSAndroid Build Coastguard Worker if (!iMemory.ok() || iMemory.value() == 0) {
1970*ec779b8eSAndroid Build Coastguard Worker return logIfErrorAndReturnStatus(
1971*ec779b8eSAndroid Build Coastguard Worker FAILED_TRANSACTION,
1972*ec779b8eSAndroid Build Coastguard Worker StringPrintf("%s(%d): Could not get control block", __func__, mPortId));
1973*ec779b8eSAndroid Build Coastguard Worker }
1974*ec779b8eSAndroid Build Coastguard Worker sp<IMemory> iMem = iMemory.value();
1975*ec779b8eSAndroid Build Coastguard Worker // TODO: Using unsecurePointer() has some associated security pitfalls
1976*ec779b8eSAndroid Build Coastguard Worker // (see declaration for details).
1977*ec779b8eSAndroid Build Coastguard Worker // Either document why it is safe in this case or address the
1978*ec779b8eSAndroid Build Coastguard Worker // issue (e.g. by copying).
1979*ec779b8eSAndroid Build Coastguard Worker void *iMemPointer = iMem->unsecurePointer();
1980*ec779b8eSAndroid Build Coastguard Worker if (iMemPointer == NULL) {
1981*ec779b8eSAndroid Build Coastguard Worker return logIfErrorAndReturnStatus(
1982*ec779b8eSAndroid Build Coastguard Worker FAILED_TRANSACTION,
1983*ec779b8eSAndroid Build Coastguard Worker StringPrintf("%s(%d): Could not get control block pointer", __func__, mPortId));
1984*ec779b8eSAndroid Build Coastguard Worker }
1985*ec779b8eSAndroid Build Coastguard Worker // invariant that mAudioTrack != 0 is true only after set() returns successfully
1986*ec779b8eSAndroid Build Coastguard Worker if (mAudioTrack != 0) {
1987*ec779b8eSAndroid Build Coastguard Worker IInterface::asBinder(mAudioTrack)->unlinkToDeath(mDeathNotifier, this);
1988*ec779b8eSAndroid Build Coastguard Worker mDeathNotifier.clear();
1989*ec779b8eSAndroid Build Coastguard Worker }
1990*ec779b8eSAndroid Build Coastguard Worker mAudioTrack = output.audioTrack;
1991*ec779b8eSAndroid Build Coastguard Worker mCblkMemory = iMem;
1992*ec779b8eSAndroid Build Coastguard Worker IPCThreadState::self()->flushCommands();
1993*ec779b8eSAndroid Build Coastguard Worker
1994*ec779b8eSAndroid Build Coastguard Worker audio_track_cblk_t* cblk = static_cast<audio_track_cblk_t*>(iMemPointer);
1995*ec779b8eSAndroid Build Coastguard Worker mCblk = cblk;
1996*ec779b8eSAndroid Build Coastguard Worker
1997*ec779b8eSAndroid Build Coastguard Worker mAwaitBoost = false;
1998*ec779b8eSAndroid Build Coastguard Worker if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
1999*ec779b8eSAndroid Build Coastguard Worker if (output.flags & AUDIO_OUTPUT_FLAG_FAST) {
2000*ec779b8eSAndroid Build Coastguard Worker ALOGI("%s(%d): AUDIO_OUTPUT_FLAG_FAST successful; frameCount %zu -> %zu",
2001*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId, mReqFrameCount, mFrameCount);
2002*ec779b8eSAndroid Build Coastguard Worker if (!mThreadCanCallJava) {
2003*ec779b8eSAndroid Build Coastguard Worker mAwaitBoost = true;
2004*ec779b8eSAndroid Build Coastguard Worker }
2005*ec779b8eSAndroid Build Coastguard Worker } else {
2006*ec779b8eSAndroid Build Coastguard Worker ALOGV("%s(%d): AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount %zu -> %zu",
2007*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId, mReqFrameCount, mFrameCount);
2008*ec779b8eSAndroid Build Coastguard Worker }
2009*ec779b8eSAndroid Build Coastguard Worker }
2010*ec779b8eSAndroid Build Coastguard Worker mFlags = output.flags;
2011*ec779b8eSAndroid Build Coastguard Worker
2012*ec779b8eSAndroid Build Coastguard Worker //mOutput != output includes the case where mOutput == AUDIO_IO_HANDLE_NONE for first creation
2013*ec779b8eSAndroid Build Coastguard Worker if (mDeviceCallback != 0) {
2014*ec779b8eSAndroid Build Coastguard Worker if (mOutput != AUDIO_IO_HANDLE_NONE) {
2015*ec779b8eSAndroid Build Coastguard Worker AudioSystem::removeAudioDeviceCallback(this, mOutput, mPortId);
2016*ec779b8eSAndroid Build Coastguard Worker }
2017*ec779b8eSAndroid Build Coastguard Worker AudioSystem::addAudioDeviceCallback(this, output.outputId, output.portId);
2018*ec779b8eSAndroid Build Coastguard Worker }
2019*ec779b8eSAndroid Build Coastguard Worker
2020*ec779b8eSAndroid Build Coastguard Worker mPortId = output.portId;
2021*ec779b8eSAndroid Build Coastguard Worker // notify the upper layers about the new portId
2022*ec779b8eSAndroid Build Coastguard Worker triggerPortIdUpdate_l();
2023*ec779b8eSAndroid Build Coastguard Worker
2024*ec779b8eSAndroid Build Coastguard Worker // We retain a copy of the I/O handle, but don't own the reference
2025*ec779b8eSAndroid Build Coastguard Worker mOutput = output.outputId;
2026*ec779b8eSAndroid Build Coastguard Worker mRefreshRemaining = true;
2027*ec779b8eSAndroid Build Coastguard Worker
2028*ec779b8eSAndroid Build Coastguard Worker // Starting address of buffers in shared memory. If there is a shared buffer, buffers
2029*ec779b8eSAndroid Build Coastguard Worker // is the value of pointer() for the shared buffer, otherwise buffers points
2030*ec779b8eSAndroid Build Coastguard Worker // immediately after the control block. This address is for the mapping within client
2031*ec779b8eSAndroid Build Coastguard Worker // address space. AudioFlinger::TrackBase::mBuffer is for the server address space.
2032*ec779b8eSAndroid Build Coastguard Worker void* buffers;
2033*ec779b8eSAndroid Build Coastguard Worker if (mSharedBuffer == 0) {
2034*ec779b8eSAndroid Build Coastguard Worker buffers = cblk + 1;
2035*ec779b8eSAndroid Build Coastguard Worker } else {
2036*ec779b8eSAndroid Build Coastguard Worker // TODO: Using unsecurePointer() has some associated security pitfalls
2037*ec779b8eSAndroid Build Coastguard Worker // (see declaration for details).
2038*ec779b8eSAndroid Build Coastguard Worker // Either document why it is safe in this case or address the
2039*ec779b8eSAndroid Build Coastguard Worker // issue (e.g. by copying).
2040*ec779b8eSAndroid Build Coastguard Worker buffers = mSharedBuffer->unsecurePointer();
2041*ec779b8eSAndroid Build Coastguard Worker if (buffers == NULL) {
2042*ec779b8eSAndroid Build Coastguard Worker return logIfErrorAndReturnStatus(
2043*ec779b8eSAndroid Build Coastguard Worker FAILED_TRANSACTION,
2044*ec779b8eSAndroid Build Coastguard Worker StringPrintf("%s(%d): Could not get buffer pointer", __func__, mPortId));
2045*ec779b8eSAndroid Build Coastguard Worker }
2046*ec779b8eSAndroid Build Coastguard Worker }
2047*ec779b8eSAndroid Build Coastguard Worker
2048*ec779b8eSAndroid Build Coastguard Worker mAudioTrack->attachAuxEffect(mAuxEffectId, &status);
2049*ec779b8eSAndroid Build Coastguard Worker
2050*ec779b8eSAndroid Build Coastguard Worker // If IAudioTrack is re-created, don't let the requested frameCount
2051*ec779b8eSAndroid Build Coastguard Worker // decrease. This can confuse clients that cache frameCount().
2052*ec779b8eSAndroid Build Coastguard Worker if (mFrameCount > mReqFrameCount) {
2053*ec779b8eSAndroid Build Coastguard Worker mReqFrameCount = mFrameCount;
2054*ec779b8eSAndroid Build Coastguard Worker }
2055*ec779b8eSAndroid Build Coastguard Worker
2056*ec779b8eSAndroid Build Coastguard Worker // reset server position to 0 as we have new cblk.
2057*ec779b8eSAndroid Build Coastguard Worker mServer = 0;
2058*ec779b8eSAndroid Build Coastguard Worker
2059*ec779b8eSAndroid Build Coastguard Worker // update proxy
2060*ec779b8eSAndroid Build Coastguard Worker if (mSharedBuffer == 0) {
2061*ec779b8eSAndroid Build Coastguard Worker mStaticProxy.clear();
2062*ec779b8eSAndroid Build Coastguard Worker mProxy = new AudioTrackClientProxy(cblk, buffers, mFrameCount, mFrameSize);
2063*ec779b8eSAndroid Build Coastguard Worker } else {
2064*ec779b8eSAndroid Build Coastguard Worker mStaticProxy = new StaticAudioTrackClientProxy(cblk, buffers, mFrameCount, mFrameSize);
2065*ec779b8eSAndroid Build Coastguard Worker mProxy = mStaticProxy;
2066*ec779b8eSAndroid Build Coastguard Worker }
2067*ec779b8eSAndroid Build Coastguard Worker
2068*ec779b8eSAndroid Build Coastguard Worker mProxy->setVolumeLR(gain_minifloat_pack(
2069*ec779b8eSAndroid Build Coastguard Worker gain_from_float(mVolume[AUDIO_INTERLEAVE_LEFT]),
2070*ec779b8eSAndroid Build Coastguard Worker gain_from_float(mVolume[AUDIO_INTERLEAVE_RIGHT])));
2071*ec779b8eSAndroid Build Coastguard Worker
2072*ec779b8eSAndroid Build Coastguard Worker mProxy->setSendLevel(mSendLevel);
2073*ec779b8eSAndroid Build Coastguard Worker const uint32_t effectiveSampleRate = adjustSampleRate(mSampleRate, mPlaybackRate.mPitch);
2074*ec779b8eSAndroid Build Coastguard Worker const float effectiveSpeed = adjustSpeed(mPlaybackRate.mSpeed, mPlaybackRate.mPitch);
2075*ec779b8eSAndroid Build Coastguard Worker const float effectivePitch = adjustPitch(mPlaybackRate.mPitch);
2076*ec779b8eSAndroid Build Coastguard Worker mProxy->setSampleRate(effectiveSampleRate);
2077*ec779b8eSAndroid Build Coastguard Worker
2078*ec779b8eSAndroid Build Coastguard Worker AudioPlaybackRate playbackRateTemp = mPlaybackRate;
2079*ec779b8eSAndroid Build Coastguard Worker playbackRateTemp.mSpeed = effectiveSpeed;
2080*ec779b8eSAndroid Build Coastguard Worker playbackRateTemp.mPitch = effectivePitch;
2081*ec779b8eSAndroid Build Coastguard Worker mProxy->setPlaybackRate(playbackRateTemp);
2082*ec779b8eSAndroid Build Coastguard Worker mProxy->setMinimum(mNotificationFramesAct);
2083*ec779b8eSAndroid Build Coastguard Worker
2084*ec779b8eSAndroid Build Coastguard Worker if (mDualMonoMode != AUDIO_DUAL_MONO_MODE_OFF) {
2085*ec779b8eSAndroid Build Coastguard Worker setDualMonoMode_l(mDualMonoMode);
2086*ec779b8eSAndroid Build Coastguard Worker }
2087*ec779b8eSAndroid Build Coastguard Worker if (mAudioDescriptionMixLeveldB != -std::numeric_limits<float>::infinity()) {
2088*ec779b8eSAndroid Build Coastguard Worker setAudioDescriptionMixLevel_l(mAudioDescriptionMixLeveldB);
2089*ec779b8eSAndroid Build Coastguard Worker }
2090*ec779b8eSAndroid Build Coastguard Worker
2091*ec779b8eSAndroid Build Coastguard Worker mDeathNotifier = new DeathNotifier(this);
2092*ec779b8eSAndroid Build Coastguard Worker IInterface::asBinder(mAudioTrack)->linkToDeath(mDeathNotifier, this);
2093*ec779b8eSAndroid Build Coastguard Worker
2094*ec779b8eSAndroid Build Coastguard Worker // This is the first log sent from the AudioTrack client.
2095*ec779b8eSAndroid Build Coastguard Worker // The creation of the audio track by AudioFlinger (in the code above)
2096*ec779b8eSAndroid Build Coastguard Worker // is the first log of the AudioTrack and must be present before
2097*ec779b8eSAndroid Build Coastguard Worker // any AudioTrack client logs will be accepted.
2098*ec779b8eSAndroid Build Coastguard Worker
2099*ec779b8eSAndroid Build Coastguard Worker mMetricsId = std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK) + std::to_string(mPortId);
2100*ec779b8eSAndroid Build Coastguard Worker mediametrics::LogItem(mMetricsId)
2101*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE)
2102*ec779b8eSAndroid Build Coastguard Worker // the following are immutable
2103*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_FLAGS, toString(mFlags).c_str())
2104*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_ORIGINALFLAGS, toString(mOrigFlags).c_str())
2105*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_SESSIONID, (int32_t)mSessionId)
2106*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_LOGSESSIONID, mLogSessionId)
2107*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_PLAYERIID, mPlayerIId)
2108*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_TRACKID, mPortId) // dup from key
2109*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_CONTENTTYPE, toString(mAttributes.content_type).c_str())
2110*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_USAGE, toString(mAttributes.usage).c_str())
2111*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_THREADID, (int32_t)output.outputId)
2112*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_SELECTEDDEVICEID, (int32_t)mSelectedDeviceId)
2113*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_ROUTEDDEVICEID, (int32_t)(getFirstDeviceId(mRoutedDeviceIds)))
2114*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_ROUTEDDEVICEIDS, toString(mRoutedDeviceIds).c_str())
2115*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_ENCODING, toString(mFormat).c_str())
2116*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_CHANNELMASK, (int32_t)mChannelMask)
2117*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_FRAMECOUNT, (int32_t)mFrameCount)
2118*ec779b8eSAndroid Build Coastguard Worker // the following are NOT immutable
2119*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_VOLUME_LEFT, (double)mVolume[AUDIO_INTERLEAVE_LEFT])
2120*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_VOLUME_RIGHT, (double)mVolume[AUDIO_INTERLEAVE_RIGHT])
2121*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
2122*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)NO_ERROR)
2123*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_AUXEFFECTID, (int32_t)mAuxEffectId)
2124*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_SAMPLERATE, (int32_t)mSampleRate)
2125*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_PLAYBACK_SPEED, (double)mPlaybackRate.mSpeed)
2126*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_PLAYBACK_PITCH, (double)mPlaybackRate.mPitch)
2127*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_PREFIX_EFFECTIVE
2128*ec779b8eSAndroid Build Coastguard Worker AMEDIAMETRICS_PROP_SAMPLERATE, (int32_t)effectiveSampleRate)
2129*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_PREFIX_EFFECTIVE
2130*ec779b8eSAndroid Build Coastguard Worker AMEDIAMETRICS_PROP_PLAYBACK_SPEED, (double)effectiveSpeed)
2131*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_PREFIX_EFFECTIVE
2132*ec779b8eSAndroid Build Coastguard Worker AMEDIAMETRICS_PROP_PLAYBACK_PITCH, (double)effectivePitch)
2133*ec779b8eSAndroid Build Coastguard Worker .record();
2134*ec779b8eSAndroid Build Coastguard Worker
2135*ec779b8eSAndroid Build Coastguard Worker // mSendLevel
2136*ec779b8eSAndroid Build Coastguard Worker // mReqFrameCount?
2137*ec779b8eSAndroid Build Coastguard Worker // mNotificationFramesAct, mNotificationFramesReq, mNotificationsPerBufferReq
2138*ec779b8eSAndroid Build Coastguard Worker // mLatency, mAfLatency, mAfFrameCount, mAfSampleRate
2139*ec779b8eSAndroid Build Coastguard Worker
2140*ec779b8eSAndroid Build Coastguard Worker }
2141*ec779b8eSAndroid Build Coastguard Worker
2142*ec779b8eSAndroid Build Coastguard Worker // sp<IAudioTrack> track destructor will cause releaseOutput() to be called by AudioFlinger
2143*ec779b8eSAndroid Build Coastguard Worker return logIfErrorAndReturnStatus(status, "");
2144*ec779b8eSAndroid Build Coastguard Worker }
2145*ec779b8eSAndroid Build Coastguard Worker
reportError(status_t status,const char * event,const char * message) const2146*ec779b8eSAndroid Build Coastguard Worker void AudioTrack::reportError(status_t status, const char *event, const char *message) const
2147*ec779b8eSAndroid Build Coastguard Worker {
2148*ec779b8eSAndroid Build Coastguard Worker if (status == NO_ERROR) return;
2149*ec779b8eSAndroid Build Coastguard Worker // We report error on the native side because some callers do not come
2150*ec779b8eSAndroid Build Coastguard Worker // from Java.
2151*ec779b8eSAndroid Build Coastguard Worker // Ensure these variables are initialized in set().
2152*ec779b8eSAndroid Build Coastguard Worker mediametrics::LogItem(AMEDIAMETRICS_KEY_AUDIO_TRACK_ERROR)
2153*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_EVENT, event)
2154*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)status)
2155*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_STATUSMESSAGE, message)
2156*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_ORIGINALFLAGS, toString(mOrigFlags).c_str())
2157*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_SESSIONID, (int32_t)mSessionId)
2158*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_CONTENTTYPE, toString(mAttributes.content_type).c_str())
2159*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_USAGE, toString(mAttributes.usage).c_str())
2160*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_SELECTEDDEVICEID, (int32_t)mSelectedDeviceId)
2161*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_ENCODING, toString(mFormat).c_str())
2162*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_CHANNELMASK, (int32_t)mChannelMask)
2163*ec779b8eSAndroid Build Coastguard Worker // the following are NOT immutable
2164*ec779b8eSAndroid Build Coastguard Worker // frame count is initially the requested frame count, but may be adjusted
2165*ec779b8eSAndroid Build Coastguard Worker // by AudioFlinger after creation.
2166*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_FRAMECOUNT, (int32_t)mFrameCount)
2167*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_SAMPLERATE, (int32_t)mSampleRate)
2168*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_PLAYBACK_SPEED, (double)mPlaybackRate.mSpeed)
2169*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_PLAYBACK_PITCH, (double)mPlaybackRate.mPitch)
2170*ec779b8eSAndroid Build Coastguard Worker .record();
2171*ec779b8eSAndroid Build Coastguard Worker }
2172*ec779b8eSAndroid Build Coastguard Worker
obtainBuffer(Buffer * audioBuffer,int32_t waitCount,size_t * nonContig)2173*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount, size_t *nonContig)
2174*ec779b8eSAndroid Build Coastguard Worker {
2175*ec779b8eSAndroid Build Coastguard Worker if (audioBuffer == NULL) {
2176*ec779b8eSAndroid Build Coastguard Worker if (nonContig != NULL) {
2177*ec779b8eSAndroid Build Coastguard Worker *nonContig = 0;
2178*ec779b8eSAndroid Build Coastguard Worker }
2179*ec779b8eSAndroid Build Coastguard Worker return BAD_VALUE;
2180*ec779b8eSAndroid Build Coastguard Worker }
2181*ec779b8eSAndroid Build Coastguard Worker if (mTransfer != TRANSFER_OBTAIN) {
2182*ec779b8eSAndroid Build Coastguard Worker audioBuffer->frameCount = 0;
2183*ec779b8eSAndroid Build Coastguard Worker audioBuffer->mSize = 0;
2184*ec779b8eSAndroid Build Coastguard Worker audioBuffer->raw = NULL;
2185*ec779b8eSAndroid Build Coastguard Worker if (nonContig != NULL) {
2186*ec779b8eSAndroid Build Coastguard Worker *nonContig = 0;
2187*ec779b8eSAndroid Build Coastguard Worker }
2188*ec779b8eSAndroid Build Coastguard Worker return INVALID_OPERATION;
2189*ec779b8eSAndroid Build Coastguard Worker }
2190*ec779b8eSAndroid Build Coastguard Worker
2191*ec779b8eSAndroid Build Coastguard Worker const struct timespec *requested;
2192*ec779b8eSAndroid Build Coastguard Worker struct timespec timeout;
2193*ec779b8eSAndroid Build Coastguard Worker if (waitCount == -1) {
2194*ec779b8eSAndroid Build Coastguard Worker requested = &ClientProxy::kForever;
2195*ec779b8eSAndroid Build Coastguard Worker } else if (waitCount == 0) {
2196*ec779b8eSAndroid Build Coastguard Worker requested = &ClientProxy::kNonBlocking;
2197*ec779b8eSAndroid Build Coastguard Worker } else if (waitCount > 0) {
2198*ec779b8eSAndroid Build Coastguard Worker time_t ms = WAIT_PERIOD_MS * (time_t) waitCount;
2199*ec779b8eSAndroid Build Coastguard Worker timeout.tv_sec = ms / 1000;
2200*ec779b8eSAndroid Build Coastguard Worker timeout.tv_nsec = (ms % 1000) * 1000000;
2201*ec779b8eSAndroid Build Coastguard Worker requested = &timeout;
2202*ec779b8eSAndroid Build Coastguard Worker } else {
2203*ec779b8eSAndroid Build Coastguard Worker ALOGE("%s(%d): invalid waitCount %d", __func__, mPortId, waitCount);
2204*ec779b8eSAndroid Build Coastguard Worker requested = NULL;
2205*ec779b8eSAndroid Build Coastguard Worker }
2206*ec779b8eSAndroid Build Coastguard Worker return obtainBuffer(audioBuffer, requested, NULL /*elapsed*/, nonContig);
2207*ec779b8eSAndroid Build Coastguard Worker }
2208*ec779b8eSAndroid Build Coastguard Worker
obtainBuffer(Buffer * audioBuffer,const struct timespec * requested,struct timespec * elapsed,size_t * nonContig)2209*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, const struct timespec *requested,
2210*ec779b8eSAndroid Build Coastguard Worker struct timespec *elapsed, size_t *nonContig)
2211*ec779b8eSAndroid Build Coastguard Worker {
2212*ec779b8eSAndroid Build Coastguard Worker // previous and new IAudioTrack sequence numbers are used to detect track re-creation
2213*ec779b8eSAndroid Build Coastguard Worker uint32_t oldSequence = 0;
2214*ec779b8eSAndroid Build Coastguard Worker
2215*ec779b8eSAndroid Build Coastguard Worker Proxy::Buffer buffer;
2216*ec779b8eSAndroid Build Coastguard Worker status_t status = NO_ERROR;
2217*ec779b8eSAndroid Build Coastguard Worker
2218*ec779b8eSAndroid Build Coastguard Worker static const int32_t kMaxTries = 5;
2219*ec779b8eSAndroid Build Coastguard Worker int32_t tryCounter = kMaxTries;
2220*ec779b8eSAndroid Build Coastguard Worker
2221*ec779b8eSAndroid Build Coastguard Worker do {
2222*ec779b8eSAndroid Build Coastguard Worker // obtainBuffer() is called with mutex unlocked, so keep extra references to these fields to
2223*ec779b8eSAndroid Build Coastguard Worker // keep them from going away if another thread re-creates the track during obtainBuffer()
2224*ec779b8eSAndroid Build Coastguard Worker sp<AudioTrackClientProxy> proxy;
2225*ec779b8eSAndroid Build Coastguard Worker
2226*ec779b8eSAndroid Build Coastguard Worker { // start of lock scope
2227*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
2228*ec779b8eSAndroid Build Coastguard Worker
2229*ec779b8eSAndroid Build Coastguard Worker // did previous obtainBuffer() fail due to media server death or voluntary invalidation?
2230*ec779b8eSAndroid Build Coastguard Worker if (status == DEAD_OBJECT) {
2231*ec779b8eSAndroid Build Coastguard Worker // re-create track, unless someone else has already done so
2232*ec779b8eSAndroid Build Coastguard Worker if (mSequence == oldSequence) {
2233*ec779b8eSAndroid Build Coastguard Worker status = restoreTrack_l("obtainBuffer");
2234*ec779b8eSAndroid Build Coastguard Worker if (status != NO_ERROR) {
2235*ec779b8eSAndroid Build Coastguard Worker buffer.mFrameCount = 0;
2236*ec779b8eSAndroid Build Coastguard Worker buffer.mRaw = NULL;
2237*ec779b8eSAndroid Build Coastguard Worker buffer.mNonContig = 0;
2238*ec779b8eSAndroid Build Coastguard Worker break;
2239*ec779b8eSAndroid Build Coastguard Worker }
2240*ec779b8eSAndroid Build Coastguard Worker }
2241*ec779b8eSAndroid Build Coastguard Worker }
2242*ec779b8eSAndroid Build Coastguard Worker oldSequence = mSequence;
2243*ec779b8eSAndroid Build Coastguard Worker
2244*ec779b8eSAndroid Build Coastguard Worker if (status == NOT_ENOUGH_DATA) {
2245*ec779b8eSAndroid Build Coastguard Worker restartIfDisabled();
2246*ec779b8eSAndroid Build Coastguard Worker }
2247*ec779b8eSAndroid Build Coastguard Worker
2248*ec779b8eSAndroid Build Coastguard Worker // Keep the extra references
2249*ec779b8eSAndroid Build Coastguard Worker mProxyObtainBufferRef = mProxy;
2250*ec779b8eSAndroid Build Coastguard Worker proxy = mProxy;
2251*ec779b8eSAndroid Build Coastguard Worker mCblkMemoryObtainBufferRef = mCblkMemory;
2252*ec779b8eSAndroid Build Coastguard Worker
2253*ec779b8eSAndroid Build Coastguard Worker if (mState == STATE_STOPPING) {
2254*ec779b8eSAndroid Build Coastguard Worker status = -EINTR;
2255*ec779b8eSAndroid Build Coastguard Worker buffer.mFrameCount = 0;
2256*ec779b8eSAndroid Build Coastguard Worker buffer.mRaw = NULL;
2257*ec779b8eSAndroid Build Coastguard Worker buffer.mNonContig = 0;
2258*ec779b8eSAndroid Build Coastguard Worker break;
2259*ec779b8eSAndroid Build Coastguard Worker }
2260*ec779b8eSAndroid Build Coastguard Worker
2261*ec779b8eSAndroid Build Coastguard Worker // Non-blocking if track is stopped or paused
2262*ec779b8eSAndroid Build Coastguard Worker if (mState != STATE_ACTIVE) {
2263*ec779b8eSAndroid Build Coastguard Worker requested = &ClientProxy::kNonBlocking;
2264*ec779b8eSAndroid Build Coastguard Worker }
2265*ec779b8eSAndroid Build Coastguard Worker
2266*ec779b8eSAndroid Build Coastguard Worker } // end of lock scope
2267*ec779b8eSAndroid Build Coastguard Worker
2268*ec779b8eSAndroid Build Coastguard Worker buffer.mFrameCount = audioBuffer->frameCount;
2269*ec779b8eSAndroid Build Coastguard Worker // FIXME starts the requested timeout and elapsed over from scratch
2270*ec779b8eSAndroid Build Coastguard Worker status = proxy->obtainBuffer(&buffer, requested, elapsed);
2271*ec779b8eSAndroid Build Coastguard Worker } while (((status == DEAD_OBJECT) || (status == NOT_ENOUGH_DATA)) && (tryCounter-- > 0));
2272*ec779b8eSAndroid Build Coastguard Worker
2273*ec779b8eSAndroid Build Coastguard Worker audioBuffer->frameCount = buffer.mFrameCount;
2274*ec779b8eSAndroid Build Coastguard Worker audioBuffer->mSize = buffer.mFrameCount * mFrameSize;
2275*ec779b8eSAndroid Build Coastguard Worker audioBuffer->raw = buffer.mRaw;
2276*ec779b8eSAndroid Build Coastguard Worker audioBuffer->sequence = oldSequence;
2277*ec779b8eSAndroid Build Coastguard Worker if (nonContig != NULL) {
2278*ec779b8eSAndroid Build Coastguard Worker *nonContig = buffer.mNonContig;
2279*ec779b8eSAndroid Build Coastguard Worker }
2280*ec779b8eSAndroid Build Coastguard Worker return status;
2281*ec779b8eSAndroid Build Coastguard Worker }
2282*ec779b8eSAndroid Build Coastguard Worker
releaseBuffer(const Buffer * audioBuffer)2283*ec779b8eSAndroid Build Coastguard Worker void AudioTrack::releaseBuffer(const Buffer* audioBuffer)
2284*ec779b8eSAndroid Build Coastguard Worker {
2285*ec779b8eSAndroid Build Coastguard Worker // FIXME add error checking on mode, by adding an internal version
2286*ec779b8eSAndroid Build Coastguard Worker if (mTransfer == TRANSFER_SHARED) {
2287*ec779b8eSAndroid Build Coastguard Worker return;
2288*ec779b8eSAndroid Build Coastguard Worker }
2289*ec779b8eSAndroid Build Coastguard Worker
2290*ec779b8eSAndroid Build Coastguard Worker size_t stepCount = audioBuffer->mSize / mFrameSize;
2291*ec779b8eSAndroid Build Coastguard Worker if (stepCount == 0) {
2292*ec779b8eSAndroid Build Coastguard Worker return;
2293*ec779b8eSAndroid Build Coastguard Worker }
2294*ec779b8eSAndroid Build Coastguard Worker
2295*ec779b8eSAndroid Build Coastguard Worker Proxy::Buffer buffer;
2296*ec779b8eSAndroid Build Coastguard Worker buffer.mFrameCount = stepCount;
2297*ec779b8eSAndroid Build Coastguard Worker buffer.mRaw = audioBuffer->raw;
2298*ec779b8eSAndroid Build Coastguard Worker
2299*ec779b8eSAndroid Build Coastguard Worker sp<IMemory> tempMemory;
2300*ec779b8eSAndroid Build Coastguard Worker sp<AudioTrackClientProxy> tempProxy;
2301*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
2302*ec779b8eSAndroid Build Coastguard Worker if (audioBuffer->sequence != mSequence) {
2303*ec779b8eSAndroid Build Coastguard Worker // This Buffer came from a different IAudioTrack instance, so ignore the releaseBuffer
2304*ec779b8eSAndroid Build Coastguard Worker ALOGD("%s is no-op due to IAudioTrack sequence mismatch %u != %u",
2305*ec779b8eSAndroid Build Coastguard Worker __func__, audioBuffer->sequence, mSequence);
2306*ec779b8eSAndroid Build Coastguard Worker return;
2307*ec779b8eSAndroid Build Coastguard Worker }
2308*ec779b8eSAndroid Build Coastguard Worker mReleased += stepCount;
2309*ec779b8eSAndroid Build Coastguard Worker mInUnderrun = false;
2310*ec779b8eSAndroid Build Coastguard Worker mProxyObtainBufferRef->releaseBuffer(&buffer);
2311*ec779b8eSAndroid Build Coastguard Worker // The extra reference of shared memory and proxy from `obtainBuffer` is not used after
2312*ec779b8eSAndroid Build Coastguard Worker // calling `releaseBuffer`. Move the extra reference to a temp strong pointer so that it
2313*ec779b8eSAndroid Build Coastguard Worker // will be cleared outside `releaseBuffer`.
2314*ec779b8eSAndroid Build Coastguard Worker tempMemory = std::move(mCblkMemoryObtainBufferRef);
2315*ec779b8eSAndroid Build Coastguard Worker tempProxy = std::move(mProxyObtainBufferRef);
2316*ec779b8eSAndroid Build Coastguard Worker
2317*ec779b8eSAndroid Build Coastguard Worker // restart track if it was disabled by audioflinger due to previous underrun
2318*ec779b8eSAndroid Build Coastguard Worker restartIfDisabled();
2319*ec779b8eSAndroid Build Coastguard Worker }
2320*ec779b8eSAndroid Build Coastguard Worker
restartIfDisabled()2321*ec779b8eSAndroid Build Coastguard Worker void AudioTrack::restartIfDisabled()
2322*ec779b8eSAndroid Build Coastguard Worker {
2323*ec779b8eSAndroid Build Coastguard Worker int32_t flags = android_atomic_and(~CBLK_DISABLED, &mCblk->mFlags);
2324*ec779b8eSAndroid Build Coastguard Worker if ((mState == STATE_ACTIVE) && (flags & CBLK_DISABLED)) {
2325*ec779b8eSAndroid Build Coastguard Worker ALOGW("%s(%d): releaseBuffer() track %p disabled due to previous underrun, restarting",
2326*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId, this);
2327*ec779b8eSAndroid Build Coastguard Worker // FIXME ignoring status
2328*ec779b8eSAndroid Build Coastguard Worker status_t status;
2329*ec779b8eSAndroid Build Coastguard Worker mAudioTrack->start(&status);
2330*ec779b8eSAndroid Build Coastguard Worker }
2331*ec779b8eSAndroid Build Coastguard Worker }
2332*ec779b8eSAndroid Build Coastguard Worker
2333*ec779b8eSAndroid Build Coastguard Worker // -------------------------------------------------------------------------
2334*ec779b8eSAndroid Build Coastguard Worker
write(const void * buffer,size_t userSize,bool blocking)2335*ec779b8eSAndroid Build Coastguard Worker ssize_t AudioTrack::write(const void* buffer, size_t userSize, bool blocking)
2336*ec779b8eSAndroid Build Coastguard Worker {
2337*ec779b8eSAndroid Build Coastguard Worker if (mTransfer != TRANSFER_SYNC && mTransfer != TRANSFER_SYNC_NOTIF_CALLBACK) {
2338*ec779b8eSAndroid Build Coastguard Worker return INVALID_OPERATION;
2339*ec779b8eSAndroid Build Coastguard Worker }
2340*ec779b8eSAndroid Build Coastguard Worker
2341*ec779b8eSAndroid Build Coastguard Worker if (isDirect()) {
2342*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
2343*ec779b8eSAndroid Build Coastguard Worker int32_t flags = android_atomic_and(
2344*ec779b8eSAndroid Build Coastguard Worker ~(CBLK_UNDERRUN | CBLK_LOOP_CYCLE | CBLK_LOOP_FINAL | CBLK_BUFFER_END),
2345*ec779b8eSAndroid Build Coastguard Worker &mCblk->mFlags);
2346*ec779b8eSAndroid Build Coastguard Worker if (flags & CBLK_INVALID) {
2347*ec779b8eSAndroid Build Coastguard Worker return DEAD_OBJECT;
2348*ec779b8eSAndroid Build Coastguard Worker }
2349*ec779b8eSAndroid Build Coastguard Worker }
2350*ec779b8eSAndroid Build Coastguard Worker
2351*ec779b8eSAndroid Build Coastguard Worker if (ssize_t(userSize) < 0 || (buffer == NULL && userSize != 0)) {
2352*ec779b8eSAndroid Build Coastguard Worker // Validation: user is most-likely passing an error code, and it would
2353*ec779b8eSAndroid Build Coastguard Worker // make the return value ambiguous (actualSize vs error).
2354*ec779b8eSAndroid Build Coastguard Worker ALOGE("%s(%d): AudioTrack::write(buffer=%p, size=%zu (%zd)",
2355*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId, buffer, userSize, userSize);
2356*ec779b8eSAndroid Build Coastguard Worker return BAD_VALUE;
2357*ec779b8eSAndroid Build Coastguard Worker }
2358*ec779b8eSAndroid Build Coastguard Worker
2359*ec779b8eSAndroid Build Coastguard Worker size_t written = 0;
2360*ec779b8eSAndroid Build Coastguard Worker Buffer audioBuffer;
2361*ec779b8eSAndroid Build Coastguard Worker
2362*ec779b8eSAndroid Build Coastguard Worker while (userSize >= mFrameSize) {
2363*ec779b8eSAndroid Build Coastguard Worker audioBuffer.frameCount = userSize / mFrameSize;
2364*ec779b8eSAndroid Build Coastguard Worker
2365*ec779b8eSAndroid Build Coastguard Worker status_t err = obtainBuffer(&audioBuffer,
2366*ec779b8eSAndroid Build Coastguard Worker blocking ? &ClientProxy::kForever : &ClientProxy::kNonBlocking);
2367*ec779b8eSAndroid Build Coastguard Worker if (err < 0) {
2368*ec779b8eSAndroid Build Coastguard Worker if (written > 0) {
2369*ec779b8eSAndroid Build Coastguard Worker break;
2370*ec779b8eSAndroid Build Coastguard Worker }
2371*ec779b8eSAndroid Build Coastguard Worker if (err == TIMED_OUT || err == -EINTR) {
2372*ec779b8eSAndroid Build Coastguard Worker err = WOULD_BLOCK;
2373*ec779b8eSAndroid Build Coastguard Worker }
2374*ec779b8eSAndroid Build Coastguard Worker return ssize_t(err);
2375*ec779b8eSAndroid Build Coastguard Worker }
2376*ec779b8eSAndroid Build Coastguard Worker
2377*ec779b8eSAndroid Build Coastguard Worker size_t toWrite = audioBuffer.size();
2378*ec779b8eSAndroid Build Coastguard Worker memcpy(audioBuffer.raw, buffer, toWrite);
2379*ec779b8eSAndroid Build Coastguard Worker buffer = ((const char *) buffer) + toWrite;
2380*ec779b8eSAndroid Build Coastguard Worker userSize -= toWrite;
2381*ec779b8eSAndroid Build Coastguard Worker written += toWrite;
2382*ec779b8eSAndroid Build Coastguard Worker
2383*ec779b8eSAndroid Build Coastguard Worker releaseBuffer(&audioBuffer);
2384*ec779b8eSAndroid Build Coastguard Worker }
2385*ec779b8eSAndroid Build Coastguard Worker
2386*ec779b8eSAndroid Build Coastguard Worker if (written > 0) {
2387*ec779b8eSAndroid Build Coastguard Worker mFramesWritten += written / mFrameSize;
2388*ec779b8eSAndroid Build Coastguard Worker
2389*ec779b8eSAndroid Build Coastguard Worker if (mTransfer == TRANSFER_SYNC_NOTIF_CALLBACK) {
2390*ec779b8eSAndroid Build Coastguard Worker const sp<AudioTrackThread> t = mAudioTrackThread;
2391*ec779b8eSAndroid Build Coastguard Worker if (t != 0) {
2392*ec779b8eSAndroid Build Coastguard Worker // causes wake up of the playback thread, that will callback the client for
2393*ec779b8eSAndroid Build Coastguard Worker // more data (with EVENT_CAN_WRITE_MORE_DATA) in processAudioBuffer()
2394*ec779b8eSAndroid Build Coastguard Worker t->wake();
2395*ec779b8eSAndroid Build Coastguard Worker }
2396*ec779b8eSAndroid Build Coastguard Worker }
2397*ec779b8eSAndroid Build Coastguard Worker }
2398*ec779b8eSAndroid Build Coastguard Worker
2399*ec779b8eSAndroid Build Coastguard Worker return written;
2400*ec779b8eSAndroid Build Coastguard Worker }
2401*ec779b8eSAndroid Build Coastguard Worker
2402*ec779b8eSAndroid Build Coastguard Worker // -------------------------------------------------------------------------
2403*ec779b8eSAndroid Build Coastguard Worker
processAudioBuffer()2404*ec779b8eSAndroid Build Coastguard Worker nsecs_t AudioTrack::processAudioBuffer()
2405*ec779b8eSAndroid Build Coastguard Worker {
2406*ec779b8eSAndroid Build Coastguard Worker // Currently the AudioTrack thread is not created if there are no callbacks.
2407*ec779b8eSAndroid Build Coastguard Worker // Would it ever make sense to run the thread, even without callbacks?
2408*ec779b8eSAndroid Build Coastguard Worker // If so, then replace this by checks at each use for mCallback != NULL.
2409*ec779b8eSAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(mCblk == NULL);
2410*ec779b8eSAndroid Build Coastguard Worker mLock.lock();
2411*ec779b8eSAndroid Build Coastguard Worker sp<IAudioTrackCallback> callback = mCallback.promote();
2412*ec779b8eSAndroid Build Coastguard Worker if (!callback) {
2413*ec779b8eSAndroid Build Coastguard Worker mCallback = nullptr;
2414*ec779b8eSAndroid Build Coastguard Worker mLock.unlock();
2415*ec779b8eSAndroid Build Coastguard Worker return NS_NEVER;
2416*ec779b8eSAndroid Build Coastguard Worker }
2417*ec779b8eSAndroid Build Coastguard Worker if (mAwaitBoost) {
2418*ec779b8eSAndroid Build Coastguard Worker mAwaitBoost = false;
2419*ec779b8eSAndroid Build Coastguard Worker mLock.unlock();
2420*ec779b8eSAndroid Build Coastguard Worker static const int32_t kMaxTries = 5;
2421*ec779b8eSAndroid Build Coastguard Worker int32_t tryCounter = kMaxTries;
2422*ec779b8eSAndroid Build Coastguard Worker uint32_t pollUs = 10000;
2423*ec779b8eSAndroid Build Coastguard Worker do {
2424*ec779b8eSAndroid Build Coastguard Worker int policy = sched_getscheduler(0) & ~SCHED_RESET_ON_FORK;
2425*ec779b8eSAndroid Build Coastguard Worker if (policy == SCHED_FIFO || policy == SCHED_RR) {
2426*ec779b8eSAndroid Build Coastguard Worker break;
2427*ec779b8eSAndroid Build Coastguard Worker }
2428*ec779b8eSAndroid Build Coastguard Worker usleep(pollUs);
2429*ec779b8eSAndroid Build Coastguard Worker pollUs <<= 1;
2430*ec779b8eSAndroid Build Coastguard Worker } while (tryCounter-- > 0);
2431*ec779b8eSAndroid Build Coastguard Worker if (tryCounter < 0) {
2432*ec779b8eSAndroid Build Coastguard Worker ALOGE("%s(%d): did not receive expected priority boost on time",
2433*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId);
2434*ec779b8eSAndroid Build Coastguard Worker }
2435*ec779b8eSAndroid Build Coastguard Worker // Run again immediately
2436*ec779b8eSAndroid Build Coastguard Worker return 0;
2437*ec779b8eSAndroid Build Coastguard Worker }
2438*ec779b8eSAndroid Build Coastguard Worker
2439*ec779b8eSAndroid Build Coastguard Worker // Can only reference mCblk while locked
2440*ec779b8eSAndroid Build Coastguard Worker int32_t flags = android_atomic_and(
2441*ec779b8eSAndroid Build Coastguard Worker ~(CBLK_UNDERRUN | CBLK_LOOP_CYCLE | CBLK_LOOP_FINAL | CBLK_BUFFER_END), &mCblk->mFlags);
2442*ec779b8eSAndroid Build Coastguard Worker
2443*ec779b8eSAndroid Build Coastguard Worker const bool isOffloaded = isOffloaded_l();
2444*ec779b8eSAndroid Build Coastguard Worker const bool isOffloadedOrDirect = isOffloadedOrDirect_l();
2445*ec779b8eSAndroid Build Coastguard Worker // Check for track invalidation
2446*ec779b8eSAndroid Build Coastguard Worker if (flags & CBLK_INVALID) {
2447*ec779b8eSAndroid Build Coastguard Worker // for offloaded tracks restoreTrack_l() will just update the sequence and clear
2448*ec779b8eSAndroid Build Coastguard Worker // AudioSystem cache. We should not exit here but after calling the callback so
2449*ec779b8eSAndroid Build Coastguard Worker // that the upper layers can recreate the track
2450*ec779b8eSAndroid Build Coastguard Worker if (!isOffloadedOrDirect || (mSequence == mObservedSequence)) {
2451*ec779b8eSAndroid Build Coastguard Worker status_t status __unused = restoreTrack_l("processAudioBuffer");
2452*ec779b8eSAndroid Build Coastguard Worker // FIXME unused status
2453*ec779b8eSAndroid Build Coastguard Worker // after restoration, continue below to make sure that the loop and buffer events
2454*ec779b8eSAndroid Build Coastguard Worker // are notified because they have been cleared from mCblk->mFlags above.
2455*ec779b8eSAndroid Build Coastguard Worker }
2456*ec779b8eSAndroid Build Coastguard Worker }
2457*ec779b8eSAndroid Build Coastguard Worker
2458*ec779b8eSAndroid Build Coastguard Worker bool waitStreamEnd = mState == STATE_STOPPING;
2459*ec779b8eSAndroid Build Coastguard Worker bool active = mState == STATE_ACTIVE;
2460*ec779b8eSAndroid Build Coastguard Worker
2461*ec779b8eSAndroid Build Coastguard Worker // Manage underrun callback, must be done under lock to avoid race with releaseBuffer()
2462*ec779b8eSAndroid Build Coastguard Worker bool newUnderrun = false;
2463*ec779b8eSAndroid Build Coastguard Worker if (flags & CBLK_UNDERRUN) {
2464*ec779b8eSAndroid Build Coastguard Worker #if 0
2465*ec779b8eSAndroid Build Coastguard Worker // Currently in shared buffer mode, when the server reaches the end of buffer,
2466*ec779b8eSAndroid Build Coastguard Worker // the track stays active in continuous underrun state. It's up to the application
2467*ec779b8eSAndroid Build Coastguard Worker // to pause or stop the track, or set the position to a new offset within buffer.
2468*ec779b8eSAndroid Build Coastguard Worker // This was some experimental code to auto-pause on underrun. Keeping it here
2469*ec779b8eSAndroid Build Coastguard Worker // in "if 0" so we can re-visit this if we add a real sequencer for shared memory content.
2470*ec779b8eSAndroid Build Coastguard Worker if (mTransfer == TRANSFER_SHARED) {
2471*ec779b8eSAndroid Build Coastguard Worker mState = STATE_PAUSED;
2472*ec779b8eSAndroid Build Coastguard Worker active = false;
2473*ec779b8eSAndroid Build Coastguard Worker }
2474*ec779b8eSAndroid Build Coastguard Worker #endif
2475*ec779b8eSAndroid Build Coastguard Worker if (!mInUnderrun) {
2476*ec779b8eSAndroid Build Coastguard Worker mInUnderrun = true;
2477*ec779b8eSAndroid Build Coastguard Worker newUnderrun = true;
2478*ec779b8eSAndroid Build Coastguard Worker }
2479*ec779b8eSAndroid Build Coastguard Worker }
2480*ec779b8eSAndroid Build Coastguard Worker
2481*ec779b8eSAndroid Build Coastguard Worker // Get current position of server
2482*ec779b8eSAndroid Build Coastguard Worker Modulo<uint32_t> position(updateAndGetPosition_l());
2483*ec779b8eSAndroid Build Coastguard Worker
2484*ec779b8eSAndroid Build Coastguard Worker // Manage marker callback
2485*ec779b8eSAndroid Build Coastguard Worker bool markerReached = false;
2486*ec779b8eSAndroid Build Coastguard Worker Modulo<uint32_t> markerPosition(mMarkerPosition);
2487*ec779b8eSAndroid Build Coastguard Worker // uses 32 bit wraparound for comparison with position.
2488*ec779b8eSAndroid Build Coastguard Worker if (!mMarkerReached && markerPosition.value() > 0 && position >= markerPosition) {
2489*ec779b8eSAndroid Build Coastguard Worker mMarkerReached = markerReached = true;
2490*ec779b8eSAndroid Build Coastguard Worker }
2491*ec779b8eSAndroid Build Coastguard Worker
2492*ec779b8eSAndroid Build Coastguard Worker // Determine number of new position callback(s) that will be needed, while locked
2493*ec779b8eSAndroid Build Coastguard Worker size_t newPosCount = 0;
2494*ec779b8eSAndroid Build Coastguard Worker Modulo<uint32_t> newPosition(mNewPosition);
2495*ec779b8eSAndroid Build Coastguard Worker uint32_t updatePeriod = mUpdatePeriod;
2496*ec779b8eSAndroid Build Coastguard Worker // FIXME fails for wraparound, need 64 bits
2497*ec779b8eSAndroid Build Coastguard Worker if (updatePeriod > 0 && position >= newPosition) {
2498*ec779b8eSAndroid Build Coastguard Worker newPosCount = ((position - newPosition).value() / updatePeriod) + 1;
2499*ec779b8eSAndroid Build Coastguard Worker mNewPosition += updatePeriod * newPosCount;
2500*ec779b8eSAndroid Build Coastguard Worker }
2501*ec779b8eSAndroid Build Coastguard Worker
2502*ec779b8eSAndroid Build Coastguard Worker // Cache other fields that will be needed soon
2503*ec779b8eSAndroid Build Coastguard Worker uint32_t sampleRate = mSampleRate;
2504*ec779b8eSAndroid Build Coastguard Worker float speed = mPlaybackRate.mSpeed;
2505*ec779b8eSAndroid Build Coastguard Worker const uint32_t notificationFrames = mNotificationFramesAct;
2506*ec779b8eSAndroid Build Coastguard Worker if (mRefreshRemaining) {
2507*ec779b8eSAndroid Build Coastguard Worker mRefreshRemaining = false;
2508*ec779b8eSAndroid Build Coastguard Worker mRemainingFrames = notificationFrames;
2509*ec779b8eSAndroid Build Coastguard Worker mRetryOnPartialBuffer = false;
2510*ec779b8eSAndroid Build Coastguard Worker }
2511*ec779b8eSAndroid Build Coastguard Worker size_t misalignment = mProxy->getMisalignment();
2512*ec779b8eSAndroid Build Coastguard Worker uint32_t sequence = mSequence;
2513*ec779b8eSAndroid Build Coastguard Worker sp<AudioTrackClientProxy> proxy = mProxy;
2514*ec779b8eSAndroid Build Coastguard Worker
2515*ec779b8eSAndroid Build Coastguard Worker // Determine the number of new loop callback(s) that will be needed, while locked.
2516*ec779b8eSAndroid Build Coastguard Worker uint32_t loopCountNotifications = 0;
2517*ec779b8eSAndroid Build Coastguard Worker uint32_t loopPeriod = 0; // time in frames for next EVENT_LOOP_END or EVENT_BUFFER_END
2518*ec779b8eSAndroid Build Coastguard Worker
2519*ec779b8eSAndroid Build Coastguard Worker if (mLoopCount > 0) {
2520*ec779b8eSAndroid Build Coastguard Worker int loopCount;
2521*ec779b8eSAndroid Build Coastguard Worker size_t bufferPosition;
2522*ec779b8eSAndroid Build Coastguard Worker mStaticProxy->getBufferPositionAndLoopCount(&bufferPosition, &loopCount);
2523*ec779b8eSAndroid Build Coastguard Worker loopPeriod = ((loopCount > 0) ? mLoopEnd : mFrameCount) - bufferPosition;
2524*ec779b8eSAndroid Build Coastguard Worker loopCountNotifications = min(mLoopCountNotified - loopCount, kMaxLoopCountNotifications);
2525*ec779b8eSAndroid Build Coastguard Worker mLoopCountNotified = loopCount; // discard any excess notifications
2526*ec779b8eSAndroid Build Coastguard Worker } else if (mLoopCount < 0) {
2527*ec779b8eSAndroid Build Coastguard Worker // FIXME: We're not accurate with notification count and position with infinite looping
2528*ec779b8eSAndroid Build Coastguard Worker // since loopCount from server side will always return -1 (we could decrement it).
2529*ec779b8eSAndroid Build Coastguard Worker size_t bufferPosition = mStaticProxy->getBufferPosition();
2530*ec779b8eSAndroid Build Coastguard Worker loopCountNotifications = int((flags & (CBLK_LOOP_CYCLE | CBLK_LOOP_FINAL)) != 0);
2531*ec779b8eSAndroid Build Coastguard Worker loopPeriod = mLoopEnd - bufferPosition;
2532*ec779b8eSAndroid Build Coastguard Worker } else if (/* mLoopCount == 0 && */ mSharedBuffer != 0) {
2533*ec779b8eSAndroid Build Coastguard Worker size_t bufferPosition = mStaticProxy->getBufferPosition();
2534*ec779b8eSAndroid Build Coastguard Worker loopPeriod = mFrameCount - bufferPosition;
2535*ec779b8eSAndroid Build Coastguard Worker }
2536*ec779b8eSAndroid Build Coastguard Worker
2537*ec779b8eSAndroid Build Coastguard Worker // These fields don't need to be cached, because they are assigned only by set():
2538*ec779b8eSAndroid Build Coastguard Worker // mTransfer, mCallback, mUserData, mFormat, mFrameSize, mFlags
2539*ec779b8eSAndroid Build Coastguard Worker // mFlags is also assigned by createTrack_l(), but not the bit we care about.
2540*ec779b8eSAndroid Build Coastguard Worker
2541*ec779b8eSAndroid Build Coastguard Worker mLock.unlock();
2542*ec779b8eSAndroid Build Coastguard Worker
2543*ec779b8eSAndroid Build Coastguard Worker // get anchor time to account for callbacks.
2544*ec779b8eSAndroid Build Coastguard Worker const nsecs_t timeBeforeCallbacks = systemTime();
2545*ec779b8eSAndroid Build Coastguard Worker
2546*ec779b8eSAndroid Build Coastguard Worker if (waitStreamEnd) {
2547*ec779b8eSAndroid Build Coastguard Worker // FIXME: Instead of blocking in proxy->waitStreamEndDone(), Callback thread
2548*ec779b8eSAndroid Build Coastguard Worker // should wait on proxy futex and handle CBLK_STREAM_END_DONE within this function
2549*ec779b8eSAndroid Build Coastguard Worker // (and make sure we don't callback for more data while we're stopping).
2550*ec779b8eSAndroid Build Coastguard Worker // This helps with position, marker notifications, and track invalidation.
2551*ec779b8eSAndroid Build Coastguard Worker struct timespec timeout;
2552*ec779b8eSAndroid Build Coastguard Worker timeout.tv_sec = WAIT_STREAM_END_TIMEOUT_SEC;
2553*ec779b8eSAndroid Build Coastguard Worker timeout.tv_nsec = 0;
2554*ec779b8eSAndroid Build Coastguard Worker
2555*ec779b8eSAndroid Build Coastguard Worker // Use timestamp progress to safeguard we don't falsely time out.
2556*ec779b8eSAndroid Build Coastguard Worker AudioTimestamp timestamp{};
2557*ec779b8eSAndroid Build Coastguard Worker const bool isTimestampValid = getTimestamp(timestamp) == OK;
2558*ec779b8eSAndroid Build Coastguard Worker const auto frameCount = isTimestampValid ? timestamp.mPosition : 0;
2559*ec779b8eSAndroid Build Coastguard Worker
2560*ec779b8eSAndroid Build Coastguard Worker status_t status = proxy->waitStreamEndDone(&timeout);
2561*ec779b8eSAndroid Build Coastguard Worker switch (status) {
2562*ec779b8eSAndroid Build Coastguard Worker case TIMED_OUT:
2563*ec779b8eSAndroid Build Coastguard Worker if (isTimestampValid
2564*ec779b8eSAndroid Build Coastguard Worker && getTimestamp(timestamp) == OK && frameCount != timestamp.mPosition) {
2565*ec779b8eSAndroid Build Coastguard Worker ALOGD("%s: waitStreamEndDone retrying", __func__);
2566*ec779b8eSAndroid Build Coastguard Worker break; // we retry again (and recheck possible state change).
2567*ec779b8eSAndroid Build Coastguard Worker }
2568*ec779b8eSAndroid Build Coastguard Worker [[fallthrough]];
2569*ec779b8eSAndroid Build Coastguard Worker case NO_ERROR:
2570*ec779b8eSAndroid Build Coastguard Worker case DEAD_OBJECT:
2571*ec779b8eSAndroid Build Coastguard Worker if (status != DEAD_OBJECT) {
2572*ec779b8eSAndroid Build Coastguard Worker // for DEAD_OBJECT, we do not send a EVENT_STREAM_END after stop();
2573*ec779b8eSAndroid Build Coastguard Worker // instead, the application should handle the EVENT_NEW_IAUDIOTRACK.
2574*ec779b8eSAndroid Build Coastguard Worker callback->onStreamEnd();
2575*ec779b8eSAndroid Build Coastguard Worker }
2576*ec779b8eSAndroid Build Coastguard Worker {
2577*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
2578*ec779b8eSAndroid Build Coastguard Worker // The previously assigned value of waitStreamEnd is no longer valid,
2579*ec779b8eSAndroid Build Coastguard Worker // since the mutex has been unlocked and either the callback handler
2580*ec779b8eSAndroid Build Coastguard Worker // or another thread could have re-started the AudioTrack during that time.
2581*ec779b8eSAndroid Build Coastguard Worker waitStreamEnd = mState == STATE_STOPPING;
2582*ec779b8eSAndroid Build Coastguard Worker if (waitStreamEnd) {
2583*ec779b8eSAndroid Build Coastguard Worker mState = STATE_STOPPED;
2584*ec779b8eSAndroid Build Coastguard Worker mReleased = 0;
2585*ec779b8eSAndroid Build Coastguard Worker }
2586*ec779b8eSAndroid Build Coastguard Worker }
2587*ec779b8eSAndroid Build Coastguard Worker if (waitStreamEnd && status != DEAD_OBJECT) {
2588*ec779b8eSAndroid Build Coastguard Worker ALOGV("%s: waitStreamEndDone complete", __func__);
2589*ec779b8eSAndroid Build Coastguard Worker return NS_INACTIVE;
2590*ec779b8eSAndroid Build Coastguard Worker }
2591*ec779b8eSAndroid Build Coastguard Worker break;
2592*ec779b8eSAndroid Build Coastguard Worker }
2593*ec779b8eSAndroid Build Coastguard Worker return 0;
2594*ec779b8eSAndroid Build Coastguard Worker }
2595*ec779b8eSAndroid Build Coastguard Worker
2596*ec779b8eSAndroid Build Coastguard Worker // perform callbacks while unlocked
2597*ec779b8eSAndroid Build Coastguard Worker if (newUnderrun) {
2598*ec779b8eSAndroid Build Coastguard Worker callback->onUnderrun();
2599*ec779b8eSAndroid Build Coastguard Worker }
2600*ec779b8eSAndroid Build Coastguard Worker while (loopCountNotifications > 0) {
2601*ec779b8eSAndroid Build Coastguard Worker --loopCountNotifications;
2602*ec779b8eSAndroid Build Coastguard Worker callback->onLoopEnd(mLoopCount > 0 ? loopCountNotifications + mLoopCountNotified : -1);
2603*ec779b8eSAndroid Build Coastguard Worker }
2604*ec779b8eSAndroid Build Coastguard Worker if (flags & CBLK_BUFFER_END) {
2605*ec779b8eSAndroid Build Coastguard Worker callback->onBufferEnd();
2606*ec779b8eSAndroid Build Coastguard Worker }
2607*ec779b8eSAndroid Build Coastguard Worker if (markerReached) {
2608*ec779b8eSAndroid Build Coastguard Worker callback->onMarker(markerPosition.value());
2609*ec779b8eSAndroid Build Coastguard Worker }
2610*ec779b8eSAndroid Build Coastguard Worker while (newPosCount > 0) {
2611*ec779b8eSAndroid Build Coastguard Worker callback->onNewPos(newPosition.value());
2612*ec779b8eSAndroid Build Coastguard Worker newPosition += updatePeriod;
2613*ec779b8eSAndroid Build Coastguard Worker newPosCount--;
2614*ec779b8eSAndroid Build Coastguard Worker }
2615*ec779b8eSAndroid Build Coastguard Worker
2616*ec779b8eSAndroid Build Coastguard Worker if (mObservedSequence != sequence) {
2617*ec779b8eSAndroid Build Coastguard Worker mObservedSequence = sequence;
2618*ec779b8eSAndroid Build Coastguard Worker callback->onNewIAudioTrack();
2619*ec779b8eSAndroid Build Coastguard Worker // for offloaded tracks, just wait for the upper layers to recreate the track
2620*ec779b8eSAndroid Build Coastguard Worker if (isOffloadedOrDirect) {
2621*ec779b8eSAndroid Build Coastguard Worker return NS_INACTIVE;
2622*ec779b8eSAndroid Build Coastguard Worker }
2623*ec779b8eSAndroid Build Coastguard Worker }
2624*ec779b8eSAndroid Build Coastguard Worker
2625*ec779b8eSAndroid Build Coastguard Worker // if inactive, then don't run me again until re-started
2626*ec779b8eSAndroid Build Coastguard Worker if (!active) {
2627*ec779b8eSAndroid Build Coastguard Worker return NS_INACTIVE;
2628*ec779b8eSAndroid Build Coastguard Worker }
2629*ec779b8eSAndroid Build Coastguard Worker
2630*ec779b8eSAndroid Build Coastguard Worker // Compute the estimated time until the next timed event (position, markers, loops)
2631*ec779b8eSAndroid Build Coastguard Worker // FIXME only for non-compressed audio
2632*ec779b8eSAndroid Build Coastguard Worker uint32_t minFrames = ~0;
2633*ec779b8eSAndroid Build Coastguard Worker if (!markerReached && position < markerPosition) {
2634*ec779b8eSAndroid Build Coastguard Worker minFrames = (markerPosition - position).value();
2635*ec779b8eSAndroid Build Coastguard Worker }
2636*ec779b8eSAndroid Build Coastguard Worker if (loopPeriod > 0 && loopPeriod < minFrames) {
2637*ec779b8eSAndroid Build Coastguard Worker // loopPeriod is already adjusted for actual position.
2638*ec779b8eSAndroid Build Coastguard Worker minFrames = loopPeriod;
2639*ec779b8eSAndroid Build Coastguard Worker }
2640*ec779b8eSAndroid Build Coastguard Worker if (updatePeriod > 0) {
2641*ec779b8eSAndroid Build Coastguard Worker minFrames = min(minFrames, (newPosition - position).value());
2642*ec779b8eSAndroid Build Coastguard Worker }
2643*ec779b8eSAndroid Build Coastguard Worker
2644*ec779b8eSAndroid Build Coastguard Worker // If > 0, poll periodically to recover from a stuck server. A good value is 2.
2645*ec779b8eSAndroid Build Coastguard Worker static const uint32_t kPoll = 0;
2646*ec779b8eSAndroid Build Coastguard Worker if (kPoll > 0 && mTransfer == TRANSFER_CALLBACK && kPoll * notificationFrames < minFrames) {
2647*ec779b8eSAndroid Build Coastguard Worker minFrames = kPoll * notificationFrames;
2648*ec779b8eSAndroid Build Coastguard Worker }
2649*ec779b8eSAndroid Build Coastguard Worker
2650*ec779b8eSAndroid Build Coastguard Worker // This "fudge factor" avoids soaking CPU, and compensates for late progress by server
2651*ec779b8eSAndroid Build Coastguard Worker static const nsecs_t kWaitPeriodNs = WAIT_PERIOD_MS * 1000000LL;
2652*ec779b8eSAndroid Build Coastguard Worker const nsecs_t timeAfterCallbacks = systemTime();
2653*ec779b8eSAndroid Build Coastguard Worker
2654*ec779b8eSAndroid Build Coastguard Worker // Convert frame units to time units
2655*ec779b8eSAndroid Build Coastguard Worker nsecs_t ns = NS_WHENEVER;
2656*ec779b8eSAndroid Build Coastguard Worker if (minFrames != (uint32_t) ~0) {
2657*ec779b8eSAndroid Build Coastguard Worker // AudioFlinger consumption of client data may be irregular when coming out of device
2658*ec779b8eSAndroid Build Coastguard Worker // standby since the kernel buffers require filling. This is throttled to no more than 2x
2659*ec779b8eSAndroid Build Coastguard Worker // the expected rate in the MixerThread. Hence, we reduce the estimated time to wait by one
2660*ec779b8eSAndroid Build Coastguard Worker // half (but no more than half a second) to improve callback accuracy during these temporary
2661*ec779b8eSAndroid Build Coastguard Worker // data surges.
2662*ec779b8eSAndroid Build Coastguard Worker const nsecs_t estimatedNs = framesToNanoseconds(minFrames, sampleRate, speed);
2663*ec779b8eSAndroid Build Coastguard Worker constexpr nsecs_t maxThrottleCompensationNs = 500000000LL;
2664*ec779b8eSAndroid Build Coastguard Worker ns = estimatedNs - min(estimatedNs / 2, maxThrottleCompensationNs) + kWaitPeriodNs;
2665*ec779b8eSAndroid Build Coastguard Worker ns -= (timeAfterCallbacks - timeBeforeCallbacks); // account for callback time
2666*ec779b8eSAndroid Build Coastguard Worker // TODO: Should we warn if the callback time is too long?
2667*ec779b8eSAndroid Build Coastguard Worker if (ns < 0) ns = 0;
2668*ec779b8eSAndroid Build Coastguard Worker }
2669*ec779b8eSAndroid Build Coastguard Worker
2670*ec779b8eSAndroid Build Coastguard Worker // If not supplying data by EVENT_MORE_DATA or EVENT_CAN_WRITE_MORE_DATA, then we're done
2671*ec779b8eSAndroid Build Coastguard Worker if (mTransfer != TRANSFER_CALLBACK && mTransfer != TRANSFER_SYNC_NOTIF_CALLBACK) {
2672*ec779b8eSAndroid Build Coastguard Worker return ns;
2673*ec779b8eSAndroid Build Coastguard Worker }
2674*ec779b8eSAndroid Build Coastguard Worker
2675*ec779b8eSAndroid Build Coastguard Worker // EVENT_MORE_DATA callback handling.
2676*ec779b8eSAndroid Build Coastguard Worker // Timing for linear pcm audio data formats can be derived directly from the
2677*ec779b8eSAndroid Build Coastguard Worker // buffer fill level.
2678*ec779b8eSAndroid Build Coastguard Worker // Timing for compressed data is not directly available from the buffer fill level,
2679*ec779b8eSAndroid Build Coastguard Worker // rather indirectly from waiting for blocking mode callbacks or waiting for obtain()
2680*ec779b8eSAndroid Build Coastguard Worker // to return a certain fill level.
2681*ec779b8eSAndroid Build Coastguard Worker
2682*ec779b8eSAndroid Build Coastguard Worker struct timespec timeout;
2683*ec779b8eSAndroid Build Coastguard Worker const struct timespec *requested = &ClientProxy::kForever;
2684*ec779b8eSAndroid Build Coastguard Worker if (ns != NS_WHENEVER) {
2685*ec779b8eSAndroid Build Coastguard Worker timeout.tv_sec = ns / 1000000000LL;
2686*ec779b8eSAndroid Build Coastguard Worker timeout.tv_nsec = ns % 1000000000LL;
2687*ec779b8eSAndroid Build Coastguard Worker ALOGV("%s(%d): timeout %ld.%03d",
2688*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId, timeout.tv_sec, (int) timeout.tv_nsec / 1000000);
2689*ec779b8eSAndroid Build Coastguard Worker requested = &timeout;
2690*ec779b8eSAndroid Build Coastguard Worker }
2691*ec779b8eSAndroid Build Coastguard Worker
2692*ec779b8eSAndroid Build Coastguard Worker size_t writtenFrames = 0;
2693*ec779b8eSAndroid Build Coastguard Worker while (mRemainingFrames > 0) {
2694*ec779b8eSAndroid Build Coastguard Worker
2695*ec779b8eSAndroid Build Coastguard Worker Buffer audioBuffer;
2696*ec779b8eSAndroid Build Coastguard Worker audioBuffer.frameCount = mRemainingFrames;
2697*ec779b8eSAndroid Build Coastguard Worker size_t nonContig;
2698*ec779b8eSAndroid Build Coastguard Worker status_t err = obtainBuffer(&audioBuffer, requested, NULL, &nonContig);
2699*ec779b8eSAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF((err != NO_ERROR) != (audioBuffer.frameCount == 0),
2700*ec779b8eSAndroid Build Coastguard Worker "%s(%d): obtainBuffer() err=%d frameCount=%zu",
2701*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId, err, audioBuffer.frameCount);
2702*ec779b8eSAndroid Build Coastguard Worker requested = &ClientProxy::kNonBlocking;
2703*ec779b8eSAndroid Build Coastguard Worker size_t avail = audioBuffer.frameCount + nonContig;
2704*ec779b8eSAndroid Build Coastguard Worker ALOGV("%s(%d): obtainBuffer(%u) returned %zu = %zu + %zu err %d",
2705*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId, mRemainingFrames, avail, audioBuffer.frameCount, nonContig, err);
2706*ec779b8eSAndroid Build Coastguard Worker if (err != NO_ERROR) {
2707*ec779b8eSAndroid Build Coastguard Worker if (err == TIMED_OUT || err == WOULD_BLOCK || err == -EINTR ||
2708*ec779b8eSAndroid Build Coastguard Worker (isOffloaded && (err == DEAD_OBJECT))) {
2709*ec779b8eSAndroid Build Coastguard Worker // FIXME bug 25195759
2710*ec779b8eSAndroid Build Coastguard Worker return 1000000;
2711*ec779b8eSAndroid Build Coastguard Worker }
2712*ec779b8eSAndroid Build Coastguard Worker ALOGE("%s(%d): Error %d obtaining an audio buffer, giving up.",
2713*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId, err);
2714*ec779b8eSAndroid Build Coastguard Worker return NS_NEVER;
2715*ec779b8eSAndroid Build Coastguard Worker }
2716*ec779b8eSAndroid Build Coastguard Worker
2717*ec779b8eSAndroid Build Coastguard Worker if (mRetryOnPartialBuffer && audio_has_proportional_frames(mFormat)) {
2718*ec779b8eSAndroid Build Coastguard Worker mRetryOnPartialBuffer = false;
2719*ec779b8eSAndroid Build Coastguard Worker if (avail < mRemainingFrames) {
2720*ec779b8eSAndroid Build Coastguard Worker if (ns > 0) { // account for obtain time
2721*ec779b8eSAndroid Build Coastguard Worker const nsecs_t timeNow = systemTime();
2722*ec779b8eSAndroid Build Coastguard Worker ns = max((nsecs_t)0, ns - (timeNow - timeAfterCallbacks));
2723*ec779b8eSAndroid Build Coastguard Worker }
2724*ec779b8eSAndroid Build Coastguard Worker
2725*ec779b8eSAndroid Build Coastguard Worker // delayNs is first computed by the additional frames required in the buffer.
2726*ec779b8eSAndroid Build Coastguard Worker nsecs_t delayNs = framesToNanoseconds(
2727*ec779b8eSAndroid Build Coastguard Worker mRemainingFrames - avail, sampleRate, speed);
2728*ec779b8eSAndroid Build Coastguard Worker
2729*ec779b8eSAndroid Build Coastguard Worker // afNs is the AudioFlinger mixer period in ns.
2730*ec779b8eSAndroid Build Coastguard Worker const nsecs_t afNs = framesToNanoseconds(mAfFrameCount, mAfSampleRate, speed);
2731*ec779b8eSAndroid Build Coastguard Worker
2732*ec779b8eSAndroid Build Coastguard Worker // If the AudioTrack is double buffered based on the AudioFlinger mixer period,
2733*ec779b8eSAndroid Build Coastguard Worker // we may have a race if we wait based on the number of frames desired.
2734*ec779b8eSAndroid Build Coastguard Worker // This is a possible issue with resampling and AAudio.
2735*ec779b8eSAndroid Build Coastguard Worker //
2736*ec779b8eSAndroid Build Coastguard Worker // The granularity of audioflinger processing is one mixer period; if
2737*ec779b8eSAndroid Build Coastguard Worker // our wait time is less than one mixer period, wait at most half the period.
2738*ec779b8eSAndroid Build Coastguard Worker if (delayNs < afNs) {
2739*ec779b8eSAndroid Build Coastguard Worker delayNs = std::min(delayNs, afNs / 2);
2740*ec779b8eSAndroid Build Coastguard Worker }
2741*ec779b8eSAndroid Build Coastguard Worker
2742*ec779b8eSAndroid Build Coastguard Worker // adjust our ns wait by delayNs.
2743*ec779b8eSAndroid Build Coastguard Worker if (ns < 0 /* NS_WHENEVER */ || delayNs < ns) {
2744*ec779b8eSAndroid Build Coastguard Worker ns = delayNs;
2745*ec779b8eSAndroid Build Coastguard Worker }
2746*ec779b8eSAndroid Build Coastguard Worker return ns;
2747*ec779b8eSAndroid Build Coastguard Worker }
2748*ec779b8eSAndroid Build Coastguard Worker }
2749*ec779b8eSAndroid Build Coastguard Worker
2750*ec779b8eSAndroid Build Coastguard Worker size_t reqSize = audioBuffer.size();
2751*ec779b8eSAndroid Build Coastguard Worker if (mTransfer == TRANSFER_SYNC_NOTIF_CALLBACK) {
2752*ec779b8eSAndroid Build Coastguard Worker // when notifying client it can write more data, pass the total size that can be
2753*ec779b8eSAndroid Build Coastguard Worker // written in the next write() call, since it's not passed through the callback
2754*ec779b8eSAndroid Build Coastguard Worker audioBuffer.mSize += nonContig;
2755*ec779b8eSAndroid Build Coastguard Worker }
2756*ec779b8eSAndroid Build Coastguard Worker const size_t writtenSize = (mTransfer == TRANSFER_CALLBACK)
2757*ec779b8eSAndroid Build Coastguard Worker ? callback->onMoreData(audioBuffer)
2758*ec779b8eSAndroid Build Coastguard Worker : callback->onCanWriteMoreData(audioBuffer);
2759*ec779b8eSAndroid Build Coastguard Worker // Validate on returned size
2760*ec779b8eSAndroid Build Coastguard Worker if (ssize_t(writtenSize) < 0 || writtenSize > reqSize) {
2761*ec779b8eSAndroid Build Coastguard Worker ALOGE("%s(%d): EVENT_MORE_DATA requested %zu bytes but callback returned %zd bytes",
2762*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId, reqSize, ssize_t(writtenSize));
2763*ec779b8eSAndroid Build Coastguard Worker return NS_NEVER;
2764*ec779b8eSAndroid Build Coastguard Worker }
2765*ec779b8eSAndroid Build Coastguard Worker
2766*ec779b8eSAndroid Build Coastguard Worker if (writtenSize == 0) {
2767*ec779b8eSAndroid Build Coastguard Worker if (mTransfer == TRANSFER_SYNC_NOTIF_CALLBACK) {
2768*ec779b8eSAndroid Build Coastguard Worker // The callback EVENT_CAN_WRITE_MORE_DATA was processed in the JNI of
2769*ec779b8eSAndroid Build Coastguard Worker // android.media.AudioTrack. The JNI is not using the callback to provide data,
2770*ec779b8eSAndroid Build Coastguard Worker // it only signals to the Java client that it can provide more data, which
2771*ec779b8eSAndroid Build Coastguard Worker // this track is read to accept now.
2772*ec779b8eSAndroid Build Coastguard Worker // The playback thread will be awaken at the next ::write()
2773*ec779b8eSAndroid Build Coastguard Worker return NS_WHENEVER;
2774*ec779b8eSAndroid Build Coastguard Worker }
2775*ec779b8eSAndroid Build Coastguard Worker // The callback is done filling buffers
2776*ec779b8eSAndroid Build Coastguard Worker // Keep this thread going to handle timed events and
2777*ec779b8eSAndroid Build Coastguard Worker // still try to get more data in intervals of WAIT_PERIOD_MS
2778*ec779b8eSAndroid Build Coastguard Worker // but don't just loop and block the CPU, so wait
2779*ec779b8eSAndroid Build Coastguard Worker
2780*ec779b8eSAndroid Build Coastguard Worker // mCbf(EVENT_MORE_DATA, ...) might either
2781*ec779b8eSAndroid Build Coastguard Worker // (1) Block until it can fill the buffer, returning 0 size on EOS.
2782*ec779b8eSAndroid Build Coastguard Worker // (2) Block until it can fill the buffer, returning 0 data (silence) on EOS.
2783*ec779b8eSAndroid Build Coastguard Worker // (3) Return 0 size when no data is available, does not wait for more data.
2784*ec779b8eSAndroid Build Coastguard Worker //
2785*ec779b8eSAndroid Build Coastguard Worker // (1) and (2) occurs with AudioPlayer/AwesomePlayer; (3) occurs with NuPlayer.
2786*ec779b8eSAndroid Build Coastguard Worker // We try to compute the wait time to avoid a tight sleep-wait cycle,
2787*ec779b8eSAndroid Build Coastguard Worker // especially for case (3).
2788*ec779b8eSAndroid Build Coastguard Worker //
2789*ec779b8eSAndroid Build Coastguard Worker // The decision to support (1) and (2) affect the sizing of mRemainingFrames
2790*ec779b8eSAndroid Build Coastguard Worker // and this loop; whereas for case (3) we could simply check once with the full
2791*ec779b8eSAndroid Build Coastguard Worker // buffer size and skip the loop entirely.
2792*ec779b8eSAndroid Build Coastguard Worker
2793*ec779b8eSAndroid Build Coastguard Worker nsecs_t myns;
2794*ec779b8eSAndroid Build Coastguard Worker if (!isOffloaded && audio_has_proportional_frames(mFormat)) {
2795*ec779b8eSAndroid Build Coastguard Worker // time to wait based on buffer occupancy
2796*ec779b8eSAndroid Build Coastguard Worker const nsecs_t datans = mRemainingFrames <= avail ? 0 :
2797*ec779b8eSAndroid Build Coastguard Worker framesToNanoseconds(mRemainingFrames - avail, sampleRate, speed);
2798*ec779b8eSAndroid Build Coastguard Worker // audio flinger thread buffer size (TODO: adjust for fast tracks)
2799*ec779b8eSAndroid Build Coastguard Worker // FIXME: use mAfFrameCountHAL instead of mAfFrameCount below for fast tracks.
2800*ec779b8eSAndroid Build Coastguard Worker const nsecs_t afns = framesToNanoseconds(mAfFrameCount, mAfSampleRate, speed);
2801*ec779b8eSAndroid Build Coastguard Worker // add a half the AudioFlinger buffer time to avoid soaking CPU if datans is 0.
2802*ec779b8eSAndroid Build Coastguard Worker myns = datans + (afns / 2);
2803*ec779b8eSAndroid Build Coastguard Worker } else {
2804*ec779b8eSAndroid Build Coastguard Worker // FIXME: This could ping quite a bit if the buffer isn't full.
2805*ec779b8eSAndroid Build Coastguard Worker // Note that when mState is stopping we waitStreamEnd, so it never gets here.
2806*ec779b8eSAndroid Build Coastguard Worker myns = kWaitPeriodNs;
2807*ec779b8eSAndroid Build Coastguard Worker }
2808*ec779b8eSAndroid Build Coastguard Worker if (ns > 0) { // account for obtain and callback time
2809*ec779b8eSAndroid Build Coastguard Worker const nsecs_t timeNow = systemTime();
2810*ec779b8eSAndroid Build Coastguard Worker ns = max((nsecs_t)0, ns - (timeNow - timeAfterCallbacks));
2811*ec779b8eSAndroid Build Coastguard Worker }
2812*ec779b8eSAndroid Build Coastguard Worker if (ns < 0 /* NS_WHENEVER */ || myns < ns) {
2813*ec779b8eSAndroid Build Coastguard Worker ns = myns;
2814*ec779b8eSAndroid Build Coastguard Worker }
2815*ec779b8eSAndroid Build Coastguard Worker return ns;
2816*ec779b8eSAndroid Build Coastguard Worker }
2817*ec779b8eSAndroid Build Coastguard Worker
2818*ec779b8eSAndroid Build Coastguard Worker // releaseBuffer reads from audioBuffer.size
2819*ec779b8eSAndroid Build Coastguard Worker audioBuffer.mSize = writtenSize;
2820*ec779b8eSAndroid Build Coastguard Worker
2821*ec779b8eSAndroid Build Coastguard Worker size_t releasedFrames = writtenSize / mFrameSize;
2822*ec779b8eSAndroid Build Coastguard Worker audioBuffer.frameCount = releasedFrames;
2823*ec779b8eSAndroid Build Coastguard Worker mRemainingFrames -= releasedFrames;
2824*ec779b8eSAndroid Build Coastguard Worker if (misalignment >= releasedFrames) {
2825*ec779b8eSAndroid Build Coastguard Worker misalignment -= releasedFrames;
2826*ec779b8eSAndroid Build Coastguard Worker } else {
2827*ec779b8eSAndroid Build Coastguard Worker misalignment = 0;
2828*ec779b8eSAndroid Build Coastguard Worker }
2829*ec779b8eSAndroid Build Coastguard Worker
2830*ec779b8eSAndroid Build Coastguard Worker releaseBuffer(&audioBuffer);
2831*ec779b8eSAndroid Build Coastguard Worker writtenFrames += releasedFrames;
2832*ec779b8eSAndroid Build Coastguard Worker
2833*ec779b8eSAndroid Build Coastguard Worker // FIXME here is where we would repeat EVENT_MORE_DATA again on same advanced buffer
2834*ec779b8eSAndroid Build Coastguard Worker // if callback doesn't like to accept the full chunk
2835*ec779b8eSAndroid Build Coastguard Worker if (writtenSize < reqSize) {
2836*ec779b8eSAndroid Build Coastguard Worker continue;
2837*ec779b8eSAndroid Build Coastguard Worker }
2838*ec779b8eSAndroid Build Coastguard Worker
2839*ec779b8eSAndroid Build Coastguard Worker // There could be enough non-contiguous frames available to satisfy the remaining request
2840*ec779b8eSAndroid Build Coastguard Worker if (mRemainingFrames <= nonContig) {
2841*ec779b8eSAndroid Build Coastguard Worker continue;
2842*ec779b8eSAndroid Build Coastguard Worker }
2843*ec779b8eSAndroid Build Coastguard Worker
2844*ec779b8eSAndroid Build Coastguard Worker #if 0
2845*ec779b8eSAndroid Build Coastguard Worker // This heuristic tries to collapse a series of EVENT_MORE_DATA that would total to a
2846*ec779b8eSAndroid Build Coastguard Worker // sum <= notificationFrames. It replaces that series by at most two EVENT_MORE_DATA
2847*ec779b8eSAndroid Build Coastguard Worker // that total to a sum == notificationFrames.
2848*ec779b8eSAndroid Build Coastguard Worker if (0 < misalignment && misalignment <= mRemainingFrames) {
2849*ec779b8eSAndroid Build Coastguard Worker mRemainingFrames = misalignment;
2850*ec779b8eSAndroid Build Coastguard Worker return ((double)mRemainingFrames * 1100000000) / ((double)sampleRate * speed);
2851*ec779b8eSAndroid Build Coastguard Worker }
2852*ec779b8eSAndroid Build Coastguard Worker #endif
2853*ec779b8eSAndroid Build Coastguard Worker
2854*ec779b8eSAndroid Build Coastguard Worker }
2855*ec779b8eSAndroid Build Coastguard Worker if (writtenFrames > 0) {
2856*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
2857*ec779b8eSAndroid Build Coastguard Worker mFramesWritten += writtenFrames;
2858*ec779b8eSAndroid Build Coastguard Worker }
2859*ec779b8eSAndroid Build Coastguard Worker mRemainingFrames = notificationFrames;
2860*ec779b8eSAndroid Build Coastguard Worker mRetryOnPartialBuffer = true;
2861*ec779b8eSAndroid Build Coastguard Worker
2862*ec779b8eSAndroid Build Coastguard Worker // A lot has transpired since ns was calculated, so run again immediately and re-calculate
2863*ec779b8eSAndroid Build Coastguard Worker return 0;
2864*ec779b8eSAndroid Build Coastguard Worker }
2865*ec779b8eSAndroid Build Coastguard Worker
restoreTrack_l(const char * from,bool forceRestore)2866*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::restoreTrack_l(const char *from, bool forceRestore)
2867*ec779b8eSAndroid Build Coastguard Worker {
2868*ec779b8eSAndroid Build Coastguard Worker status_t result = NO_ERROR; // logged: make sure to set this before returning.
2869*ec779b8eSAndroid Build Coastguard Worker const int64_t beginNs = systemTime();
2870*ec779b8eSAndroid Build Coastguard Worker mediametrics::Defer defer([&] {
2871*ec779b8eSAndroid Build Coastguard Worker mediametrics::LogItem(mMetricsId)
2872*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_RESTORE)
2873*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(systemTime() - beginNs))
2874*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
2875*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)result)
2876*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_WHERE, from)
2877*ec779b8eSAndroid Build Coastguard Worker .record(); });
2878*ec779b8eSAndroid Build Coastguard Worker
2879*ec779b8eSAndroid Build Coastguard Worker ALOGW("%s(%d): dead IAudioTrack, %s, creating a new one from %s()",
2880*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId, isOffloadedOrDirect_l() ? "Offloaded or Direct" : "PCM", from);
2881*ec779b8eSAndroid Build Coastguard Worker ++mSequence;
2882*ec779b8eSAndroid Build Coastguard Worker
2883*ec779b8eSAndroid Build Coastguard Worker if (!forceRestore &&
2884*ec779b8eSAndroid Build Coastguard Worker (isOffloadedOrDirect_l() || mDoNotReconnect)) {
2885*ec779b8eSAndroid Build Coastguard Worker // FIXME re-creation of offloaded and direct tracks is not yet implemented;
2886*ec779b8eSAndroid Build Coastguard Worker // Disabled since (1) timestamp correction is not implemented for non-PCM and
2887*ec779b8eSAndroid Build Coastguard Worker // (2) We pre-empt existing direct tracks on resource constraint, so these tracks
2888*ec779b8eSAndroid Build Coastguard Worker // shouldn't reconnect.
2889*ec779b8eSAndroid Build Coastguard Worker result = DEAD_OBJECT;
2890*ec779b8eSAndroid Build Coastguard Worker return result;
2891*ec779b8eSAndroid Build Coastguard Worker }
2892*ec779b8eSAndroid Build Coastguard Worker
2893*ec779b8eSAndroid Build Coastguard Worker // Save so we can return count since creation.
2894*ec779b8eSAndroid Build Coastguard Worker mUnderrunCountOffset = getUnderrunCount_l();
2895*ec779b8eSAndroid Build Coastguard Worker
2896*ec779b8eSAndroid Build Coastguard Worker // save the old static buffer position
2897*ec779b8eSAndroid Build Coastguard Worker uint32_t staticPosition = 0;
2898*ec779b8eSAndroid Build Coastguard Worker size_t bufferPosition = 0;
2899*ec779b8eSAndroid Build Coastguard Worker int loopCount = 0;
2900*ec779b8eSAndroid Build Coastguard Worker if (mStaticProxy != 0) {
2901*ec779b8eSAndroid Build Coastguard Worker mStaticProxy->getBufferPositionAndLoopCount(&bufferPosition, &loopCount);
2902*ec779b8eSAndroid Build Coastguard Worker staticPosition = mStaticProxy->getPosition().unsignedValue();
2903*ec779b8eSAndroid Build Coastguard Worker }
2904*ec779b8eSAndroid Build Coastguard Worker
2905*ec779b8eSAndroid Build Coastguard Worker // save the old startThreshold and framecount
2906*ec779b8eSAndroid Build Coastguard Worker const uint32_t originalStartThresholdInFrames = mProxy->getStartThresholdInFrames();
2907*ec779b8eSAndroid Build Coastguard Worker const uint32_t originalFrameCount = mProxy->frameCount();
2908*ec779b8eSAndroid Build Coastguard Worker
2909*ec779b8eSAndroid Build Coastguard Worker // See b/74409267. Connecting to a BT A2DP device supporting multiple codecs
2910*ec779b8eSAndroid Build Coastguard Worker // causes a lot of churn on the service side, and it can reject starting
2911*ec779b8eSAndroid Build Coastguard Worker // playback of a previously created track. May also apply to other cases.
2912*ec779b8eSAndroid Build Coastguard Worker const int INITIAL_RETRIES = 3;
2913*ec779b8eSAndroid Build Coastguard Worker int retries = INITIAL_RETRIES;
2914*ec779b8eSAndroid Build Coastguard Worker retry:
2915*ec779b8eSAndroid Build Coastguard Worker mFlags = mOrigFlags;
2916*ec779b8eSAndroid Build Coastguard Worker
2917*ec779b8eSAndroid Build Coastguard Worker // If a new IAudioTrack is successfully created, createTrack_l() will modify the
2918*ec779b8eSAndroid Build Coastguard Worker // following member variables: mAudioTrack, mCblkMemory and mCblk.
2919*ec779b8eSAndroid Build Coastguard Worker // It will also delete the strong references on previous IAudioTrack and IMemory.
2920*ec779b8eSAndroid Build Coastguard Worker // If a new IAudioTrack cannot be created, the previous (dead) instance will be left intact.
2921*ec779b8eSAndroid Build Coastguard Worker result = createTrack_l();
2922*ec779b8eSAndroid Build Coastguard Worker
2923*ec779b8eSAndroid Build Coastguard Worker if (result == NO_ERROR) {
2924*ec779b8eSAndroid Build Coastguard Worker // take the frames that will be lost by track recreation into account in saved position
2925*ec779b8eSAndroid Build Coastguard Worker // For streaming tracks, this is the amount we obtained from the user/client
2926*ec779b8eSAndroid Build Coastguard Worker // (not the number actually consumed at the server - those are already lost).
2927*ec779b8eSAndroid Build Coastguard Worker if (mStaticProxy == 0) {
2928*ec779b8eSAndroid Build Coastguard Worker mPosition = mReleased;
2929*ec779b8eSAndroid Build Coastguard Worker }
2930*ec779b8eSAndroid Build Coastguard Worker // Continue playback from last known position and restore loop.
2931*ec779b8eSAndroid Build Coastguard Worker if (mStaticProxy != 0) {
2932*ec779b8eSAndroid Build Coastguard Worker if (loopCount != 0) {
2933*ec779b8eSAndroid Build Coastguard Worker mStaticProxy->setBufferPositionAndLoop(bufferPosition,
2934*ec779b8eSAndroid Build Coastguard Worker mLoopStart, mLoopEnd, loopCount);
2935*ec779b8eSAndroid Build Coastguard Worker } else {
2936*ec779b8eSAndroid Build Coastguard Worker mStaticProxy->setBufferPosition(bufferPosition);
2937*ec779b8eSAndroid Build Coastguard Worker if (bufferPosition == mFrameCount) {
2938*ec779b8eSAndroid Build Coastguard Worker ALOGD("%s(%d): restoring track at end of static buffer", __func__, mPortId);
2939*ec779b8eSAndroid Build Coastguard Worker }
2940*ec779b8eSAndroid Build Coastguard Worker }
2941*ec779b8eSAndroid Build Coastguard Worker }
2942*ec779b8eSAndroid Build Coastguard Worker // restore volume handler
2943*ec779b8eSAndroid Build Coastguard Worker mVolumeHandler->forall([this](const VolumeShaper &shaper) -> VolumeShaper::Status {
2944*ec779b8eSAndroid Build Coastguard Worker sp<VolumeShaper::Operation> operationToEnd =
2945*ec779b8eSAndroid Build Coastguard Worker new VolumeShaper::Operation(shaper.mOperation);
2946*ec779b8eSAndroid Build Coastguard Worker // TODO: Ideally we would restore to the exact xOffset position
2947*ec779b8eSAndroid Build Coastguard Worker // as returned by getVolumeShaperState(), but we don't have that
2948*ec779b8eSAndroid Build Coastguard Worker // information when restoring at the client unless we periodically poll
2949*ec779b8eSAndroid Build Coastguard Worker // the server or create shared memory state.
2950*ec779b8eSAndroid Build Coastguard Worker //
2951*ec779b8eSAndroid Build Coastguard Worker // For now, we simply advance to the end of the VolumeShaper effect
2952*ec779b8eSAndroid Build Coastguard Worker // if it has been started.
2953*ec779b8eSAndroid Build Coastguard Worker if (shaper.isStarted()) {
2954*ec779b8eSAndroid Build Coastguard Worker operationToEnd->setNormalizedTime(1.f);
2955*ec779b8eSAndroid Build Coastguard Worker }
2956*ec779b8eSAndroid Build Coastguard Worker media::VolumeShaperConfiguration config;
2957*ec779b8eSAndroid Build Coastguard Worker shaper.mConfiguration->writeToParcelable(&config);
2958*ec779b8eSAndroid Build Coastguard Worker media::VolumeShaperOperation operation;
2959*ec779b8eSAndroid Build Coastguard Worker operationToEnd->writeToParcelable(&operation);
2960*ec779b8eSAndroid Build Coastguard Worker status_t status;
2961*ec779b8eSAndroid Build Coastguard Worker mAudioTrack->applyVolumeShaper(config, operation, &status);
2962*ec779b8eSAndroid Build Coastguard Worker return status;
2963*ec779b8eSAndroid Build Coastguard Worker });
2964*ec779b8eSAndroid Build Coastguard Worker
2965*ec779b8eSAndroid Build Coastguard Worker // restore the original start threshold if different than frameCount.
2966*ec779b8eSAndroid Build Coastguard Worker if (originalStartThresholdInFrames != originalFrameCount) {
2967*ec779b8eSAndroid Build Coastguard Worker // Note: mProxy->setStartThresholdInFrames() call is in the Proxy
2968*ec779b8eSAndroid Build Coastguard Worker // and does not trigger a restart.
2969*ec779b8eSAndroid Build Coastguard Worker // (Also CBLK_DISABLED is not set, buffers are empty after track recreation).
2970*ec779b8eSAndroid Build Coastguard Worker // Any start would be triggered on the mState == ACTIVE check below.
2971*ec779b8eSAndroid Build Coastguard Worker const uint32_t currentThreshold =
2972*ec779b8eSAndroid Build Coastguard Worker mProxy->setStartThresholdInFrames(originalStartThresholdInFrames);
2973*ec779b8eSAndroid Build Coastguard Worker ALOGD_IF(originalStartThresholdInFrames != currentThreshold,
2974*ec779b8eSAndroid Build Coastguard Worker "%s(%d) startThresholdInFrames changing from %u to %u",
2975*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId, originalStartThresholdInFrames, currentThreshold);
2976*ec779b8eSAndroid Build Coastguard Worker }
2977*ec779b8eSAndroid Build Coastguard Worker if (mState == STATE_ACTIVE) {
2978*ec779b8eSAndroid Build Coastguard Worker mAudioTrack->start(&result);
2979*ec779b8eSAndroid Build Coastguard Worker }
2980*ec779b8eSAndroid Build Coastguard Worker // server resets to zero so we offset
2981*ec779b8eSAndroid Build Coastguard Worker mFramesWrittenServerOffset =
2982*ec779b8eSAndroid Build Coastguard Worker mStaticProxy.get() != nullptr ? staticPosition : mFramesWritten;
2983*ec779b8eSAndroid Build Coastguard Worker mFramesWrittenAtRestore = mFramesWrittenServerOffset;
2984*ec779b8eSAndroid Build Coastguard Worker }
2985*ec779b8eSAndroid Build Coastguard Worker if (result != NO_ERROR) {
2986*ec779b8eSAndroid Build Coastguard Worker ALOGW("%s(%d): failed status %d, retries %d", __func__, mPortId, result, retries);
2987*ec779b8eSAndroid Build Coastguard Worker if (--retries > 0) {
2988*ec779b8eSAndroid Build Coastguard Worker // leave time for an eventual race condition to clear before retrying
2989*ec779b8eSAndroid Build Coastguard Worker usleep(500000);
2990*ec779b8eSAndroid Build Coastguard Worker goto retry;
2991*ec779b8eSAndroid Build Coastguard Worker }
2992*ec779b8eSAndroid Build Coastguard Worker // if no retries left, set invalid bit to force restoring at next occasion
2993*ec779b8eSAndroid Build Coastguard Worker // and avoid inconsistent active state on client and server sides
2994*ec779b8eSAndroid Build Coastguard Worker if (mCblk != nullptr) {
2995*ec779b8eSAndroid Build Coastguard Worker android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
2996*ec779b8eSAndroid Build Coastguard Worker }
2997*ec779b8eSAndroid Build Coastguard Worker }
2998*ec779b8eSAndroid Build Coastguard Worker return result;
2999*ec779b8eSAndroid Build Coastguard Worker }
3000*ec779b8eSAndroid Build Coastguard Worker
updateAndGetPosition_l()3001*ec779b8eSAndroid Build Coastguard Worker Modulo<uint32_t> AudioTrack::updateAndGetPosition_l()
3002*ec779b8eSAndroid Build Coastguard Worker {
3003*ec779b8eSAndroid Build Coastguard Worker // This is the sole place to read server consumed frames
3004*ec779b8eSAndroid Build Coastguard Worker Modulo<uint32_t> newServer(mProxy->getPosition());
3005*ec779b8eSAndroid Build Coastguard Worker const int32_t delta = (newServer - mServer).signedValue();
3006*ec779b8eSAndroid Build Coastguard Worker // TODO There is controversy about whether there can be "negative jitter" in server position.
3007*ec779b8eSAndroid Build Coastguard Worker // This should be investigated further, and if possible, it should be addressed.
3008*ec779b8eSAndroid Build Coastguard Worker // A more definite failure mode is infrequent polling by client.
3009*ec779b8eSAndroid Build Coastguard Worker // One could call (void)getPosition_l() in releaseBuffer(),
3010*ec779b8eSAndroid Build Coastguard Worker // so mReleased and mPosition are always lock-step as best possible.
3011*ec779b8eSAndroid Build Coastguard Worker // That should ensure delta never goes negative for infrequent polling
3012*ec779b8eSAndroid Build Coastguard Worker // unless the server has more than 2^31 frames in its buffer,
3013*ec779b8eSAndroid Build Coastguard Worker // in which case the use of uint32_t for these counters has bigger issues.
3014*ec779b8eSAndroid Build Coastguard Worker ALOGE_IF(delta < 0,
3015*ec779b8eSAndroid Build Coastguard Worker "%s(%d): detected illegal retrograde motion by the server: mServer advanced by %d",
3016*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId, delta);
3017*ec779b8eSAndroid Build Coastguard Worker mServer = newServer;
3018*ec779b8eSAndroid Build Coastguard Worker if (delta > 0) { // avoid retrograde
3019*ec779b8eSAndroid Build Coastguard Worker mPosition += delta;
3020*ec779b8eSAndroid Build Coastguard Worker }
3021*ec779b8eSAndroid Build Coastguard Worker return mPosition;
3022*ec779b8eSAndroid Build Coastguard Worker }
3023*ec779b8eSAndroid Build Coastguard Worker
isSampleRateSpeedAllowed_l(uint32_t sampleRate,float speed)3024*ec779b8eSAndroid Build Coastguard Worker bool AudioTrack::isSampleRateSpeedAllowed_l(uint32_t sampleRate, float speed)
3025*ec779b8eSAndroid Build Coastguard Worker {
3026*ec779b8eSAndroid Build Coastguard Worker updateLatency_l();
3027*ec779b8eSAndroid Build Coastguard Worker // applicable for mixing tracks only (not offloaded or direct)
3028*ec779b8eSAndroid Build Coastguard Worker if (mStaticProxy != 0) {
3029*ec779b8eSAndroid Build Coastguard Worker return true; // static tracks do not have issues with buffer sizing.
3030*ec779b8eSAndroid Build Coastguard Worker }
3031*ec779b8eSAndroid Build Coastguard Worker const size_t minFrameCount =
3032*ec779b8eSAndroid Build Coastguard Worker AudioSystem::calculateMinFrameCount(mAfLatency, mAfFrameCount, mAfSampleRate,
3033*ec779b8eSAndroid Build Coastguard Worker sampleRate, speed /*, 0 mNotificationsPerBufferReq*/);
3034*ec779b8eSAndroid Build Coastguard Worker const bool allowed = mFrameCount >= minFrameCount;
3035*ec779b8eSAndroid Build Coastguard Worker ALOGD_IF(!allowed,
3036*ec779b8eSAndroid Build Coastguard Worker "%s(%d): denied "
3037*ec779b8eSAndroid Build Coastguard Worker "mAfLatency:%u mAfFrameCount:%zu mAfSampleRate:%u sampleRate:%u speed:%f "
3038*ec779b8eSAndroid Build Coastguard Worker "mFrameCount:%zu < minFrameCount:%zu",
3039*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId,
3040*ec779b8eSAndroid Build Coastguard Worker mAfLatency, mAfFrameCount, mAfSampleRate, sampleRate, speed,
3041*ec779b8eSAndroid Build Coastguard Worker mFrameCount, minFrameCount);
3042*ec779b8eSAndroid Build Coastguard Worker return allowed;
3043*ec779b8eSAndroid Build Coastguard Worker }
3044*ec779b8eSAndroid Build Coastguard Worker
setParameters(const String8 & keyValuePairs)3045*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::setParameters(const String8& keyValuePairs)
3046*ec779b8eSAndroid Build Coastguard Worker {
3047*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
3048*ec779b8eSAndroid Build Coastguard Worker status_t status;
3049*ec779b8eSAndroid Build Coastguard Worker mAudioTrack->setParameters(keyValuePairs.c_str(), &status);
3050*ec779b8eSAndroid Build Coastguard Worker return status;
3051*ec779b8eSAndroid Build Coastguard Worker }
3052*ec779b8eSAndroid Build Coastguard Worker
selectPresentation(int presentationId,int programId)3053*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::selectPresentation(int presentationId, int programId)
3054*ec779b8eSAndroid Build Coastguard Worker {
3055*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
3056*ec779b8eSAndroid Build Coastguard Worker AudioParameter param = AudioParameter();
3057*ec779b8eSAndroid Build Coastguard Worker param.addInt(String8(AudioParameter::keyPresentationId), presentationId);
3058*ec779b8eSAndroid Build Coastguard Worker param.addInt(String8(AudioParameter::keyProgramId), programId);
3059*ec779b8eSAndroid Build Coastguard Worker ALOGV("%s(%d): PresentationId/ProgramId[%s]",
3060*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId, param.toString().c_str());
3061*ec779b8eSAndroid Build Coastguard Worker
3062*ec779b8eSAndroid Build Coastguard Worker status_t status;
3063*ec779b8eSAndroid Build Coastguard Worker mAudioTrack->setParameters(param.toString().c_str(), &status);
3064*ec779b8eSAndroid Build Coastguard Worker return status;
3065*ec779b8eSAndroid Build Coastguard Worker }
3066*ec779b8eSAndroid Build Coastguard Worker
applyVolumeShaper(const sp<VolumeShaper::Configuration> & configuration,const sp<VolumeShaper::Operation> & operation)3067*ec779b8eSAndroid Build Coastguard Worker VolumeShaper::Status AudioTrack::applyVolumeShaper(
3068*ec779b8eSAndroid Build Coastguard Worker const sp<VolumeShaper::Configuration>& configuration,
3069*ec779b8eSAndroid Build Coastguard Worker const sp<VolumeShaper::Operation>& operation)
3070*ec779b8eSAndroid Build Coastguard Worker {
3071*ec779b8eSAndroid Build Coastguard Worker const int64_t beginNs = systemTime();
3072*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
3073*ec779b8eSAndroid Build Coastguard Worker mVolumeHandler->setIdIfNecessary(configuration);
3074*ec779b8eSAndroid Build Coastguard Worker media::VolumeShaperConfiguration config;
3075*ec779b8eSAndroid Build Coastguard Worker configuration->writeToParcelable(&config);
3076*ec779b8eSAndroid Build Coastguard Worker media::VolumeShaperOperation op;
3077*ec779b8eSAndroid Build Coastguard Worker operation->writeToParcelable(&op);
3078*ec779b8eSAndroid Build Coastguard Worker VolumeShaper::Status status;
3079*ec779b8eSAndroid Build Coastguard Worker
3080*ec779b8eSAndroid Build Coastguard Worker mediametrics::Defer defer([&] {
3081*ec779b8eSAndroid Build Coastguard Worker mediametrics::LogItem(mMetricsId)
3082*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_APPLYVOLUMESHAPER)
3083*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(systemTime() - beginNs))
3084*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
3085*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)status)
3086*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_TOSTRING, configuration->toString()
3087*ec779b8eSAndroid Build Coastguard Worker .append(" ")
3088*ec779b8eSAndroid Build Coastguard Worker .append(operation->toString()))
3089*ec779b8eSAndroid Build Coastguard Worker .record(); });
3090*ec779b8eSAndroid Build Coastguard Worker
3091*ec779b8eSAndroid Build Coastguard Worker mAudioTrack->applyVolumeShaper(config, op, &status);
3092*ec779b8eSAndroid Build Coastguard Worker
3093*ec779b8eSAndroid Build Coastguard Worker if (status == DEAD_OBJECT) {
3094*ec779b8eSAndroid Build Coastguard Worker if (restoreTrack_l("applyVolumeShaper") == OK) {
3095*ec779b8eSAndroid Build Coastguard Worker mAudioTrack->applyVolumeShaper(config, op, &status);
3096*ec779b8eSAndroid Build Coastguard Worker }
3097*ec779b8eSAndroid Build Coastguard Worker }
3098*ec779b8eSAndroid Build Coastguard Worker if (status >= 0) {
3099*ec779b8eSAndroid Build Coastguard Worker // save VolumeShaper for restore
3100*ec779b8eSAndroid Build Coastguard Worker mVolumeHandler->applyVolumeShaper(configuration, operation);
3101*ec779b8eSAndroid Build Coastguard Worker if (mState == STATE_ACTIVE || mState == STATE_STOPPING) {
3102*ec779b8eSAndroid Build Coastguard Worker mVolumeHandler->setStarted();
3103*ec779b8eSAndroid Build Coastguard Worker }
3104*ec779b8eSAndroid Build Coastguard Worker } else {
3105*ec779b8eSAndroid Build Coastguard Worker // warn only if not an expected restore failure.
3106*ec779b8eSAndroid Build Coastguard Worker ALOGW_IF(!((isOffloadedOrDirect_l() || mDoNotReconnect) && status == DEAD_OBJECT),
3107*ec779b8eSAndroid Build Coastguard Worker "%s(%d): applyVolumeShaper failed: %d", __func__, mPortId, status);
3108*ec779b8eSAndroid Build Coastguard Worker }
3109*ec779b8eSAndroid Build Coastguard Worker return status;
3110*ec779b8eSAndroid Build Coastguard Worker }
3111*ec779b8eSAndroid Build Coastguard Worker
getVolumeShaperState(int id)3112*ec779b8eSAndroid Build Coastguard Worker sp<VolumeShaper::State> AudioTrack::getVolumeShaperState(int id)
3113*ec779b8eSAndroid Build Coastguard Worker {
3114*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
3115*ec779b8eSAndroid Build Coastguard Worker std::optional<media::VolumeShaperState> vss;
3116*ec779b8eSAndroid Build Coastguard Worker mAudioTrack->getVolumeShaperState(id, &vss);
3117*ec779b8eSAndroid Build Coastguard Worker sp<VolumeShaper::State> state;
3118*ec779b8eSAndroid Build Coastguard Worker if (vss.has_value()) {
3119*ec779b8eSAndroid Build Coastguard Worker state = new VolumeShaper::State();
3120*ec779b8eSAndroid Build Coastguard Worker state->readFromParcelable(vss.value());
3121*ec779b8eSAndroid Build Coastguard Worker }
3122*ec779b8eSAndroid Build Coastguard Worker if (state.get() == nullptr && (mCblk->mFlags & CBLK_INVALID) != 0) {
3123*ec779b8eSAndroid Build Coastguard Worker if (restoreTrack_l("getVolumeShaperState") == OK) {
3124*ec779b8eSAndroid Build Coastguard Worker mAudioTrack->getVolumeShaperState(id, &vss);
3125*ec779b8eSAndroid Build Coastguard Worker if (vss.has_value()) {
3126*ec779b8eSAndroid Build Coastguard Worker state = new VolumeShaper::State();
3127*ec779b8eSAndroid Build Coastguard Worker state->readFromParcelable(vss.value());
3128*ec779b8eSAndroid Build Coastguard Worker }
3129*ec779b8eSAndroid Build Coastguard Worker }
3130*ec779b8eSAndroid Build Coastguard Worker }
3131*ec779b8eSAndroid Build Coastguard Worker return state;
3132*ec779b8eSAndroid Build Coastguard Worker }
3133*ec779b8eSAndroid Build Coastguard Worker
getTimestamp(ExtendedTimestamp * timestamp)3134*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::getTimestamp(ExtendedTimestamp *timestamp)
3135*ec779b8eSAndroid Build Coastguard Worker {
3136*ec779b8eSAndroid Build Coastguard Worker if (timestamp == nullptr) {
3137*ec779b8eSAndroid Build Coastguard Worker return BAD_VALUE;
3138*ec779b8eSAndroid Build Coastguard Worker }
3139*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
3140*ec779b8eSAndroid Build Coastguard Worker return getTimestamp_l(timestamp);
3141*ec779b8eSAndroid Build Coastguard Worker }
3142*ec779b8eSAndroid Build Coastguard Worker
getTimestamp_l(ExtendedTimestamp * timestamp)3143*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::getTimestamp_l(ExtendedTimestamp *timestamp)
3144*ec779b8eSAndroid Build Coastguard Worker {
3145*ec779b8eSAndroid Build Coastguard Worker if (mCblk->mFlags & CBLK_INVALID) {
3146*ec779b8eSAndroid Build Coastguard Worker const status_t status = restoreTrack_l("getTimestampExtended");
3147*ec779b8eSAndroid Build Coastguard Worker if (status != OK) {
3148*ec779b8eSAndroid Build Coastguard Worker // per getTimestamp() API doc in header, we return DEAD_OBJECT here,
3149*ec779b8eSAndroid Build Coastguard Worker // recommending that the track be recreated.
3150*ec779b8eSAndroid Build Coastguard Worker return DEAD_OBJECT;
3151*ec779b8eSAndroid Build Coastguard Worker }
3152*ec779b8eSAndroid Build Coastguard Worker }
3153*ec779b8eSAndroid Build Coastguard Worker // check for offloaded/direct here in case restoring somehow changed those flags.
3154*ec779b8eSAndroid Build Coastguard Worker if (isOffloadedOrDirect_l()) {
3155*ec779b8eSAndroid Build Coastguard Worker return INVALID_OPERATION; // not supported
3156*ec779b8eSAndroid Build Coastguard Worker }
3157*ec779b8eSAndroid Build Coastguard Worker status_t status = mProxy->getTimestamp(timestamp);
3158*ec779b8eSAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(status != OK, "%s(%d): status %d not allowed from proxy getTimestamp",
3159*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId, status);
3160*ec779b8eSAndroid Build Coastguard Worker bool found = false;
3161*ec779b8eSAndroid Build Coastguard Worker timestamp->mPosition[ExtendedTimestamp::LOCATION_CLIENT] = mFramesWritten;
3162*ec779b8eSAndroid Build Coastguard Worker timestamp->mTimeNs[ExtendedTimestamp::LOCATION_CLIENT] = 0;
3163*ec779b8eSAndroid Build Coastguard Worker // server side frame offset in case AudioTrack has been restored.
3164*ec779b8eSAndroid Build Coastguard Worker for (int i = ExtendedTimestamp::LOCATION_SERVER;
3165*ec779b8eSAndroid Build Coastguard Worker i < ExtendedTimestamp::LOCATION_MAX; ++i) {
3166*ec779b8eSAndroid Build Coastguard Worker if (timestamp->mTimeNs[i] >= 0) {
3167*ec779b8eSAndroid Build Coastguard Worker // apply server offset (frames flushed is ignored
3168*ec779b8eSAndroid Build Coastguard Worker // so we don't report the jump when the flush occurs).
3169*ec779b8eSAndroid Build Coastguard Worker timestamp->mPosition[i] += mFramesWrittenServerOffset;
3170*ec779b8eSAndroid Build Coastguard Worker found = true;
3171*ec779b8eSAndroid Build Coastguard Worker }
3172*ec779b8eSAndroid Build Coastguard Worker }
3173*ec779b8eSAndroid Build Coastguard Worker return found ? OK : WOULD_BLOCK;
3174*ec779b8eSAndroid Build Coastguard Worker }
3175*ec779b8eSAndroid Build Coastguard Worker
getTimestamp(AudioTimestamp & timestamp)3176*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::getTimestamp(AudioTimestamp& timestamp)
3177*ec779b8eSAndroid Build Coastguard Worker {
3178*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
3179*ec779b8eSAndroid Build Coastguard Worker return getTimestamp_l(timestamp);
3180*ec779b8eSAndroid Build Coastguard Worker }
3181*ec779b8eSAndroid Build Coastguard Worker
getTimestamp_l(AudioTimestamp & timestamp)3182*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::getTimestamp_l(AudioTimestamp& timestamp)
3183*ec779b8eSAndroid Build Coastguard Worker {
3184*ec779b8eSAndroid Build Coastguard Worker bool previousTimestampValid = mPreviousTimestampValid;
3185*ec779b8eSAndroid Build Coastguard Worker // Set false here to cover all the error return cases.
3186*ec779b8eSAndroid Build Coastguard Worker mPreviousTimestampValid = false;
3187*ec779b8eSAndroid Build Coastguard Worker
3188*ec779b8eSAndroid Build Coastguard Worker switch (mState) {
3189*ec779b8eSAndroid Build Coastguard Worker case STATE_ACTIVE:
3190*ec779b8eSAndroid Build Coastguard Worker case STATE_PAUSED:
3191*ec779b8eSAndroid Build Coastguard Worker break; // handle below
3192*ec779b8eSAndroid Build Coastguard Worker case STATE_FLUSHED:
3193*ec779b8eSAndroid Build Coastguard Worker case STATE_STOPPED:
3194*ec779b8eSAndroid Build Coastguard Worker return WOULD_BLOCK;
3195*ec779b8eSAndroid Build Coastguard Worker case STATE_STOPPING:
3196*ec779b8eSAndroid Build Coastguard Worker case STATE_PAUSED_STOPPING:
3197*ec779b8eSAndroid Build Coastguard Worker if (!isOffloaded_l()) {
3198*ec779b8eSAndroid Build Coastguard Worker return INVALID_OPERATION;
3199*ec779b8eSAndroid Build Coastguard Worker }
3200*ec779b8eSAndroid Build Coastguard Worker break; // offloaded tracks handled below
3201*ec779b8eSAndroid Build Coastguard Worker default:
3202*ec779b8eSAndroid Build Coastguard Worker LOG_ALWAYS_FATAL("%s(%d): Invalid mState in getTimestamp(): %d",
3203*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId, mState);
3204*ec779b8eSAndroid Build Coastguard Worker break;
3205*ec779b8eSAndroid Build Coastguard Worker }
3206*ec779b8eSAndroid Build Coastguard Worker
3207*ec779b8eSAndroid Build Coastguard Worker if (mCblk->mFlags & CBLK_INVALID) {
3208*ec779b8eSAndroid Build Coastguard Worker const status_t status = restoreTrack_l("getTimestamp");
3209*ec779b8eSAndroid Build Coastguard Worker if (status != OK) {
3210*ec779b8eSAndroid Build Coastguard Worker // per getTimestamp() API doc in header, we return DEAD_OBJECT here,
3211*ec779b8eSAndroid Build Coastguard Worker // recommending that the track be recreated.
3212*ec779b8eSAndroid Build Coastguard Worker return DEAD_OBJECT;
3213*ec779b8eSAndroid Build Coastguard Worker }
3214*ec779b8eSAndroid Build Coastguard Worker }
3215*ec779b8eSAndroid Build Coastguard Worker
3216*ec779b8eSAndroid Build Coastguard Worker // The presented frame count must always lag behind the consumed frame count.
3217*ec779b8eSAndroid Build Coastguard Worker // To avoid a race, read the presented frames first. This ensures that presented <= consumed.
3218*ec779b8eSAndroid Build Coastguard Worker
3219*ec779b8eSAndroid Build Coastguard Worker status_t status;
3220*ec779b8eSAndroid Build Coastguard Worker if (isAfTrackOffloadedOrDirect_l()) {
3221*ec779b8eSAndroid Build Coastguard Worker // use Binder to get timestamp
3222*ec779b8eSAndroid Build Coastguard Worker media::AudioTimestampInternal ts;
3223*ec779b8eSAndroid Build Coastguard Worker mAudioTrack->getTimestamp(&ts, &status);
3224*ec779b8eSAndroid Build Coastguard Worker if (status == OK) {
3225*ec779b8eSAndroid Build Coastguard Worker auto legacyTs = aidl2legacy_AudioTimestampInternal_AudioTimestamp(ts);
3226*ec779b8eSAndroid Build Coastguard Worker if (!legacyTs.ok()) {
3227*ec779b8eSAndroid Build Coastguard Worker return logIfErrorAndReturnStatus(
3228*ec779b8eSAndroid Build Coastguard Worker BAD_VALUE, StringPrintf("%s: received invalid audio timestamp", __func__));
3229*ec779b8eSAndroid Build Coastguard Worker }
3230*ec779b8eSAndroid Build Coastguard Worker timestamp = legacyTs.value();
3231*ec779b8eSAndroid Build Coastguard Worker }
3232*ec779b8eSAndroid Build Coastguard Worker } else {
3233*ec779b8eSAndroid Build Coastguard Worker // read timestamp from shared memory
3234*ec779b8eSAndroid Build Coastguard Worker ExtendedTimestamp ets;
3235*ec779b8eSAndroid Build Coastguard Worker status = mProxy->getTimestamp(&ets);
3236*ec779b8eSAndroid Build Coastguard Worker if (status == OK) {
3237*ec779b8eSAndroid Build Coastguard Worker ExtendedTimestamp::Location location;
3238*ec779b8eSAndroid Build Coastguard Worker status = ets.getBestTimestamp(×tamp, &location);
3239*ec779b8eSAndroid Build Coastguard Worker
3240*ec779b8eSAndroid Build Coastguard Worker if (status == OK) {
3241*ec779b8eSAndroid Build Coastguard Worker updateLatency_l();
3242*ec779b8eSAndroid Build Coastguard Worker // It is possible that the best location has moved from the kernel to the server.
3243*ec779b8eSAndroid Build Coastguard Worker // In this case we adjust the position from the previous computed latency.
3244*ec779b8eSAndroid Build Coastguard Worker if (location == ExtendedTimestamp::LOCATION_SERVER) {
3245*ec779b8eSAndroid Build Coastguard Worker ALOGW_IF(mPreviousLocation == ExtendedTimestamp::LOCATION_KERNEL,
3246*ec779b8eSAndroid Build Coastguard Worker "%s(%d): location moved from kernel to server",
3247*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId);
3248*ec779b8eSAndroid Build Coastguard Worker // check that the last kernel OK time info exists and the positions
3249*ec779b8eSAndroid Build Coastguard Worker // are valid (if they predate the current track, the positions may
3250*ec779b8eSAndroid Build Coastguard Worker // be zero or negative).
3251*ec779b8eSAndroid Build Coastguard Worker const int64_t frames =
3252*ec779b8eSAndroid Build Coastguard Worker (ets.mTimeNs[ExtendedTimestamp::LOCATION_SERVER_LASTKERNELOK] < 0 ||
3253*ec779b8eSAndroid Build Coastguard Worker ets.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL_LASTKERNELOK] < 0 ||
3254*ec779b8eSAndroid Build Coastguard Worker ets.mPosition[ExtendedTimestamp::LOCATION_SERVER_LASTKERNELOK] <= 0 ||
3255*ec779b8eSAndroid Build Coastguard Worker ets.mPosition[ExtendedTimestamp::LOCATION_KERNEL_LASTKERNELOK] <= 0)
3256*ec779b8eSAndroid Build Coastguard Worker ?
3257*ec779b8eSAndroid Build Coastguard Worker int64_t((double)mAfLatency * mSampleRate * mPlaybackRate.mSpeed
3258*ec779b8eSAndroid Build Coastguard Worker / 1000)
3259*ec779b8eSAndroid Build Coastguard Worker :
3260*ec779b8eSAndroid Build Coastguard Worker (ets.mPosition[ExtendedTimestamp::LOCATION_SERVER_LASTKERNELOK]
3261*ec779b8eSAndroid Build Coastguard Worker - ets.mPosition[ExtendedTimestamp::LOCATION_KERNEL_LASTKERNELOK]);
3262*ec779b8eSAndroid Build Coastguard Worker ALOGV("%s(%d): frame adjustment:%lld timestamp:%s",
3263*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId, (long long)frames, ets.toString().c_str());
3264*ec779b8eSAndroid Build Coastguard Worker if (frames >= ets.mPosition[location]) {
3265*ec779b8eSAndroid Build Coastguard Worker timestamp.mPosition = 0;
3266*ec779b8eSAndroid Build Coastguard Worker } else {
3267*ec779b8eSAndroid Build Coastguard Worker timestamp.mPosition = (uint32_t)(ets.mPosition[location] - frames);
3268*ec779b8eSAndroid Build Coastguard Worker }
3269*ec779b8eSAndroid Build Coastguard Worker } else if (location == ExtendedTimestamp::LOCATION_KERNEL) {
3270*ec779b8eSAndroid Build Coastguard Worker ALOGV_IF(mPreviousLocation == ExtendedTimestamp::LOCATION_SERVER,
3271*ec779b8eSAndroid Build Coastguard Worker "%s(%d): location moved from server to kernel",
3272*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId);
3273*ec779b8eSAndroid Build Coastguard Worker
3274*ec779b8eSAndroid Build Coastguard Worker if (ets.mPosition[ExtendedTimestamp::LOCATION_SERVER] ==
3275*ec779b8eSAndroid Build Coastguard Worker ets.mPosition[ExtendedTimestamp::LOCATION_KERNEL]) {
3276*ec779b8eSAndroid Build Coastguard Worker // In Q, we don't return errors as an invalid time
3277*ec779b8eSAndroid Build Coastguard Worker // but instead we leave the last kernel good timestamp alone.
3278*ec779b8eSAndroid Build Coastguard Worker //
3279*ec779b8eSAndroid Build Coastguard Worker // If server is identical to kernel, the device data pipeline is idle.
3280*ec779b8eSAndroid Build Coastguard Worker // A better start time is now. The retrograde check ensures
3281*ec779b8eSAndroid Build Coastguard Worker // timestamp monotonicity.
3282*ec779b8eSAndroid Build Coastguard Worker const int64_t nowNs = systemTime();
3283*ec779b8eSAndroid Build Coastguard Worker if (!mTimestampStallReported) {
3284*ec779b8eSAndroid Build Coastguard Worker ALOGD("%s(%d): device stall time corrected using current time %lld",
3285*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId, (long long)nowNs);
3286*ec779b8eSAndroid Build Coastguard Worker mTimestampStallReported = true;
3287*ec779b8eSAndroid Build Coastguard Worker }
3288*ec779b8eSAndroid Build Coastguard Worker timestamp.mTime = convertNsToTimespec(nowNs);
3289*ec779b8eSAndroid Build Coastguard Worker } else {
3290*ec779b8eSAndroid Build Coastguard Worker mTimestampStallReported = false;
3291*ec779b8eSAndroid Build Coastguard Worker }
3292*ec779b8eSAndroid Build Coastguard Worker }
3293*ec779b8eSAndroid Build Coastguard Worker
3294*ec779b8eSAndroid Build Coastguard Worker // We update the timestamp time even when paused.
3295*ec779b8eSAndroid Build Coastguard Worker if (mState == STATE_PAUSED /* not needed: STATE_PAUSED_STOPPING */) {
3296*ec779b8eSAndroid Build Coastguard Worker const int64_t now = systemTime();
3297*ec779b8eSAndroid Build Coastguard Worker const int64_t at = audio_utils_ns_from_timespec(×tamp.mTime);
3298*ec779b8eSAndroid Build Coastguard Worker const int64_t lag =
3299*ec779b8eSAndroid Build Coastguard Worker (ets.mTimeNs[ExtendedTimestamp::LOCATION_SERVER_LASTKERNELOK] < 0 ||
3300*ec779b8eSAndroid Build Coastguard Worker ets.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL_LASTKERNELOK] < 0)
3301*ec779b8eSAndroid Build Coastguard Worker ? int64_t(mAfLatency * 1000000LL)
3302*ec779b8eSAndroid Build Coastguard Worker : (ets.mPosition[ExtendedTimestamp::LOCATION_SERVER_LASTKERNELOK]
3303*ec779b8eSAndroid Build Coastguard Worker - ets.mPosition[ExtendedTimestamp::LOCATION_KERNEL_LASTKERNELOK])
3304*ec779b8eSAndroid Build Coastguard Worker * NANOS_PER_SECOND / mSampleRate;
3305*ec779b8eSAndroid Build Coastguard Worker const int64_t limit = now - lag; // no earlier than this limit
3306*ec779b8eSAndroid Build Coastguard Worker if (at < limit) {
3307*ec779b8eSAndroid Build Coastguard Worker ALOGV("timestamp pause lag:%lld adjusting from %lld to %lld",
3308*ec779b8eSAndroid Build Coastguard Worker (long long)lag, (long long)at, (long long)limit);
3309*ec779b8eSAndroid Build Coastguard Worker timestamp.mTime = convertNsToTimespec(limit);
3310*ec779b8eSAndroid Build Coastguard Worker }
3311*ec779b8eSAndroid Build Coastguard Worker }
3312*ec779b8eSAndroid Build Coastguard Worker mPreviousLocation = location;
3313*ec779b8eSAndroid Build Coastguard Worker } else {
3314*ec779b8eSAndroid Build Coastguard Worker // right after AudioTrack is started, one may not find a timestamp
3315*ec779b8eSAndroid Build Coastguard Worker ALOGV("%s(%d): getBestTimestamp did not find timestamp", __func__, mPortId);
3316*ec779b8eSAndroid Build Coastguard Worker }
3317*ec779b8eSAndroid Build Coastguard Worker }
3318*ec779b8eSAndroid Build Coastguard Worker if (status == INVALID_OPERATION) {
3319*ec779b8eSAndroid Build Coastguard Worker // INVALID_OPERATION occurs when no timestamp has been issued by the server;
3320*ec779b8eSAndroid Build Coastguard Worker // other failures are signaled by a negative time.
3321*ec779b8eSAndroid Build Coastguard Worker // If we come out of FLUSHED or STOPPED where the position is known
3322*ec779b8eSAndroid Build Coastguard Worker // to be zero we convert this to WOULD_BLOCK (with the implicit meaning of
3323*ec779b8eSAndroid Build Coastguard Worker // "zero" for NuPlayer). We don't convert for track restoration as position
3324*ec779b8eSAndroid Build Coastguard Worker // does not reset.
3325*ec779b8eSAndroid Build Coastguard Worker ALOGV("%s(%d): timestamp server offset:%lld restore frames:%lld",
3326*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId,
3327*ec779b8eSAndroid Build Coastguard Worker (long long)mFramesWrittenServerOffset, (long long)mFramesWrittenAtRestore);
3328*ec779b8eSAndroid Build Coastguard Worker if (mFramesWrittenServerOffset != mFramesWrittenAtRestore) {
3329*ec779b8eSAndroid Build Coastguard Worker status = WOULD_BLOCK;
3330*ec779b8eSAndroid Build Coastguard Worker }
3331*ec779b8eSAndroid Build Coastguard Worker }
3332*ec779b8eSAndroid Build Coastguard Worker }
3333*ec779b8eSAndroid Build Coastguard Worker if (status != NO_ERROR) {
3334*ec779b8eSAndroid Build Coastguard Worker ALOGV_IF(status != WOULD_BLOCK, "%s(%d): getTimestamp error:%#x", __func__, mPortId, status);
3335*ec779b8eSAndroid Build Coastguard Worker return status;
3336*ec779b8eSAndroid Build Coastguard Worker }
3337*ec779b8eSAndroid Build Coastguard Worker if (isAfTrackOffloadedOrDirect_l()) {
3338*ec779b8eSAndroid Build Coastguard Worker if (isOffloaded_l() && (mState == STATE_PAUSED || mState == STATE_PAUSED_STOPPING)) {
3339*ec779b8eSAndroid Build Coastguard Worker // use cached paused position in case another offloaded track is running.
3340*ec779b8eSAndroid Build Coastguard Worker timestamp.mPosition = mPausedPosition;
3341*ec779b8eSAndroid Build Coastguard Worker clock_gettime(CLOCK_MONOTONIC, ×tamp.mTime);
3342*ec779b8eSAndroid Build Coastguard Worker // TODO: adjust for delay
3343*ec779b8eSAndroid Build Coastguard Worker return NO_ERROR;
3344*ec779b8eSAndroid Build Coastguard Worker }
3345*ec779b8eSAndroid Build Coastguard Worker
3346*ec779b8eSAndroid Build Coastguard Worker // Check whether a pending flush or stop has completed, as those commands may
3347*ec779b8eSAndroid Build Coastguard Worker // be asynchronous or return near finish or exhibit glitchy behavior.
3348*ec779b8eSAndroid Build Coastguard Worker //
3349*ec779b8eSAndroid Build Coastguard Worker // Originally this showed up as the first timestamp being a continuation of
3350*ec779b8eSAndroid Build Coastguard Worker // the previous song under gapless playback.
3351*ec779b8eSAndroid Build Coastguard Worker // However, we sometimes see zero timestamps, then a glitch of
3352*ec779b8eSAndroid Build Coastguard Worker // the previous song's position, and then correct timestamps afterwards.
3353*ec779b8eSAndroid Build Coastguard Worker if (mStartFromZeroUs != 0 && mSampleRate != 0) {
3354*ec779b8eSAndroid Build Coastguard Worker static const int kTimeJitterUs = 100000; // 100 ms
3355*ec779b8eSAndroid Build Coastguard Worker static const int k1SecUs = 1000000;
3356*ec779b8eSAndroid Build Coastguard Worker
3357*ec779b8eSAndroid Build Coastguard Worker const int64_t timeNow = getNowUs();
3358*ec779b8eSAndroid Build Coastguard Worker
3359*ec779b8eSAndroid Build Coastguard Worker if (timeNow < mStartFromZeroUs + k1SecUs) { // within first second of starting
3360*ec779b8eSAndroid Build Coastguard Worker const int64_t timestampTimeUs = convertTimespecToUs(timestamp.mTime);
3361*ec779b8eSAndroid Build Coastguard Worker if (timestampTimeUs < mStartFromZeroUs) {
3362*ec779b8eSAndroid Build Coastguard Worker return WOULD_BLOCK; // stale timestamp time, occurs before start.
3363*ec779b8eSAndroid Build Coastguard Worker }
3364*ec779b8eSAndroid Build Coastguard Worker const int64_t deltaTimeUs = timestampTimeUs - mStartFromZeroUs;
3365*ec779b8eSAndroid Build Coastguard Worker const int64_t deltaPositionByUs = (double)timestamp.mPosition * 1000000
3366*ec779b8eSAndroid Build Coastguard Worker / ((double)mSampleRate * mPlaybackRate.mSpeed);
3367*ec779b8eSAndroid Build Coastguard Worker
3368*ec779b8eSAndroid Build Coastguard Worker if (deltaPositionByUs > deltaTimeUs + kTimeJitterUs) {
3369*ec779b8eSAndroid Build Coastguard Worker // Verify that the counter can't count faster than the sample rate
3370*ec779b8eSAndroid Build Coastguard Worker // since the start time. If greater, then that means we may have failed
3371*ec779b8eSAndroid Build Coastguard Worker // to completely flush or stop the previous playing track.
3372*ec779b8eSAndroid Build Coastguard Worker ALOGW_IF(!mTimestampStartupGlitchReported,
3373*ec779b8eSAndroid Build Coastguard Worker "%s(%d): startup glitch detected"
3374*ec779b8eSAndroid Build Coastguard Worker " deltaTimeUs(%lld) deltaPositionUs(%lld) tsmPosition(%u)",
3375*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId,
3376*ec779b8eSAndroid Build Coastguard Worker (long long)deltaTimeUs, (long long)deltaPositionByUs,
3377*ec779b8eSAndroid Build Coastguard Worker timestamp.mPosition);
3378*ec779b8eSAndroid Build Coastguard Worker mTimestampStartupGlitchReported = true;
3379*ec779b8eSAndroid Build Coastguard Worker if (previousTimestampValid
3380*ec779b8eSAndroid Build Coastguard Worker && mPreviousTimestamp.mPosition == 0 /* should be true if valid */) {
3381*ec779b8eSAndroid Build Coastguard Worker timestamp = mPreviousTimestamp;
3382*ec779b8eSAndroid Build Coastguard Worker mPreviousTimestampValid = true;
3383*ec779b8eSAndroid Build Coastguard Worker return NO_ERROR;
3384*ec779b8eSAndroid Build Coastguard Worker }
3385*ec779b8eSAndroid Build Coastguard Worker return WOULD_BLOCK;
3386*ec779b8eSAndroid Build Coastguard Worker }
3387*ec779b8eSAndroid Build Coastguard Worker if (deltaPositionByUs != 0) {
3388*ec779b8eSAndroid Build Coastguard Worker mStartFromZeroUs = 0; // don't check again, we got valid nonzero position.
3389*ec779b8eSAndroid Build Coastguard Worker }
3390*ec779b8eSAndroid Build Coastguard Worker } else {
3391*ec779b8eSAndroid Build Coastguard Worker mStartFromZeroUs = 0; // don't check again, start time expired.
3392*ec779b8eSAndroid Build Coastguard Worker }
3393*ec779b8eSAndroid Build Coastguard Worker mTimestampStartupGlitchReported = false;
3394*ec779b8eSAndroid Build Coastguard Worker }
3395*ec779b8eSAndroid Build Coastguard Worker } else {
3396*ec779b8eSAndroid Build Coastguard Worker // Update the mapping between local consumed (mPosition) and server consumed (mServer)
3397*ec779b8eSAndroid Build Coastguard Worker (void) updateAndGetPosition_l();
3398*ec779b8eSAndroid Build Coastguard Worker // Server consumed (mServer) and presented both use the same server time base,
3399*ec779b8eSAndroid Build Coastguard Worker // and server consumed is always >= presented.
3400*ec779b8eSAndroid Build Coastguard Worker // The delta between these represents the number of frames in the buffer pipeline.
3401*ec779b8eSAndroid Build Coastguard Worker // If this delta between these is greater than the client position, it means that
3402*ec779b8eSAndroid Build Coastguard Worker // actually presented is still stuck at the starting line (figuratively speaking),
3403*ec779b8eSAndroid Build Coastguard Worker // waiting for the first frame to go by. So we can't report a valid timestamp yet.
3404*ec779b8eSAndroid Build Coastguard Worker // Note: We explicitly use non-Modulo comparison here - potential wrap issue when
3405*ec779b8eSAndroid Build Coastguard Worker // mPosition exceeds 32 bits.
3406*ec779b8eSAndroid Build Coastguard Worker // TODO Remove when timestamp is updated to contain pipeline status info.
3407*ec779b8eSAndroid Build Coastguard Worker const int32_t pipelineDepthInFrames = (mServer - timestamp.mPosition).signedValue();
3408*ec779b8eSAndroid Build Coastguard Worker if (pipelineDepthInFrames > 0 /* should be true, but we check anyways */
3409*ec779b8eSAndroid Build Coastguard Worker && (uint32_t)pipelineDepthInFrames > mPosition.value()) {
3410*ec779b8eSAndroid Build Coastguard Worker return INVALID_OPERATION;
3411*ec779b8eSAndroid Build Coastguard Worker }
3412*ec779b8eSAndroid Build Coastguard Worker // Convert timestamp position from server time base to client time base.
3413*ec779b8eSAndroid Build Coastguard Worker // TODO The following code should work OK now because timestamp.mPosition is 32-bit.
3414*ec779b8eSAndroid Build Coastguard Worker // But if we change it to 64-bit then this could fail.
3415*ec779b8eSAndroid Build Coastguard Worker // Use Modulo computation here.
3416*ec779b8eSAndroid Build Coastguard Worker timestamp.mPosition = (mPosition - mServer + timestamp.mPosition).value();
3417*ec779b8eSAndroid Build Coastguard Worker // Immediately after a call to getPosition_l(), mPosition and
3418*ec779b8eSAndroid Build Coastguard Worker // mServer both represent the same frame position. mPosition is
3419*ec779b8eSAndroid Build Coastguard Worker // in client's point of view, and mServer is in server's point of
3420*ec779b8eSAndroid Build Coastguard Worker // view. So the difference between them is the "fudge factor"
3421*ec779b8eSAndroid Build Coastguard Worker // between client and server views due to stop() and/or new
3422*ec779b8eSAndroid Build Coastguard Worker // IAudioTrack. And timestamp.mPosition is initially in server's
3423*ec779b8eSAndroid Build Coastguard Worker // point of view, so we need to apply the same fudge factor to it.
3424*ec779b8eSAndroid Build Coastguard Worker }
3425*ec779b8eSAndroid Build Coastguard Worker
3426*ec779b8eSAndroid Build Coastguard Worker // Prevent retrograde motion in timestamp.
3427*ec779b8eSAndroid Build Coastguard Worker // This is sometimes caused by erratic reports of the available space in the ALSA drivers.
3428*ec779b8eSAndroid Build Coastguard Worker if (status == NO_ERROR) {
3429*ec779b8eSAndroid Build Coastguard Worker // Fix stale time when checking timestamp right after start().
3430*ec779b8eSAndroid Build Coastguard Worker // The position is at the last reported location but the time can be stale
3431*ec779b8eSAndroid Build Coastguard Worker // due to pause or standby or cold start latency.
3432*ec779b8eSAndroid Build Coastguard Worker //
3433*ec779b8eSAndroid Build Coastguard Worker // We keep advancing the time (but not the position) to ensure that the
3434*ec779b8eSAndroid Build Coastguard Worker // stale value does not confuse the application.
3435*ec779b8eSAndroid Build Coastguard Worker //
3436*ec779b8eSAndroid Build Coastguard Worker // For offload compatibility, use a default lag value here.
3437*ec779b8eSAndroid Build Coastguard Worker // Any time discrepancy between this update and the pause timestamp is handled
3438*ec779b8eSAndroid Build Coastguard Worker // by the retrograde check afterwards.
3439*ec779b8eSAndroid Build Coastguard Worker int64_t currentTimeNanos = audio_utils_ns_from_timespec(×tamp.mTime);
3440*ec779b8eSAndroid Build Coastguard Worker const int64_t lagNs = int64_t(mAfLatency * 1000000LL);
3441*ec779b8eSAndroid Build Coastguard Worker const int64_t limitNs = mStartNs - lagNs;
3442*ec779b8eSAndroid Build Coastguard Worker if (currentTimeNanos < limitNs) {
3443*ec779b8eSAndroid Build Coastguard Worker if (!mTimestampStaleTimeReported) {
3444*ec779b8eSAndroid Build Coastguard Worker ALOGD("%s(%d): stale timestamp time corrected, "
3445*ec779b8eSAndroid Build Coastguard Worker "currentTimeNanos: %lld < limitNs: %lld < mStartNs: %lld",
3446*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId,
3447*ec779b8eSAndroid Build Coastguard Worker (long long)currentTimeNanos, (long long)limitNs, (long long)mStartNs);
3448*ec779b8eSAndroid Build Coastguard Worker mTimestampStaleTimeReported = true;
3449*ec779b8eSAndroid Build Coastguard Worker }
3450*ec779b8eSAndroid Build Coastguard Worker timestamp.mTime = convertNsToTimespec(limitNs);
3451*ec779b8eSAndroid Build Coastguard Worker currentTimeNanos = limitNs;
3452*ec779b8eSAndroid Build Coastguard Worker } else {
3453*ec779b8eSAndroid Build Coastguard Worker mTimestampStaleTimeReported = false;
3454*ec779b8eSAndroid Build Coastguard Worker }
3455*ec779b8eSAndroid Build Coastguard Worker
3456*ec779b8eSAndroid Build Coastguard Worker // previousTimestampValid is set to false when starting after a stop or flush.
3457*ec779b8eSAndroid Build Coastguard Worker if (previousTimestampValid) {
3458*ec779b8eSAndroid Build Coastguard Worker const int64_t previousTimeNanos =
3459*ec779b8eSAndroid Build Coastguard Worker audio_utils_ns_from_timespec(&mPreviousTimestamp.mTime);
3460*ec779b8eSAndroid Build Coastguard Worker
3461*ec779b8eSAndroid Build Coastguard Worker // retrograde check
3462*ec779b8eSAndroid Build Coastguard Worker if (currentTimeNanos < previousTimeNanos) {
3463*ec779b8eSAndroid Build Coastguard Worker if (!mTimestampRetrogradeTimeReported) {
3464*ec779b8eSAndroid Build Coastguard Worker ALOGW("%s(%d): retrograde timestamp time corrected, %lld < %lld",
3465*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId,
3466*ec779b8eSAndroid Build Coastguard Worker (long long)currentTimeNanos, (long long)previousTimeNanos);
3467*ec779b8eSAndroid Build Coastguard Worker mTimestampRetrogradeTimeReported = true;
3468*ec779b8eSAndroid Build Coastguard Worker }
3469*ec779b8eSAndroid Build Coastguard Worker timestamp.mTime = mPreviousTimestamp.mTime;
3470*ec779b8eSAndroid Build Coastguard Worker } else {
3471*ec779b8eSAndroid Build Coastguard Worker mTimestampRetrogradeTimeReported = false;
3472*ec779b8eSAndroid Build Coastguard Worker }
3473*ec779b8eSAndroid Build Coastguard Worker
3474*ec779b8eSAndroid Build Coastguard Worker // Looking at signed delta will work even when the timestamps
3475*ec779b8eSAndroid Build Coastguard Worker // are wrapping around.
3476*ec779b8eSAndroid Build Coastguard Worker int32_t deltaPosition = (Modulo<uint32_t>(timestamp.mPosition)
3477*ec779b8eSAndroid Build Coastguard Worker - mPreviousTimestamp.mPosition).signedValue();
3478*ec779b8eSAndroid Build Coastguard Worker if (deltaPosition < 0) {
3479*ec779b8eSAndroid Build Coastguard Worker // Only report once per position instead of spamming the log.
3480*ec779b8eSAndroid Build Coastguard Worker if (!mTimestampRetrogradePositionReported) {
3481*ec779b8eSAndroid Build Coastguard Worker ALOGW("%s(%d): retrograde timestamp position corrected, %d = %u - %u",
3482*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId,
3483*ec779b8eSAndroid Build Coastguard Worker deltaPosition,
3484*ec779b8eSAndroid Build Coastguard Worker timestamp.mPosition,
3485*ec779b8eSAndroid Build Coastguard Worker mPreviousTimestamp.mPosition);
3486*ec779b8eSAndroid Build Coastguard Worker mTimestampRetrogradePositionReported = true;
3487*ec779b8eSAndroid Build Coastguard Worker }
3488*ec779b8eSAndroid Build Coastguard Worker } else {
3489*ec779b8eSAndroid Build Coastguard Worker mTimestampRetrogradePositionReported = false;
3490*ec779b8eSAndroid Build Coastguard Worker }
3491*ec779b8eSAndroid Build Coastguard Worker if (deltaPosition < 0) {
3492*ec779b8eSAndroid Build Coastguard Worker timestamp.mPosition = mPreviousTimestamp.mPosition;
3493*ec779b8eSAndroid Build Coastguard Worker deltaPosition = 0;
3494*ec779b8eSAndroid Build Coastguard Worker }
3495*ec779b8eSAndroid Build Coastguard Worker #if 0
3496*ec779b8eSAndroid Build Coastguard Worker // Uncomment this to verify audio timestamp rate.
3497*ec779b8eSAndroid Build Coastguard Worker const int64_t deltaTime =
3498*ec779b8eSAndroid Build Coastguard Worker audio_utils_ns_from_timespec(×tamp.mTime) - previousTimeNanos;
3499*ec779b8eSAndroid Build Coastguard Worker if (deltaTime != 0) {
3500*ec779b8eSAndroid Build Coastguard Worker const int64_t computedSampleRate =
3501*ec779b8eSAndroid Build Coastguard Worker deltaPosition * (long long)NANOS_PER_SECOND / deltaTime;
3502*ec779b8eSAndroid Build Coastguard Worker ALOGD("%s(%d): computedSampleRate:%u sampleRate:%u",
3503*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId,
3504*ec779b8eSAndroid Build Coastguard Worker (unsigned)computedSampleRate, mSampleRate);
3505*ec779b8eSAndroid Build Coastguard Worker }
3506*ec779b8eSAndroid Build Coastguard Worker #endif
3507*ec779b8eSAndroid Build Coastguard Worker }
3508*ec779b8eSAndroid Build Coastguard Worker mPreviousTimestamp = timestamp;
3509*ec779b8eSAndroid Build Coastguard Worker mPreviousTimestampValid = true;
3510*ec779b8eSAndroid Build Coastguard Worker }
3511*ec779b8eSAndroid Build Coastguard Worker
3512*ec779b8eSAndroid Build Coastguard Worker return status;
3513*ec779b8eSAndroid Build Coastguard Worker }
3514*ec779b8eSAndroid Build Coastguard Worker
getParameters(const String8 & keys)3515*ec779b8eSAndroid Build Coastguard Worker String8 AudioTrack::getParameters(const String8& keys)
3516*ec779b8eSAndroid Build Coastguard Worker {
3517*ec779b8eSAndroid Build Coastguard Worker audio_io_handle_t output = getOutput();
3518*ec779b8eSAndroid Build Coastguard Worker if (output != AUDIO_IO_HANDLE_NONE) {
3519*ec779b8eSAndroid Build Coastguard Worker return AudioSystem::getParameters(output, keys);
3520*ec779b8eSAndroid Build Coastguard Worker } else {
3521*ec779b8eSAndroid Build Coastguard Worker return String8();
3522*ec779b8eSAndroid Build Coastguard Worker }
3523*ec779b8eSAndroid Build Coastguard Worker }
3524*ec779b8eSAndroid Build Coastguard Worker
isOffloaded() const3525*ec779b8eSAndroid Build Coastguard Worker bool AudioTrack::isOffloaded() const
3526*ec779b8eSAndroid Build Coastguard Worker {
3527*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
3528*ec779b8eSAndroid Build Coastguard Worker return isOffloaded_l();
3529*ec779b8eSAndroid Build Coastguard Worker }
3530*ec779b8eSAndroid Build Coastguard Worker
isDirect() const3531*ec779b8eSAndroid Build Coastguard Worker bool AudioTrack::isDirect() const
3532*ec779b8eSAndroid Build Coastguard Worker {
3533*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
3534*ec779b8eSAndroid Build Coastguard Worker return isDirect_l();
3535*ec779b8eSAndroid Build Coastguard Worker }
3536*ec779b8eSAndroid Build Coastguard Worker
isOffloadedOrDirect() const3537*ec779b8eSAndroid Build Coastguard Worker bool AudioTrack::isOffloadedOrDirect() const
3538*ec779b8eSAndroid Build Coastguard Worker {
3539*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
3540*ec779b8eSAndroid Build Coastguard Worker return isOffloadedOrDirect_l();
3541*ec779b8eSAndroid Build Coastguard Worker }
3542*ec779b8eSAndroid Build Coastguard Worker
3543*ec779b8eSAndroid Build Coastguard Worker
dump(int fd,const Vector<String16> & args __unused) const3544*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::dump(int fd, const Vector<String16>& args __unused) const
3545*ec779b8eSAndroid Build Coastguard Worker {
3546*ec779b8eSAndroid Build Coastguard Worker String8 result;
3547*ec779b8eSAndroid Build Coastguard Worker
3548*ec779b8eSAndroid Build Coastguard Worker result.append(" AudioTrack::dump\n");
3549*ec779b8eSAndroid Build Coastguard Worker result.appendFormat(" id(%d) status(%d), state(%d), session Id(%d), flags(%#x)\n",
3550*ec779b8eSAndroid Build Coastguard Worker mPortId, mStatus, mState, mSessionId, mFlags);
3551*ec779b8eSAndroid Build Coastguard Worker result.appendFormat(" stream type(%d), left - right volume(%f, %f)\n",
3552*ec779b8eSAndroid Build Coastguard Worker mStreamType,
3553*ec779b8eSAndroid Build Coastguard Worker mVolume[AUDIO_INTERLEAVE_LEFT], mVolume[AUDIO_INTERLEAVE_RIGHT]);
3554*ec779b8eSAndroid Build Coastguard Worker result.appendFormat(" format(%#x), channel mask(%#x), channel count(%u)\n",
3555*ec779b8eSAndroid Build Coastguard Worker mFormat, mChannelMask, mChannelCount);
3556*ec779b8eSAndroid Build Coastguard Worker result.appendFormat(" sample rate(%u), original sample rate(%u), speed(%f)\n",
3557*ec779b8eSAndroid Build Coastguard Worker mSampleRate, mOriginalSampleRate, mPlaybackRate.mSpeed);
3558*ec779b8eSAndroid Build Coastguard Worker result.appendFormat(" frame count(%zu), req. frame count(%zu)\n",
3559*ec779b8eSAndroid Build Coastguard Worker mFrameCount, mReqFrameCount);
3560*ec779b8eSAndroid Build Coastguard Worker result.appendFormat(" notif. frame count(%u), req. notif. frame count(%u),"
3561*ec779b8eSAndroid Build Coastguard Worker " req. notif. per buff(%u)\n",
3562*ec779b8eSAndroid Build Coastguard Worker mNotificationFramesAct, mNotificationFramesReq, mNotificationsPerBufferReq);
3563*ec779b8eSAndroid Build Coastguard Worker result.appendFormat(" latency (%d), selected device Id(%d), routed device Ids(%s)\n",
3564*ec779b8eSAndroid Build Coastguard Worker mLatency, mSelectedDeviceId, toString(mRoutedDeviceIds).c_str());
3565*ec779b8eSAndroid Build Coastguard Worker result.appendFormat(" output(%d) AF latency (%u) AF frame count(%zu) AF SampleRate(%u)\n",
3566*ec779b8eSAndroid Build Coastguard Worker mOutput, mAfLatency, mAfFrameCount, mAfSampleRate);
3567*ec779b8eSAndroid Build Coastguard Worker ::write(fd, result.c_str(), result.size());
3568*ec779b8eSAndroid Build Coastguard Worker return NO_ERROR;
3569*ec779b8eSAndroid Build Coastguard Worker }
3570*ec779b8eSAndroid Build Coastguard Worker
getUnderrunCount() const3571*ec779b8eSAndroid Build Coastguard Worker uint32_t AudioTrack::getUnderrunCount() const
3572*ec779b8eSAndroid Build Coastguard Worker {
3573*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
3574*ec779b8eSAndroid Build Coastguard Worker return getUnderrunCount_l();
3575*ec779b8eSAndroid Build Coastguard Worker }
3576*ec779b8eSAndroid Build Coastguard Worker
getUnderrunCount_l() const3577*ec779b8eSAndroid Build Coastguard Worker uint32_t AudioTrack::getUnderrunCount_l() const
3578*ec779b8eSAndroid Build Coastguard Worker {
3579*ec779b8eSAndroid Build Coastguard Worker return mProxy->getUnderrunCount() + mUnderrunCountOffset;
3580*ec779b8eSAndroid Build Coastguard Worker }
3581*ec779b8eSAndroid Build Coastguard Worker
getUnderrunFrames() const3582*ec779b8eSAndroid Build Coastguard Worker uint32_t AudioTrack::getUnderrunFrames() const
3583*ec779b8eSAndroid Build Coastguard Worker {
3584*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
3585*ec779b8eSAndroid Build Coastguard Worker return mProxy->getUnderrunFrames();
3586*ec779b8eSAndroid Build Coastguard Worker }
3587*ec779b8eSAndroid Build Coastguard Worker
setLogSessionId(const char * logSessionId)3588*ec779b8eSAndroid Build Coastguard Worker void AudioTrack::setLogSessionId(const char *logSessionId)
3589*ec779b8eSAndroid Build Coastguard Worker {
3590*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
3591*ec779b8eSAndroid Build Coastguard Worker if (logSessionId == nullptr) logSessionId = ""; // an empty string is an unset session id.
3592*ec779b8eSAndroid Build Coastguard Worker if (mLogSessionId == logSessionId) return;
3593*ec779b8eSAndroid Build Coastguard Worker
3594*ec779b8eSAndroid Build Coastguard Worker mLogSessionId = logSessionId;
3595*ec779b8eSAndroid Build Coastguard Worker mediametrics::LogItem(mMetricsId)
3596*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_SETLOGSESSIONID)
3597*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_LOGSESSIONID, logSessionId)
3598*ec779b8eSAndroid Build Coastguard Worker .record();
3599*ec779b8eSAndroid Build Coastguard Worker }
3600*ec779b8eSAndroid Build Coastguard Worker
setPlayerIId(int playerIId)3601*ec779b8eSAndroid Build Coastguard Worker void AudioTrack::setPlayerIId(int playerIId)
3602*ec779b8eSAndroid Build Coastguard Worker {
3603*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
3604*ec779b8eSAndroid Build Coastguard Worker if (mPlayerIId == playerIId) return;
3605*ec779b8eSAndroid Build Coastguard Worker
3606*ec779b8eSAndroid Build Coastguard Worker mPlayerIId = playerIId;
3607*ec779b8eSAndroid Build Coastguard Worker triggerPortIdUpdate_l();
3608*ec779b8eSAndroid Build Coastguard Worker mediametrics::LogItem(mMetricsId)
3609*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_SETPLAYERIID)
3610*ec779b8eSAndroid Build Coastguard Worker .set(AMEDIAMETRICS_PROP_PLAYERIID, playerIId)
3611*ec779b8eSAndroid Build Coastguard Worker .record();
3612*ec779b8eSAndroid Build Coastguard Worker }
3613*ec779b8eSAndroid Build Coastguard Worker
triggerPortIdUpdate_l()3614*ec779b8eSAndroid Build Coastguard Worker void AudioTrack::triggerPortIdUpdate_l() {
3615*ec779b8eSAndroid Build Coastguard Worker if (mAudioManager == nullptr) {
3616*ec779b8eSAndroid Build Coastguard Worker // use checkService() to avoid blocking if audio service is not up yet
3617*ec779b8eSAndroid Build Coastguard Worker sp<IBinder> binder =
3618*ec779b8eSAndroid Build Coastguard Worker defaultServiceManager()->checkService(String16(kAudioServiceName));
3619*ec779b8eSAndroid Build Coastguard Worker if (binder == nullptr) {
3620*ec779b8eSAndroid Build Coastguard Worker ALOGE("%s(%d): binding to audio service failed.",
3621*ec779b8eSAndroid Build Coastguard Worker __func__,
3622*ec779b8eSAndroid Build Coastguard Worker mPlayerIId);
3623*ec779b8eSAndroid Build Coastguard Worker return;
3624*ec779b8eSAndroid Build Coastguard Worker }
3625*ec779b8eSAndroid Build Coastguard Worker
3626*ec779b8eSAndroid Build Coastguard Worker mAudioManager = interface_cast<IAudioManager>(binder);
3627*ec779b8eSAndroid Build Coastguard Worker }
3628*ec779b8eSAndroid Build Coastguard Worker
3629*ec779b8eSAndroid Build Coastguard Worker // first time when the track is created we do not have a valid piid
3630*ec779b8eSAndroid Build Coastguard Worker if (mPlayerIId != PLAYER_PIID_INVALID) {
3631*ec779b8eSAndroid Build Coastguard Worker mAudioManager->playerEvent(mPlayerIId, PLAYER_UPDATE_PORT_ID, {mPortId});
3632*ec779b8eSAndroid Build Coastguard Worker }
3633*ec779b8eSAndroid Build Coastguard Worker }
3634*ec779b8eSAndroid Build Coastguard Worker
addAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback> & callback)3635*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::addAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& callback)
3636*ec779b8eSAndroid Build Coastguard Worker {
3637*ec779b8eSAndroid Build Coastguard Worker
3638*ec779b8eSAndroid Build Coastguard Worker if (callback == 0) {
3639*ec779b8eSAndroid Build Coastguard Worker ALOGW("%s(%d): adding NULL callback!", __func__, mPortId);
3640*ec779b8eSAndroid Build Coastguard Worker return BAD_VALUE;
3641*ec779b8eSAndroid Build Coastguard Worker }
3642*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
3643*ec779b8eSAndroid Build Coastguard Worker if (mDeviceCallback.unsafe_get() == callback.get()) {
3644*ec779b8eSAndroid Build Coastguard Worker ALOGW("%s(%d): adding same callback!", __func__, mPortId);
3645*ec779b8eSAndroid Build Coastguard Worker return INVALID_OPERATION;
3646*ec779b8eSAndroid Build Coastguard Worker }
3647*ec779b8eSAndroid Build Coastguard Worker status_t status = NO_ERROR;
3648*ec779b8eSAndroid Build Coastguard Worker if (mOutput != AUDIO_IO_HANDLE_NONE) {
3649*ec779b8eSAndroid Build Coastguard Worker if (mDeviceCallback != 0) {
3650*ec779b8eSAndroid Build Coastguard Worker ALOGW("%s(%d): callback already present!", __func__, mPortId);
3651*ec779b8eSAndroid Build Coastguard Worker AudioSystem::removeAudioDeviceCallback(this, mOutput, mPortId);
3652*ec779b8eSAndroid Build Coastguard Worker }
3653*ec779b8eSAndroid Build Coastguard Worker status = AudioSystem::addAudioDeviceCallback(this, mOutput, mPortId);
3654*ec779b8eSAndroid Build Coastguard Worker }
3655*ec779b8eSAndroid Build Coastguard Worker mDeviceCallback = callback;
3656*ec779b8eSAndroid Build Coastguard Worker return status;
3657*ec779b8eSAndroid Build Coastguard Worker }
3658*ec779b8eSAndroid Build Coastguard Worker
removeAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback> & callback)3659*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::removeAudioDeviceCallback(
3660*ec779b8eSAndroid Build Coastguard Worker const sp<AudioSystem::AudioDeviceCallback>& callback)
3661*ec779b8eSAndroid Build Coastguard Worker {
3662*ec779b8eSAndroid Build Coastguard Worker if (callback == 0) {
3663*ec779b8eSAndroid Build Coastguard Worker ALOGW("%s(%d): removing NULL callback!", __func__, mPortId);
3664*ec779b8eSAndroid Build Coastguard Worker return BAD_VALUE;
3665*ec779b8eSAndroid Build Coastguard Worker }
3666*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
3667*ec779b8eSAndroid Build Coastguard Worker if (mDeviceCallback.unsafe_get() != callback.get()) {
3668*ec779b8eSAndroid Build Coastguard Worker ALOGW("%s removing different callback!", __FUNCTION__);
3669*ec779b8eSAndroid Build Coastguard Worker return INVALID_OPERATION;
3670*ec779b8eSAndroid Build Coastguard Worker }
3671*ec779b8eSAndroid Build Coastguard Worker mDeviceCallback.clear();
3672*ec779b8eSAndroid Build Coastguard Worker if (mOutput != AUDIO_IO_HANDLE_NONE) {
3673*ec779b8eSAndroid Build Coastguard Worker AudioSystem::removeAudioDeviceCallback(this, mOutput, mPortId);
3674*ec779b8eSAndroid Build Coastguard Worker }
3675*ec779b8eSAndroid Build Coastguard Worker return NO_ERROR;
3676*ec779b8eSAndroid Build Coastguard Worker }
3677*ec779b8eSAndroid Build Coastguard Worker
3678*ec779b8eSAndroid Build Coastguard Worker
onAudioDeviceUpdate(audio_io_handle_t audioIo,const DeviceIdVector & deviceIds)3679*ec779b8eSAndroid Build Coastguard Worker void AudioTrack::onAudioDeviceUpdate(audio_io_handle_t audioIo,
3680*ec779b8eSAndroid Build Coastguard Worker const DeviceIdVector& deviceIds)
3681*ec779b8eSAndroid Build Coastguard Worker {
3682*ec779b8eSAndroid Build Coastguard Worker sp<AudioSystem::AudioDeviceCallback> callback;
3683*ec779b8eSAndroid Build Coastguard Worker {
3684*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
3685*ec779b8eSAndroid Build Coastguard Worker if (audioIo != mOutput) {
3686*ec779b8eSAndroid Build Coastguard Worker return;
3687*ec779b8eSAndroid Build Coastguard Worker }
3688*ec779b8eSAndroid Build Coastguard Worker callback = mDeviceCallback.promote();
3689*ec779b8eSAndroid Build Coastguard Worker // only update device if the track is active as route changes due to other use cases are
3690*ec779b8eSAndroid Build Coastguard Worker // irrelevant for this client
3691*ec779b8eSAndroid Build Coastguard Worker if (mState == STATE_ACTIVE) {
3692*ec779b8eSAndroid Build Coastguard Worker mRoutedDeviceIds = deviceIds;
3693*ec779b8eSAndroid Build Coastguard Worker }
3694*ec779b8eSAndroid Build Coastguard Worker }
3695*ec779b8eSAndroid Build Coastguard Worker
3696*ec779b8eSAndroid Build Coastguard Worker if (callback.get() != nullptr) {
3697*ec779b8eSAndroid Build Coastguard Worker callback->onAudioDeviceUpdate(mOutput, mRoutedDeviceIds);
3698*ec779b8eSAndroid Build Coastguard Worker }
3699*ec779b8eSAndroid Build Coastguard Worker }
3700*ec779b8eSAndroid Build Coastguard Worker
pendingDuration(int32_t * msec,ExtendedTimestamp::Location location)3701*ec779b8eSAndroid Build Coastguard Worker status_t AudioTrack::pendingDuration(int32_t *msec, ExtendedTimestamp::Location location)
3702*ec779b8eSAndroid Build Coastguard Worker {
3703*ec779b8eSAndroid Build Coastguard Worker if (msec == nullptr ||
3704*ec779b8eSAndroid Build Coastguard Worker (location != ExtendedTimestamp::LOCATION_SERVER
3705*ec779b8eSAndroid Build Coastguard Worker && location != ExtendedTimestamp::LOCATION_KERNEL)) {
3706*ec779b8eSAndroid Build Coastguard Worker return BAD_VALUE;
3707*ec779b8eSAndroid Build Coastguard Worker }
3708*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
3709*ec779b8eSAndroid Build Coastguard Worker // inclusive of offloaded and direct tracks.
3710*ec779b8eSAndroid Build Coastguard Worker //
3711*ec779b8eSAndroid Build Coastguard Worker // It is possible, but not enabled, to allow duration computation for non-pcm
3712*ec779b8eSAndroid Build Coastguard Worker // audio_has_proportional_frames() formats because currently they have
3713*ec779b8eSAndroid Build Coastguard Worker // the drain rate equivalent to the pcm sample rate * framesize.
3714*ec779b8eSAndroid Build Coastguard Worker if (!isPurePcmData_l()) {
3715*ec779b8eSAndroid Build Coastguard Worker return INVALID_OPERATION;
3716*ec779b8eSAndroid Build Coastguard Worker }
3717*ec779b8eSAndroid Build Coastguard Worker ExtendedTimestamp ets;
3718*ec779b8eSAndroid Build Coastguard Worker if (getTimestamp_l(&ets) == OK
3719*ec779b8eSAndroid Build Coastguard Worker && ets.mTimeNs[location] > 0) {
3720*ec779b8eSAndroid Build Coastguard Worker int64_t diff = ets.mPosition[ExtendedTimestamp::LOCATION_CLIENT]
3721*ec779b8eSAndroid Build Coastguard Worker - ets.mPosition[location];
3722*ec779b8eSAndroid Build Coastguard Worker if (diff < 0) {
3723*ec779b8eSAndroid Build Coastguard Worker *msec = 0;
3724*ec779b8eSAndroid Build Coastguard Worker } else {
3725*ec779b8eSAndroid Build Coastguard Worker // ms is the playback time by frames
3726*ec779b8eSAndroid Build Coastguard Worker int64_t ms = (int64_t)((double)diff * 1000 /
3727*ec779b8eSAndroid Build Coastguard Worker ((double)mSampleRate * mPlaybackRate.mSpeed));
3728*ec779b8eSAndroid Build Coastguard Worker // clockdiff is the timestamp age (negative)
3729*ec779b8eSAndroid Build Coastguard Worker int64_t clockdiff = (mState != STATE_ACTIVE) ? 0 :
3730*ec779b8eSAndroid Build Coastguard Worker ets.mTimeNs[location]
3731*ec779b8eSAndroid Build Coastguard Worker + ets.mTimebaseOffset[ExtendedTimestamp::TIMEBASE_MONOTONIC]
3732*ec779b8eSAndroid Build Coastguard Worker - systemTime(SYSTEM_TIME_MONOTONIC);
3733*ec779b8eSAndroid Build Coastguard Worker
3734*ec779b8eSAndroid Build Coastguard Worker //ALOGV("ms: %lld clockdiff: %lld", (long long)ms, (long long)clockdiff);
3735*ec779b8eSAndroid Build Coastguard Worker static const int NANOS_PER_MILLIS = 1000000;
3736*ec779b8eSAndroid Build Coastguard Worker *msec = (int32_t)(ms + clockdiff / NANOS_PER_MILLIS);
3737*ec779b8eSAndroid Build Coastguard Worker }
3738*ec779b8eSAndroid Build Coastguard Worker return NO_ERROR;
3739*ec779b8eSAndroid Build Coastguard Worker }
3740*ec779b8eSAndroid Build Coastguard Worker if (location != ExtendedTimestamp::LOCATION_SERVER) {
3741*ec779b8eSAndroid Build Coastguard Worker return INVALID_OPERATION; // LOCATION_KERNEL is not available
3742*ec779b8eSAndroid Build Coastguard Worker }
3743*ec779b8eSAndroid Build Coastguard Worker // use server position directly (offloaded and direct arrive here)
3744*ec779b8eSAndroid Build Coastguard Worker updateAndGetPosition_l();
3745*ec779b8eSAndroid Build Coastguard Worker int32_t diff = (Modulo<uint32_t>(mFramesWritten) - mPosition).signedValue();
3746*ec779b8eSAndroid Build Coastguard Worker *msec = (diff <= 0) ? 0
3747*ec779b8eSAndroid Build Coastguard Worker : (int32_t)((double)diff * 1000 / ((double)mSampleRate * mPlaybackRate.mSpeed));
3748*ec779b8eSAndroid Build Coastguard Worker return NO_ERROR;
3749*ec779b8eSAndroid Build Coastguard Worker }
3750*ec779b8eSAndroid Build Coastguard Worker
hasStarted()3751*ec779b8eSAndroid Build Coastguard Worker bool AudioTrack::hasStarted()
3752*ec779b8eSAndroid Build Coastguard Worker {
3753*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mLock);
3754*ec779b8eSAndroid Build Coastguard Worker switch (mState) {
3755*ec779b8eSAndroid Build Coastguard Worker case STATE_STOPPED:
3756*ec779b8eSAndroid Build Coastguard Worker if (isOffloadedOrDirect_l()) {
3757*ec779b8eSAndroid Build Coastguard Worker // check if we have started in the past to return true.
3758*ec779b8eSAndroid Build Coastguard Worker return mStartFromZeroUs > 0;
3759*ec779b8eSAndroid Build Coastguard Worker }
3760*ec779b8eSAndroid Build Coastguard Worker // A normal audio track may still be draining, so
3761*ec779b8eSAndroid Build Coastguard Worker // check if stream has ended. This covers fasttrack position
3762*ec779b8eSAndroid Build Coastguard Worker // instability and start/stop without any data written.
3763*ec779b8eSAndroid Build Coastguard Worker if (mProxy->getStreamEndDone()) {
3764*ec779b8eSAndroid Build Coastguard Worker return true;
3765*ec779b8eSAndroid Build Coastguard Worker }
3766*ec779b8eSAndroid Build Coastguard Worker FALLTHROUGH_INTENDED;
3767*ec779b8eSAndroid Build Coastguard Worker case STATE_ACTIVE:
3768*ec779b8eSAndroid Build Coastguard Worker case STATE_STOPPING:
3769*ec779b8eSAndroid Build Coastguard Worker break;
3770*ec779b8eSAndroid Build Coastguard Worker case STATE_PAUSED:
3771*ec779b8eSAndroid Build Coastguard Worker case STATE_PAUSED_STOPPING:
3772*ec779b8eSAndroid Build Coastguard Worker case STATE_FLUSHED:
3773*ec779b8eSAndroid Build Coastguard Worker return false; // we're not active
3774*ec779b8eSAndroid Build Coastguard Worker default:
3775*ec779b8eSAndroid Build Coastguard Worker LOG_ALWAYS_FATAL("%s(%d): Invalid mState in hasStarted(): %d", __func__, mPortId, mState);
3776*ec779b8eSAndroid Build Coastguard Worker break;
3777*ec779b8eSAndroid Build Coastguard Worker }
3778*ec779b8eSAndroid Build Coastguard Worker
3779*ec779b8eSAndroid Build Coastguard Worker // wait indicates whether we need to wait for a timestamp.
3780*ec779b8eSAndroid Build Coastguard Worker // This is conservatively figured - if we encounter an unexpected error
3781*ec779b8eSAndroid Build Coastguard Worker // then we will not wait.
3782*ec779b8eSAndroid Build Coastguard Worker bool wait = false;
3783*ec779b8eSAndroid Build Coastguard Worker if (isAfTrackOffloadedOrDirect_l()) {
3784*ec779b8eSAndroid Build Coastguard Worker AudioTimestamp ts;
3785*ec779b8eSAndroid Build Coastguard Worker status_t status = getTimestamp_l(ts);
3786*ec779b8eSAndroid Build Coastguard Worker if (status == WOULD_BLOCK) {
3787*ec779b8eSAndroid Build Coastguard Worker wait = true;
3788*ec779b8eSAndroid Build Coastguard Worker } else if (status == OK) {
3789*ec779b8eSAndroid Build Coastguard Worker wait = (ts.mPosition == 0 || ts.mPosition == mStartTs.mPosition);
3790*ec779b8eSAndroid Build Coastguard Worker }
3791*ec779b8eSAndroid Build Coastguard Worker ALOGV("%s(%d): hasStarted wait:%d ts:%u start position:%lld",
3792*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId,
3793*ec779b8eSAndroid Build Coastguard Worker (int)wait,
3794*ec779b8eSAndroid Build Coastguard Worker ts.mPosition,
3795*ec779b8eSAndroid Build Coastguard Worker (long long)mStartTs.mPosition);
3796*ec779b8eSAndroid Build Coastguard Worker } else {
3797*ec779b8eSAndroid Build Coastguard Worker int location = ExtendedTimestamp::LOCATION_SERVER; // for ALOG
3798*ec779b8eSAndroid Build Coastguard Worker ExtendedTimestamp ets;
3799*ec779b8eSAndroid Build Coastguard Worker status_t status = getTimestamp_l(&ets);
3800*ec779b8eSAndroid Build Coastguard Worker if (status == WOULD_BLOCK) { // no SERVER or KERNEL frame info in ets
3801*ec779b8eSAndroid Build Coastguard Worker wait = true;
3802*ec779b8eSAndroid Build Coastguard Worker } else if (status == OK) {
3803*ec779b8eSAndroid Build Coastguard Worker for (location = ExtendedTimestamp::LOCATION_KERNEL;
3804*ec779b8eSAndroid Build Coastguard Worker location >= ExtendedTimestamp::LOCATION_SERVER; --location) {
3805*ec779b8eSAndroid Build Coastguard Worker if (ets.mTimeNs[location] < 0 || mStartEts.mTimeNs[location] < 0) {
3806*ec779b8eSAndroid Build Coastguard Worker continue;
3807*ec779b8eSAndroid Build Coastguard Worker }
3808*ec779b8eSAndroid Build Coastguard Worker wait = ets.mPosition[location] == 0
3809*ec779b8eSAndroid Build Coastguard Worker || ets.mPosition[location] == mStartEts.mPosition[location];
3810*ec779b8eSAndroid Build Coastguard Worker break;
3811*ec779b8eSAndroid Build Coastguard Worker }
3812*ec779b8eSAndroid Build Coastguard Worker }
3813*ec779b8eSAndroid Build Coastguard Worker ALOGV("%s(%d): hasStarted wait:%d ets:%lld start position:%lld",
3814*ec779b8eSAndroid Build Coastguard Worker __func__, mPortId,
3815*ec779b8eSAndroid Build Coastguard Worker (int)wait,
3816*ec779b8eSAndroid Build Coastguard Worker (long long)ets.mPosition[location],
3817*ec779b8eSAndroid Build Coastguard Worker (long long)mStartEts.mPosition[location]);
3818*ec779b8eSAndroid Build Coastguard Worker }
3819*ec779b8eSAndroid Build Coastguard Worker return !wait;
3820*ec779b8eSAndroid Build Coastguard Worker }
3821*ec779b8eSAndroid Build Coastguard Worker
3822*ec779b8eSAndroid Build Coastguard Worker // =========================================================================
3823*ec779b8eSAndroid Build Coastguard Worker
binderDied(const wp<IBinder> & who __unused)3824*ec779b8eSAndroid Build Coastguard Worker void AudioTrack::DeathNotifier::binderDied(const wp<IBinder>& who __unused)
3825*ec779b8eSAndroid Build Coastguard Worker {
3826*ec779b8eSAndroid Build Coastguard Worker sp<AudioTrack> audioTrack = mAudioTrack.promote();
3827*ec779b8eSAndroid Build Coastguard Worker if (audioTrack != 0) {
3828*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(audioTrack->mLock);
3829*ec779b8eSAndroid Build Coastguard Worker audioTrack->mProxy->binderDied();
3830*ec779b8eSAndroid Build Coastguard Worker }
3831*ec779b8eSAndroid Build Coastguard Worker }
3832*ec779b8eSAndroid Build Coastguard Worker
3833*ec779b8eSAndroid Build Coastguard Worker // =========================================================================
3834*ec779b8eSAndroid Build Coastguard Worker
AudioTrackThread(AudioTrack & receiver)3835*ec779b8eSAndroid Build Coastguard Worker AudioTrack::AudioTrackThread::AudioTrackThread(AudioTrack& receiver)
3836*ec779b8eSAndroid Build Coastguard Worker : Thread(true /* bCanCallJava */) // binder recursion on restoreTrack_l() may call Java.
3837*ec779b8eSAndroid Build Coastguard Worker , mReceiver(receiver), mPaused(true), mPausedInt(false), mPausedNs(0LL),
3838*ec779b8eSAndroid Build Coastguard Worker mIgnoreNextPausedInt(false)
3839*ec779b8eSAndroid Build Coastguard Worker {
3840*ec779b8eSAndroid Build Coastguard Worker }
3841*ec779b8eSAndroid Build Coastguard Worker
~AudioTrackThread()3842*ec779b8eSAndroid Build Coastguard Worker AudioTrack::AudioTrackThread::~AudioTrackThread()
3843*ec779b8eSAndroid Build Coastguard Worker {
3844*ec779b8eSAndroid Build Coastguard Worker }
3845*ec779b8eSAndroid Build Coastguard Worker
threadLoop()3846*ec779b8eSAndroid Build Coastguard Worker bool AudioTrack::AudioTrackThread::threadLoop()
3847*ec779b8eSAndroid Build Coastguard Worker {
3848*ec779b8eSAndroid Build Coastguard Worker {
3849*ec779b8eSAndroid Build Coastguard Worker AutoMutex _l(mMyLock);
3850*ec779b8eSAndroid Build Coastguard Worker if (mPaused) {
3851*ec779b8eSAndroid Build Coastguard Worker // TODO check return value and handle or log
3852*ec779b8eSAndroid Build Coastguard Worker mMyCond.wait(mMyLock);
3853*ec779b8eSAndroid Build Coastguard Worker // caller will check for exitPending()
3854*ec779b8eSAndroid Build Coastguard Worker return true;
3855*ec779b8eSAndroid Build Coastguard Worker }
3856*ec779b8eSAndroid Build Coastguard Worker if (mIgnoreNextPausedInt) {
3857*ec779b8eSAndroid Build Coastguard Worker mIgnoreNextPausedInt = false;
3858*ec779b8eSAndroid Build Coastguard Worker mPausedInt = false;
3859*ec779b8eSAndroid Build Coastguard Worker }
3860*ec779b8eSAndroid Build Coastguard Worker if (mPausedInt) {
3861*ec779b8eSAndroid Build Coastguard Worker // TODO use futex instead of condition, for event flag "or"
3862*ec779b8eSAndroid Build Coastguard Worker if (mPausedNs > 0) {
3863*ec779b8eSAndroid Build Coastguard Worker // TODO check return value and handle or log
3864*ec779b8eSAndroid Build Coastguard Worker (void) mMyCond.waitRelative(mMyLock, mPausedNs);
3865*ec779b8eSAndroid Build Coastguard Worker } else {
3866*ec779b8eSAndroid Build Coastguard Worker // TODO check return value and handle or log
3867*ec779b8eSAndroid Build Coastguard Worker mMyCond.wait(mMyLock);
3868*ec779b8eSAndroid Build Coastguard Worker }
3869*ec779b8eSAndroid Build Coastguard Worker mPausedInt = false;
3870*ec779b8eSAndroid Build Coastguard Worker return true;
3871*ec779b8eSAndroid Build Coastguard Worker }
3872*ec779b8eSAndroid Build Coastguard Worker }
3873*ec779b8eSAndroid Build Coastguard Worker if (exitPending()) {
3874*ec779b8eSAndroid Build Coastguard Worker return false;
3875*ec779b8eSAndroid Build Coastguard Worker }
3876*ec779b8eSAndroid Build Coastguard Worker nsecs_t ns = mReceiver.processAudioBuffer();
3877*ec779b8eSAndroid Build Coastguard Worker switch (ns) {
3878*ec779b8eSAndroid Build Coastguard Worker case 0:
3879*ec779b8eSAndroid Build Coastguard Worker return true;
3880*ec779b8eSAndroid Build Coastguard Worker case NS_INACTIVE:
3881*ec779b8eSAndroid Build Coastguard Worker pauseInternal();
3882*ec779b8eSAndroid Build Coastguard Worker return true;
3883*ec779b8eSAndroid Build Coastguard Worker case NS_NEVER:
3884*ec779b8eSAndroid Build Coastguard Worker return false;
3885*ec779b8eSAndroid Build Coastguard Worker case NS_WHENEVER:
3886*ec779b8eSAndroid Build Coastguard Worker // Event driven: call wake() when callback notifications conditions change.
3887*ec779b8eSAndroid Build Coastguard Worker ns = INT64_MAX;
3888*ec779b8eSAndroid Build Coastguard Worker FALLTHROUGH_INTENDED;
3889*ec779b8eSAndroid Build Coastguard Worker default:
3890*ec779b8eSAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(ns < 0, "%s(%d): processAudioBuffer() returned %lld",
3891*ec779b8eSAndroid Build Coastguard Worker __func__, mReceiver.mPortId, (long long)ns);
3892*ec779b8eSAndroid Build Coastguard Worker pauseInternal(ns);
3893*ec779b8eSAndroid Build Coastguard Worker return true;
3894*ec779b8eSAndroid Build Coastguard Worker }
3895*ec779b8eSAndroid Build Coastguard Worker }
3896*ec779b8eSAndroid Build Coastguard Worker
requestExit()3897*ec779b8eSAndroid Build Coastguard Worker void AudioTrack::AudioTrackThread::requestExit()
3898*ec779b8eSAndroid Build Coastguard Worker {
3899*ec779b8eSAndroid Build Coastguard Worker // must be in this order to avoid a race condition
3900*ec779b8eSAndroid Build Coastguard Worker Thread::requestExit();
3901*ec779b8eSAndroid Build Coastguard Worker resume();
3902*ec779b8eSAndroid Build Coastguard Worker }
3903*ec779b8eSAndroid Build Coastguard Worker
pause()3904*ec779b8eSAndroid Build Coastguard Worker void AudioTrack::AudioTrackThread::pause()
3905*ec779b8eSAndroid Build Coastguard Worker {
3906*ec779b8eSAndroid Build Coastguard Worker AutoMutex _l(mMyLock);
3907*ec779b8eSAndroid Build Coastguard Worker mPaused = true;
3908*ec779b8eSAndroid Build Coastguard Worker }
3909*ec779b8eSAndroid Build Coastguard Worker
resume()3910*ec779b8eSAndroid Build Coastguard Worker void AudioTrack::AudioTrackThread::resume()
3911*ec779b8eSAndroid Build Coastguard Worker {
3912*ec779b8eSAndroid Build Coastguard Worker AutoMutex _l(mMyLock);
3913*ec779b8eSAndroid Build Coastguard Worker mIgnoreNextPausedInt = true;
3914*ec779b8eSAndroid Build Coastguard Worker if (mPaused || mPausedInt) {
3915*ec779b8eSAndroid Build Coastguard Worker mPaused = false;
3916*ec779b8eSAndroid Build Coastguard Worker mPausedInt = false;
3917*ec779b8eSAndroid Build Coastguard Worker mMyCond.signal();
3918*ec779b8eSAndroid Build Coastguard Worker }
3919*ec779b8eSAndroid Build Coastguard Worker }
3920*ec779b8eSAndroid Build Coastguard Worker
wake()3921*ec779b8eSAndroid Build Coastguard Worker void AudioTrack::AudioTrackThread::wake()
3922*ec779b8eSAndroid Build Coastguard Worker {
3923*ec779b8eSAndroid Build Coastguard Worker AutoMutex _l(mMyLock);
3924*ec779b8eSAndroid Build Coastguard Worker if (!mPaused) {
3925*ec779b8eSAndroid Build Coastguard Worker // wake() might be called while servicing a callback - ignore the next
3926*ec779b8eSAndroid Build Coastguard Worker // pause time and call processAudioBuffer.
3927*ec779b8eSAndroid Build Coastguard Worker mIgnoreNextPausedInt = true;
3928*ec779b8eSAndroid Build Coastguard Worker if (mPausedInt && mPausedNs > 0) {
3929*ec779b8eSAndroid Build Coastguard Worker // audio track is active and internally paused with timeout.
3930*ec779b8eSAndroid Build Coastguard Worker mPausedInt = false;
3931*ec779b8eSAndroid Build Coastguard Worker mMyCond.signal();
3932*ec779b8eSAndroid Build Coastguard Worker }
3933*ec779b8eSAndroid Build Coastguard Worker }
3934*ec779b8eSAndroid Build Coastguard Worker }
3935*ec779b8eSAndroid Build Coastguard Worker
pauseInternal(nsecs_t ns)3936*ec779b8eSAndroid Build Coastguard Worker void AudioTrack::AudioTrackThread::pauseInternal(nsecs_t ns)
3937*ec779b8eSAndroid Build Coastguard Worker {
3938*ec779b8eSAndroid Build Coastguard Worker AutoMutex _l(mMyLock);
3939*ec779b8eSAndroid Build Coastguard Worker mPausedInt = true;
3940*ec779b8eSAndroid Build Coastguard Worker mPausedNs = ns;
3941*ec779b8eSAndroid Build Coastguard Worker }
3942*ec779b8eSAndroid Build Coastguard Worker
onCodecFormatChanged(const std::vector<uint8_t> & audioMetadata)3943*ec779b8eSAndroid Build Coastguard Worker binder::Status AudioTrack::AudioTrackCallback::onCodecFormatChanged(
3944*ec779b8eSAndroid Build Coastguard Worker const std::vector<uint8_t>& audioMetadata)
3945*ec779b8eSAndroid Build Coastguard Worker {
3946*ec779b8eSAndroid Build Coastguard Worker AutoMutex _l(mAudioTrackCbLock);
3947*ec779b8eSAndroid Build Coastguard Worker sp<media::IAudioTrackCallback> callback = mCallback.promote();
3948*ec779b8eSAndroid Build Coastguard Worker if (callback.get() != nullptr) {
3949*ec779b8eSAndroid Build Coastguard Worker callback->onCodecFormatChanged(audioMetadata);
3950*ec779b8eSAndroid Build Coastguard Worker } else {
3951*ec779b8eSAndroid Build Coastguard Worker mCallback.clear();
3952*ec779b8eSAndroid Build Coastguard Worker }
3953*ec779b8eSAndroid Build Coastguard Worker return binder::Status::ok();
3954*ec779b8eSAndroid Build Coastguard Worker }
3955*ec779b8eSAndroid Build Coastguard Worker
setAudioTrackCallback(const sp<media::IAudioTrackCallback> & callback)3956*ec779b8eSAndroid Build Coastguard Worker void AudioTrack::AudioTrackCallback::setAudioTrackCallback(
3957*ec779b8eSAndroid Build Coastguard Worker const sp<media::IAudioTrackCallback> &callback) {
3958*ec779b8eSAndroid Build Coastguard Worker AutoMutex lock(mAudioTrackCbLock);
3959*ec779b8eSAndroid Build Coastguard Worker mCallback = callback;
3960*ec779b8eSAndroid Build Coastguard Worker }
3961*ec779b8eSAndroid Build Coastguard Worker
3962*ec779b8eSAndroid Build Coastguard Worker } // namespace android
3963