1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 //#define LOG_NDEBUG 0
18 #include <utility>
19 #define LOG_TAG "SoundPool::Stream"
20 #include <utils/Log.h>
21 #include <android/content/AttributionSourceState.h>
22
23 #include "Stream.h"
24
25 #include "StreamManager.h"
26
27 namespace android::soundpool {
28
~Stream()29 Stream::~Stream()
30 {
31 ALOGV("%s(%p)", __func__, this);
32 }
33
autoPause()34 void Stream::autoPause()
35 {
36 std::lock_guard lock(mLock);
37 if (mState == PLAYING) {
38 ALOGV("%s: track streamID: %d", __func__, (int)mStreamID);
39 mState = PAUSED;
40 mAutoPaused = true;
41 if (mAudioTrack != nullptr) {
42 mAudioTrack->pause();
43 }
44 }
45 }
46
autoResume()47 void Stream::autoResume()
48 {
49 std::lock_guard lock(mLock);
50 if (mAutoPaused) {
51 if (mState == PAUSED) {
52 ALOGV("%s: track streamID: %d", __func__, (int)mStreamID);
53 mState = PLAYING;
54 if (mAudioTrack != nullptr) {
55 mAudioTrack->start();
56 }
57 }
58 mAutoPaused = false; // New for R: always reset autopause (consistent with API spec).
59 }
60 }
61
mute(bool muting)62 void Stream::mute(bool muting)
63 {
64 std::lock_guard lock(mLock);
65 mMuted = muting;
66 if (mAudioTrack != nullptr) {
67 if (mMuted) {
68 mAudioTrack->setVolume(0.0f, 0.0f);
69 } else {
70 mAudioTrack->setVolume(mLeftVolume, mRightVolume);
71 }
72 }
73 }
74
pause(int32_t streamID)75 void Stream::pause(int32_t streamID)
76 {
77 std::lock_guard lock(mLock);
78 if (streamID == mStreamID) {
79 if (mState == PLAYING) {
80 ALOGV("%s: track streamID: %d", __func__, streamID);
81 mState = PAUSED;
82 if (mAudioTrack != nullptr) {
83 mAudioTrack->pause();
84 }
85 }
86 }
87 }
88
resume(int32_t streamID)89 void Stream::resume(int32_t streamID)
90 {
91 std::lock_guard lock(mLock);
92 if (streamID == mStreamID) {
93 if (mState == PAUSED) {
94 ALOGV("%s: track streamID: %d", __func__, streamID);
95 mState = PLAYING;
96 if (mAudioTrack != nullptr) {
97 mAudioTrack->start();
98 }
99 mAutoPaused = false; // TODO: is this right? (ambiguous per spec), move outside?
100 }
101 }
102 }
103
setRate(int32_t streamID,float rate)104 void Stream::setRate(int32_t streamID, float rate)
105 {
106 std::lock_guard lock(mLock);
107 if (streamID == mStreamID) {
108 mRate = rate;
109 if (mAudioTrack != nullptr && mSound != nullptr) {
110 const auto sampleRate = (uint32_t)lround(double(mSound->getSampleRate()) * rate);
111 mAudioTrack->setSampleRate(sampleRate);
112 }
113 }
114 }
115
setVolume_l(float leftVolume,float rightVolume)116 void Stream::setVolume_l(float leftVolume, float rightVolume)
117 {
118 mLeftVolume = leftVolume;
119 mRightVolume = rightVolume;
120 if (mAudioTrack != nullptr && !mMuted) {
121 mAudioTrack->setVolume(leftVolume, rightVolume);
122 }
123 }
124
setVolume(int32_t streamID,float leftVolume,float rightVolume)125 void Stream::setVolume(int32_t streamID, float leftVolume, float rightVolume)
126 {
127 std::lock_guard lock(mLock);
128 if (streamID == mStreamID) {
129 setVolume_l(leftVolume, rightVolume);
130 }
131 }
132
setPriority(int32_t streamID,int32_t priority)133 void Stream::setPriority(int32_t streamID, int32_t priority)
134 {
135 std::lock_guard lock(mLock);
136 if (streamID == mStreamID) {
137 mPriority = priority;
138 }
139 }
140
setLoop(int32_t streamID,int32_t loop)141 void Stream::setLoop(int32_t streamID, int32_t loop)
142 {
143 std::lock_guard lock(mLock);
144 if (streamID == mStreamID) {
145 if (mAudioTrack != nullptr && mSound != nullptr) {
146 const uint32_t loopEnd = mSound->getSizeInBytes() / mSound->getChannelCount() /
147 (mSound->getFormat() == AUDIO_FORMAT_PCM_16_BIT
148 ? sizeof(int16_t) : sizeof(uint8_t));
149 mAudioTrack->setLoop(0, loopEnd, loop);
150 }
151 mLoop = loop;
152 }
153 }
154
setPlay(int32_t streamID,const std::shared_ptr<Sound> & sound,int32_t soundID,float leftVolume,float rightVolume,int32_t priority,int32_t loop,float rate)155 void Stream::setPlay(
156 int32_t streamID, const std::shared_ptr<Sound> &sound, int32_t soundID,
157 float leftVolume, float rightVolume, int32_t priority, int32_t loop, float rate)
158 {
159 std::lock_guard lock(mLock);
160 // We must be idle, or we must be repurposing a pending Stream.
161 LOG_ALWAYS_FATAL_IF(mState != IDLE && mAudioTrack != nullptr, "State %d must be IDLE", mState);
162 mSound = sound;
163 mSoundID = soundID;
164 mLeftVolume = leftVolume;
165 mRightVolume = rightVolume;
166 mPriority = priority;
167 mLoop = loop;
168 mRate = rate;
169 mState = PLAYING;
170 mAutoPaused = false; // New for R (consistent with Java API spec).
171 mStreamID = streamID; // prefer this to be the last, as it is an atomic sync point
172 }
173
setStopTimeNs(int64_t stopTimeNs)174 void Stream::setStopTimeNs(int64_t stopTimeNs)
175 {
176 std::lock_guard lock(mLock);
177 mStopTimeNs = stopTimeNs;
178 }
179
requestStop(int32_t streamID)180 bool Stream::requestStop(int32_t streamID)
181 {
182 std::lock_guard lock(mLock);
183 if (streamID == mStreamID) {
184 ALOGV("%s: track streamID: %d", __func__, streamID);
185 if (mAudioTrack != nullptr) {
186 if (mState == PLAYING && !mMuted && (mLeftVolume != 0.f || mRightVolume != 0.f)) {
187 setVolume_l(0.f, 0.f);
188 mStopTimeNs = systemTime() + kStopWaitTimeNs;
189 } else {
190 mStopTimeNs = systemTime();
191 }
192 return true; // must be queued on the restart list.
193 }
194 stop_l();
195 }
196 return false;
197 }
198
stop()199 void Stream::stop()
200 {
201 std::lock_guard lock(mLock);
202 stop_l();
203 }
204
stop_l()205 void Stream::stop_l()
206 {
207 if (mState != IDLE) {
208 ALOGV("%s: track(%p) streamID: %d", __func__, mAudioTrack.get(), (int)mStreamID);
209 if (mAudioTrack != nullptr) {
210 mAudioTrack->stop();
211 }
212 mSound.reset();
213 mState = IDLE;
214 }
215 }
216
clearAudioTrack()217 void Stream::clearAudioTrack()
218 {
219 sp<AudioTrack> release; // release outside of lock.
220 std::lock_guard lock(mLock);
221 // This will invoke the destructor which waits for the AudioTrack thread to join,
222 // and is currently the only safe way to ensure there are no callbacks afterwards.
223 release = mAudioTrack; // or std::swap if we had move semantics.
224 mAudioTrack.clear();
225 }
226
getPairStream() const227 Stream* Stream::getPairStream() const
228 {
229 return mStreamManager->getPairStream(this);
230 }
231
playPairStream(std::vector<std::any> & garbage,int32_t playerIId)232 Stream* Stream::playPairStream(std::vector<std::any>& garbage, int32_t playerIId) {
233 Stream* pairStream = getPairStream();
234 LOG_ALWAYS_FATAL_IF(pairStream == nullptr, "No pair stream!");
235 {
236 ALOGV("%s: track streamID: %d", __func__, (int)getStreamID());
237 // TODO: Do we really want to force a simultaneous synchronization between
238 // the stream and its pair?
239
240 // note locking order - the paired stream is obtained before the queued stream.
241 // we can invert the locking order, but it is slightly more optimal to do it this way.
242 std::lock_guard lockp(pairStream->mLock);
243 if (pairStream->mSound == nullptr) {
244 return nullptr; // no pair sound
245 }
246 {
247 std::lock_guard lock(mLock);
248 LOG_ALWAYS_FATAL_IF(mState != IDLE, "State: %d must be IDLE", mState);
249 // TODO: do we want a specific set() here?
250 pairStream->mAudioTrack = mAudioTrack;
251 pairStream->mSoundID = mSoundID; // optimization to reuse AudioTrack.
252 pairStream->mToggle = mToggle;
253 pairStream->mAutoPaused = mAutoPaused; // save autopause state
254 pairStream->mMuted = mMuted;
255 mAudioTrack.clear(); // the pair owns the audiotrack.
256 mSound.reset();
257 mSoundID = 0;
258 }
259 // TODO: do we need a specific play_l() anymore?
260 const int pairState = pairStream->mState;
261 pairStream->play_l(pairStream->mSound, pairStream->mStreamID,
262 pairStream->mLeftVolume, pairStream->mRightVolume, pairStream->mPriority,
263 pairStream->mLoop, pairStream->mRate, garbage, playerIId);
264 if (pairStream->mState == IDLE) {
265 return nullptr; // AudioTrack error
266 }
267 if (pairState == PAUSED) { // reestablish pause
268 pairStream->mState = PAUSED;
269 pairStream->mAudioTrack->pause();
270 }
271 }
272 return pairStream;
273 }
274
play_l(const std::shared_ptr<Sound> & sound,int32_t nextStreamID,float leftVolume,float rightVolume,int32_t priority,int32_t loop,float rate,std::vector<std::any> & garbage,int32_t playerIId)275 void Stream::play_l(const std::shared_ptr<Sound>& sound, int32_t nextStreamID,
276 float leftVolume, float rightVolume, int32_t priority, int32_t loop, float rate,
277 std::vector<std::any>& garbage, int32_t playerIId)
278 {
279 ALOGV("%s(%p)(soundID=%d, streamID=%d, leftVolume=%f, rightVolume=%f,"
280 " priority=%d, loop=%d, rate=%f, playerIId=%d)",
281 __func__, this, sound->getSoundID(), nextStreamID, leftVolume, rightVolume,
282 priority, loop, rate, playerIId);
283
284 // initialize track
285 const int32_t channelCount = sound->getChannelCount();
286 const auto sampleRate = (uint32_t)lround(double(sound->getSampleRate()) * rate);
287 size_t frameCount = 0;
288
289 if (loop) {
290 const audio_format_t format = sound->getFormat();
291 const size_t frameSize = audio_is_linear_pcm(format)
292 ? channelCount * audio_bytes_per_sample(format) : 1;
293 frameCount = sound->getSizeInBytes() / frameSize;
294 }
295
296 if (mAudioTrack != nullptr) {
297 if (mSoundID == sound->getSoundID()
298 && mAudioTrack->setSampleRate(sampleRate) == NO_ERROR) {
299 // Reuse the old track if the soundID matches.
300 // the sample rate may fail to change if the audio track is a fast track.
301 ALOGV("%s: reusing track %p for sound %d",
302 __func__, mAudioTrack.get(), sound->getSoundID());
303 } else {
304 // If reuse not possible, move mAudioTrack to garbage, set to nullptr.
305 garbage.emplace_back(std::move(mAudioTrack));
306 mAudioTrack.clear(); // move should have cleared the sp<>, but we clear just in case.
307 }
308 }
309 if (mAudioTrack == nullptr) {
310 // mToggle toggles each time a track is started on a given stream.
311 // This enables the detection of callbacks received from the old
312 // audio track while the new one is being started and avoids processing them with
313 // wrong audio audio buffer size (mAudioBufferSize)
314 auto toggle = mToggle ^ 1;
315 // NOLINTNEXTLINE(performance-no-int-to-ptr)
316 audio_channel_mask_t soundChannelMask = sound->getChannelMask();
317 // When sound contains a valid channel mask, use it as is.
318 // Otherwise, use stream count to calculate channel mask.
319 audio_channel_mask_t channelMask = soundChannelMask != AUDIO_CHANNEL_NONE
320 ? soundChannelMask : audio_channel_out_mask_from_count(channelCount);
321
322 // do not create a new audio track if current track is compatible with sound parameters
323
324 android::content::AttributionSourceState attributionSource;
325 attributionSource.packageName = mStreamManager->getOpPackageName();
326 attributionSource.token = sp<BBinder>::make();
327 mCallback = sp<StreamCallback>::make(this, toggle),
328 // TODO b/182469354 make consistent with AudioRecord, add util for native source
329 mAudioTrack = new AudioTrack(AUDIO_STREAM_DEFAULT, sampleRate, sound->getFormat(),
330 channelMask, sound->getIMemory(), AUDIO_OUTPUT_FLAG_NONE,
331 mCallback,
332 0 /*default notification frames*/, AUDIO_SESSION_ALLOCATE,
333 AudioTrack::TRANSFER_DEFAULT,
334 nullptr /*offloadInfo*/, attributionSource,
335 mStreamManager->getAttributes(),
336 false /*doNotReconnect*/, 1.0f /*maxRequiredSpeed*/);
337 // Set caller name so it can be logged in destructor.
338 // MediaMetricsConstants.h: AMEDIAMETRICS_PROP_CALLERNAME_VALUE_SOUNDPOOL
339 mAudioTrack->setCallerName("soundpool");
340
341 if (playerIId != PLAYER_PIID_INVALID) {
342 mAudioTrack->setPlayerIId(playerIId);
343 }
344
345 if (status_t status = mAudioTrack->initCheck();
346 status != NO_ERROR) {
347 ALOGE("%s: error %d creating AudioTrack", __func__, status);
348 // TODO: should we consider keeping the soundID and reusing the old track?
349 mState = IDLE;
350 mSoundID = 0;
351 mSound.reset();
352 garbage.emplace_back(std::move(mAudioTrack)); // remove mAudioTrack.
353 mAudioTrack.clear(); // move should have cleared the sp<>, but we clear just in case.
354 return;
355 }
356 // From now on, AudioTrack callbacks received with previous toggle value will be ignored.
357 mToggle = toggle;
358 ALOGV("%s: using new track %p for sound %d",
359 __func__, mAudioTrack.get(), sound->getSoundID());
360 }
361 if (mMuted) {
362 mAudioTrack->setVolume(0.f, 0.f);
363 } else {
364 mAudioTrack->setVolume(leftVolume, rightVolume);
365 }
366 mAudioTrack->setLoop(0, frameCount, loop);
367 mAudioTrack->start();
368 mSound = sound;
369 mSoundID = sound->getSoundID();
370 mPriority = priority;
371 mLoop = loop;
372 mLeftVolume = leftVolume;
373 mRightVolume = rightVolume;
374 mRate = rate;
375 mState = PLAYING;
376 mStopTimeNs = 0;
377 mStreamID = nextStreamID; // prefer this to be the last, as it is an atomic sync point
378 }
379
getCorrespondingStreamID()380 int Stream::getCorrespondingStreamID() {
381 std::lock_guard lock(mLock);
382 return static_cast<int>(mAudioTrack ? mStreamID : getPairStream()->mStreamID);
383 }
384
onMoreData(const AudioTrack::Buffer &)385 size_t Stream::StreamCallback::onMoreData(const AudioTrack::Buffer&) {
386 ALOGW("%s streamID %d Unexpected EVENT_MORE_DATA for static track",
387 __func__, mStream->getCorrespondingStreamID());
388 return 0;
389 }
390
onUnderrun()391 void Stream::StreamCallback::onUnderrun() {
392 ALOGW("%s streamID %d Unexpected EVENT_UNDERRUN for static track",
393 __func__, mStream->getCorrespondingStreamID());
394 }
395
onLoopEnd(int32_t)396 void Stream::StreamCallback::onLoopEnd(int32_t) {
397 ALOGV("%s streamID %d EVENT_LOOP_END", __func__, mStream->getCorrespondingStreamID());
398 }
399
onMarker(uint32_t)400 void Stream::StreamCallback::onMarker(uint32_t) {
401 ALOGW("%s streamID %d Unexpected EVENT_MARKER for static track",
402 __func__, mStream->getCorrespondingStreamID());
403 }
404
onNewPos(uint32_t)405 void Stream::StreamCallback::onNewPos(uint32_t) {
406 ALOGW("%s streamID %d Unexpected EVENT_NEW_POS for static track",
407 __func__, mStream->getCorrespondingStreamID());
408 }
409
onBufferEnd()410 void Stream::StreamCallback::onBufferEnd() {
411 mStream->onBufferEnd(mToggle, 0);
412 }
413
onNewIAudioTrack()414 void Stream::StreamCallback::onNewIAudioTrack() {
415 ALOGV("%s streamID %d NEW_IAUDIOTRACK", __func__, mStream->getCorrespondingStreamID());
416 }
417
onStreamEnd()418 void Stream::StreamCallback::onStreamEnd() {
419 ALOGW("%s streamID %d Unexpected EVENT_STREAM_END for static track",
420 __func__, mStream->getCorrespondingStreamID());
421 }
422
onCanWriteMoreData(const AudioTrack::Buffer &)423 size_t Stream::StreamCallback::onCanWriteMoreData(const AudioTrack::Buffer&) {
424 ALOGW("%s streamID %d Unexpected EVENT_CAN_WRITE_MORE_DATA for static track",
425 __func__, mStream->getCorrespondingStreamID());
426 return 0;
427 }
428
onBufferEnd(int toggle,int tries)429 void Stream::onBufferEnd(int toggle, int tries)
430 {
431 int32_t activeStreamIDToRestart = 0;
432 {
433 std::unique_lock lock(mLock);
434 ALOGV("%s track(%p) streamID %d", __func__, mAudioTrack.get(), (int)mStreamID);
435
436 if (mAudioTrack == nullptr) {
437 // The AudioTrack is either with this stream or its pair.
438 // if this swaps a few times, the toggle is bound to be wrong, so we fail then.
439 //
440 // TODO: Modify AudioTrack callbacks to avoid the hacky toggle and retry
441 // logic here.
442 if (tries < 3) {
443 lock.unlock();
444 ALOGV("%s streamID %d going to pair stream", __func__, (int)mStreamID);
445 getPairStream()->onBufferEnd(toggle, tries + 1);
446 } else {
447 ALOGW("%s streamID %d cannot find track", __func__, (int)mStreamID);
448 }
449 return;
450 }
451 if (mToggle != toggle) {
452 ALOGD("%s streamID %d wrong toggle", __func__, (int)mStreamID);
453 return;
454 }
455 ALOGV("%s streamID %d EVENT_BUFFER_END", __func__, (int)mStreamID);
456 if (mState != IDLE) {
457 activeStreamIDToRestart = mStreamID;
458 mStopTimeNs = systemTime();
459 }
460 } // lock ends here. This is on the callback thread, no need to be precise.
461 if (activeStreamIDToRestart > 0) {
462 // Restart only if a particular streamID is still current and active.
463 ALOGV("%s: moveToRestartQueue %d", __func__, activeStreamIDToRestart);
464 mStreamManager->moveToRestartQueue(this, activeStreamIDToRestart);
465 }
466 }
467
dump() const468 void Stream::dump() const
469 {
470 // TODO: consider std::try_lock() - ok for now for ALOGV.
471 ALOGV("mPairStream=%p, mState=%d, mStreamID=%d, mSoundID=%d, mPriority=%d, mLoop=%d",
472 getPairStream(), mState, (int)getStreamID(), getSoundID(), mPriority, mLoop);
473 }
474
475 } // namespace android::soundpool
476