1 /*
2  * Copyright 2016 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_TAG "AudioStreamTrack"
18 //#define LOG_NDEBUG 0
19 #include <utils/Log.h>
20 
21 #include <stdint.h>
22 #include <media/AudioTrack.h>
23 
24 #include <aaudio/AAudio.h>
25 #include <system/audio.h>
26 #include "utility/AudioClock.h"
27 #include "legacy/AudioStreamLegacy.h"
28 #include "legacy/AudioStreamTrack.h"
29 #include "utility/FixedBlockReader.h"
30 
31 using namespace android;
32 using namespace aaudio;
33 
34 // Arbitrary and somewhat generous number of bursts.
35 #define DEFAULT_BURSTS_PER_BUFFER_CAPACITY     8
36 
37 /*
38  * Create a stream that uses the AudioTrack.
39  */
AudioStreamTrack()40 AudioStreamTrack::AudioStreamTrack()
41     : AudioStreamLegacy()
42     , mFixedBlockReader(*this)
43 {
44 }
45 
~AudioStreamTrack()46 AudioStreamTrack::~AudioStreamTrack()
47 {
48     const aaudio_stream_state_t state = getState();
49     bool bad = !(state == AAUDIO_STREAM_STATE_UNINITIALIZED || state == AAUDIO_STREAM_STATE_CLOSED);
50     ALOGE_IF(bad, "stream not closed, in state %d", state);
51 }
52 
open(const AudioStreamBuilder & builder)53 aaudio_result_t AudioStreamTrack::open(const AudioStreamBuilder& builder)
54 {
55     aaudio_result_t result = AAUDIO_OK;
56 
57     result = AudioStream::open(builder);
58     if (result != OK) {
59         return result;
60     }
61 
62     // Try to create an AudioTrack
63     // Use stereo if unspecified.
64     int32_t samplesPerFrame = (getSamplesPerFrame() == AAUDIO_UNSPECIFIED)
65                               ? 2 : getSamplesPerFrame();
66     audio_channel_mask_t channelMask = audio_channel_out_mask_from_count(samplesPerFrame);
67 
68     audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE;
69     aaudio_performance_mode_t perfMode = getPerformanceMode();
70     switch(perfMode) {
71         case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY:
72             // Bypass the normal mixer and go straight to the FAST mixer.
73             flags = (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_RAW);
74             break;
75 
76         case AAUDIO_PERFORMANCE_MODE_POWER_SAVING:
77             // This uses a mixer that wakes up less often than the FAST mixer.
78             flags = AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
79             break;
80 
81         case AAUDIO_PERFORMANCE_MODE_NONE:
82         default:
83             // No flags. Use a normal mixer in front of the FAST mixer.
84             break;
85     }
86 
87     size_t frameCount = (size_t)builder.getBufferCapacity();
88 
89     int32_t notificationFrames = 0;
90 
91     audio_format_t format = (getFormat() == AAUDIO_FORMAT_UNSPECIFIED)
92             ? AUDIO_FORMAT_PCM_FLOAT
93             : AAudioConvert_aaudioToAndroidDataFormat(getFormat());
94 
95     // Setup the callback if there is one.
96     AudioTrack::callback_t callback = nullptr;
97     void *callbackData = nullptr;
98     // Note that TRANSFER_SYNC does not allow FAST track
99     AudioTrack::transfer_type streamTransferType = AudioTrack::transfer_type::TRANSFER_SYNC;
100     if (builder.getDataCallbackProc() != nullptr) {
101         streamTransferType = AudioTrack::transfer_type::TRANSFER_CALLBACK;
102         callback = getLegacyCallback();
103         callbackData = this;
104 
105         // If the total buffer size is unspecified then base the size on the burst size.
106         if (frameCount == 0
107                 && ((flags & AUDIO_OUTPUT_FLAG_FAST) != 0)) {
108             // Take advantage of a special trick that allows us to create a buffer
109             // that is some multiple of the burst size.
110             notificationFrames = 0 - DEFAULT_BURSTS_PER_BUFFER_CAPACITY;
111         } else {
112             notificationFrames = builder.getFramesPerDataCallback();
113         }
114     }
115     mCallbackBufferSize = builder.getFramesPerDataCallback();
116 
117     ALOGD("open(), request notificationFrames = %d, frameCount = %u",
118           notificationFrames, (uint)frameCount);
119 
120     // Don't call mAudioTrack->setDeviceId() because it will be overwritten by set()!
121     audio_port_handle_t selectedDeviceId = (getDeviceId() == AAUDIO_UNSPECIFIED)
122                                            ? AUDIO_PORT_HANDLE_NONE
123                                            : getDeviceId();
124 
125     const audio_content_type_t contentType =
126             AAudioConvert_contentTypeToInternal(builder.getContentType());
127     const audio_usage_t usage =
128             AAudioConvert_usageToInternal(builder.getUsage());
129 
130     const audio_attributes_t attributes = {
131             .content_type = contentType,
132             .usage = usage,
133             .source = AUDIO_SOURCE_DEFAULT, // only used for recording
134             .flags = AUDIO_FLAG_NONE, // Different than the AUDIO_OUTPUT_FLAGS
135             .tags = ""
136     };
137 
138     static_assert(AAUDIO_UNSPECIFIED == AUDIO_SESSION_ALLOCATE, "Session IDs should match");
139 
140     aaudio_session_id_t requestedSessionId = builder.getSessionId();
141     audio_session_t sessionId = AAudioConvert_aaudioToAndroidSessionId(requestedSessionId);
142 
143     mAudioTrack = new AudioTrack();
144     mAudioTrack->set(
145             AUDIO_STREAM_DEFAULT,  // ignored because we pass attributes below
146             getSampleRate(),
147             format,
148             channelMask,
149             frameCount,
150             flags,
151             callback,
152             callbackData,
153             notificationFrames,
154             0,       // DEFAULT sharedBuffer*/,
155             false,   // DEFAULT threadCanCallJava
156             sessionId,
157             streamTransferType,
158             NULL,    // DEFAULT audio_offload_info_t
159             AUDIO_UID_INVALID, // DEFAULT uid
160             -1,      // DEFAULT pid
161             &attributes,
162             // WARNING - If doNotReconnect set true then audio stops after plugging and unplugging
163             // headphones a few times.
164             false,   // DEFAULT doNotReconnect,
165             1.0f,    // DEFAULT maxRequiredSpeed
166             selectedDeviceId
167     );
168 
169     // Did we get a valid track?
170     status_t status = mAudioTrack->initCheck();
171     if (status != NO_ERROR) {
172         close();
173         ALOGE("open(), initCheck() returned %d", status);
174         return AAudioConvert_androidToAAudioResult(status);
175     }
176 
177     doSetVolume();
178 
179     // Get the actual values from the AudioTrack.
180     setSamplesPerFrame(mAudioTrack->channelCount());
181     aaudio_format_t aaudioFormat =
182             AAudioConvert_androidToAAudioDataFormat(mAudioTrack->format());
183     setFormat(aaudioFormat);
184     setDeviceFormat(aaudioFormat);
185 
186     int32_t actualSampleRate = mAudioTrack->getSampleRate();
187     ALOGW_IF(actualSampleRate != getSampleRate(),
188              "open() sampleRate changed from %d to %d",
189              getSampleRate(), actualSampleRate);
190     setSampleRate(actualSampleRate);
191 
192     // We may need to pass the data through a block size adapter to guarantee constant size.
193     if (mCallbackBufferSize != AAUDIO_UNSPECIFIED) {
194         int callbackSizeBytes = getBytesPerFrame() * mCallbackBufferSize;
195         mFixedBlockReader.open(callbackSizeBytes);
196         mBlockAdapter = &mFixedBlockReader;
197     } else {
198         mBlockAdapter = nullptr;
199     }
200 
201     setState(AAUDIO_STREAM_STATE_OPEN);
202     setDeviceId(mAudioTrack->getRoutedDeviceId());
203 
204     aaudio_session_id_t actualSessionId =
205             (requestedSessionId == AAUDIO_SESSION_ID_NONE)
206             ? AAUDIO_SESSION_ID_NONE
207             : (aaudio_session_id_t) mAudioTrack->getSessionId();
208     setSessionId(actualSessionId);
209 
210     mAudioTrack->addAudioDeviceCallback(mDeviceCallback);
211 
212     // Update performance mode based on the actual stream flags.
213     // For example, if the sample rate is not allowed then you won't get a FAST track.
214     audio_output_flags_t actualFlags = mAudioTrack->getFlags();
215     aaudio_performance_mode_t actualPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE;
216     // We may not get the RAW flag. But as long as we get the FAST flag we can call it LOW_LATENCY.
217     if ((actualFlags & AUDIO_OUTPUT_FLAG_FAST) != 0) {
218         actualPerformanceMode = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
219     } else if ((actualFlags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) != 0) {
220         actualPerformanceMode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING;
221     }
222     setPerformanceMode(actualPerformanceMode);
223 
224     setSharingMode(AAUDIO_SHARING_MODE_SHARED); // EXCLUSIVE mode not supported in legacy
225 
226     // Log warning if we did not get what we asked for.
227     ALOGW_IF(actualFlags != flags,
228              "open() flags changed from 0x%08X to 0x%08X",
229              flags, actualFlags);
230     ALOGW_IF(actualPerformanceMode != perfMode,
231              "open() perfMode changed from %d to %d",
232              perfMode, actualPerformanceMode);
233 
234     return AAUDIO_OK;
235 }
236 
close()237 aaudio_result_t AudioStreamTrack::close()
238 {
239     if (getState() != AAUDIO_STREAM_STATE_CLOSED) {
240         mAudioTrack->removeAudioDeviceCallback(mDeviceCallback);
241         setState(AAUDIO_STREAM_STATE_CLOSED);
242     }
243     mFixedBlockReader.close();
244     return AAUDIO_OK;
245 }
246 
processCallback(int event,void * info)247 void AudioStreamTrack::processCallback(int event, void *info) {
248 
249     switch (event) {
250         case AudioTrack::EVENT_MORE_DATA:
251             processCallbackCommon(AAUDIO_CALLBACK_OPERATION_PROCESS_DATA, info);
252             break;
253 
254             // Stream got rerouted so we disconnect.
255         case AudioTrack::EVENT_NEW_IAUDIOTRACK:
256             processCallbackCommon(AAUDIO_CALLBACK_OPERATION_DISCONNECTED, info);
257             break;
258 
259         default:
260             break;
261     }
262     return;
263 }
264 
requestStart()265 aaudio_result_t AudioStreamTrack::requestStart() {
266     if (mAudioTrack.get() == nullptr) {
267         ALOGE("requestStart() no AudioTrack");
268         return AAUDIO_ERROR_INVALID_STATE;
269     }
270     // Get current position so we can detect when the track is playing.
271     status_t err = mAudioTrack->getPosition(&mPositionWhenStarting);
272     if (err != OK) {
273         return AAudioConvert_androidToAAudioResult(err);
274     }
275 
276     // Enable callback before starting AudioTrack to avoid shutting
277     // down because of a race condition.
278     mCallbackEnabled.store(true);
279     err = mAudioTrack->start();
280     if (err != OK) {
281         return AAudioConvert_androidToAAudioResult(err);
282     } else {
283         setState(AAUDIO_STREAM_STATE_STARTING);
284     }
285     return AAUDIO_OK;
286 }
287 
requestPause()288 aaudio_result_t AudioStreamTrack::requestPause() {
289     if (mAudioTrack.get() == nullptr) {
290         ALOGE("requestPause() no AudioTrack");
291         return AAUDIO_ERROR_INVALID_STATE;
292     }
293 
294     setState(AAUDIO_STREAM_STATE_PAUSING);
295     mAudioTrack->pause();
296     mCallbackEnabled.store(false);
297     status_t err = mAudioTrack->getPosition(&mPositionWhenPausing);
298     if (err != OK) {
299         return AAudioConvert_androidToAAudioResult(err);
300     }
301     return checkForDisconnectRequest(false);
302 }
303 
requestFlush()304 aaudio_result_t AudioStreamTrack::requestFlush() {
305     if (mAudioTrack.get() == nullptr) {
306         ALOGE("requestFlush() no AudioTrack");
307         return AAUDIO_ERROR_INVALID_STATE;
308     }
309 
310     setState(AAUDIO_STREAM_STATE_FLUSHING);
311     incrementFramesRead(getFramesWritten() - getFramesRead());
312     mAudioTrack->flush();
313     mFramesRead.reset32(); // service reads frames, service position reset on flush
314     mTimestampPosition.reset32();
315     return AAUDIO_OK;
316 }
317 
requestStop()318 aaudio_result_t AudioStreamTrack::requestStop() {
319     if (mAudioTrack.get() == nullptr) {
320         ALOGE("requestStop() no AudioTrack");
321         return AAUDIO_ERROR_INVALID_STATE;
322     }
323 
324     setState(AAUDIO_STREAM_STATE_STOPPING);
325     incrementFramesRead(getFramesWritten() - getFramesRead()); // TODO review
326     mTimestampPosition.set(getFramesWritten());
327     mFramesRead.reset32(); // service reads frames, service position reset on stop
328     mTimestampPosition.reset32();
329     mAudioTrack->stop();
330     mCallbackEnabled.store(false);
331     return checkForDisconnectRequest(false);;
332 }
333 
updateStateMachine()334 aaudio_result_t AudioStreamTrack::updateStateMachine()
335 {
336     status_t err;
337     aaudio_wrapping_frames_t position;
338     switch (getState()) {
339     // TODO add better state visibility to AudioTrack
340     case AAUDIO_STREAM_STATE_STARTING:
341         if (mAudioTrack->hasStarted()) {
342             setState(AAUDIO_STREAM_STATE_STARTED);
343         }
344         break;
345     case AAUDIO_STREAM_STATE_PAUSING:
346         if (mAudioTrack->stopped()) {
347             err = mAudioTrack->getPosition(&position);
348             if (err != OK) {
349                 return AAudioConvert_androidToAAudioResult(err);
350             } else if (position == mPositionWhenPausing) {
351                 // Has stream really stopped advancing?
352                 setState(AAUDIO_STREAM_STATE_PAUSED);
353             }
354             mPositionWhenPausing = position;
355         }
356         break;
357     case AAUDIO_STREAM_STATE_FLUSHING:
358         {
359             err = mAudioTrack->getPosition(&position);
360             if (err != OK) {
361                 return AAudioConvert_androidToAAudioResult(err);
362             } else if (position == 0) {
363                 // TODO Advance frames read to match written.
364                 setState(AAUDIO_STREAM_STATE_FLUSHED);
365             }
366         }
367         break;
368     case AAUDIO_STREAM_STATE_STOPPING:
369         if (mAudioTrack->stopped()) {
370             setState(AAUDIO_STREAM_STATE_STOPPED);
371         }
372         break;
373     default:
374         break;
375     }
376     return AAUDIO_OK;
377 }
378 
write(const void * buffer,int32_t numFrames,int64_t timeoutNanoseconds)379 aaudio_result_t AudioStreamTrack::write(const void *buffer,
380                                       int32_t numFrames,
381                                       int64_t timeoutNanoseconds)
382 {
383     int32_t bytesPerFrame = getBytesPerFrame();
384     int32_t numBytes;
385     aaudio_result_t result = AAudioConvert_framesToBytes(numFrames, bytesPerFrame, &numBytes);
386     if (result != AAUDIO_OK) {
387         return result;
388     }
389 
390     if (getState() == AAUDIO_STREAM_STATE_DISCONNECTED) {
391         return AAUDIO_ERROR_DISCONNECTED;
392     }
393 
394     // TODO add timeout to AudioTrack
395     bool blocking = timeoutNanoseconds > 0;
396     ssize_t bytesWritten = mAudioTrack->write(buffer, numBytes, blocking);
397     if (bytesWritten == WOULD_BLOCK) {
398         return 0;
399     } else if (bytesWritten < 0) {
400         ALOGE("invalid write, returned %d", (int)bytesWritten);
401         // in this context, a DEAD_OBJECT is more likely to be a disconnect notification due to
402         // AudioTrack invalidation
403         if (bytesWritten == DEAD_OBJECT) {
404             setState(AAUDIO_STREAM_STATE_DISCONNECTED);
405             return AAUDIO_ERROR_DISCONNECTED;
406         }
407         return AAudioConvert_androidToAAudioResult(bytesWritten);
408     }
409     int32_t framesWritten = (int32_t)(bytesWritten / bytesPerFrame);
410     incrementFramesWritten(framesWritten);
411 
412     result = updateStateMachine();
413     if (result != AAUDIO_OK) {
414         return result;
415     }
416 
417     return framesWritten;
418 }
419 
setBufferSize(int32_t requestedFrames)420 aaudio_result_t AudioStreamTrack::setBufferSize(int32_t requestedFrames)
421 {
422     ssize_t result = mAudioTrack->setBufferSizeInFrames(requestedFrames);
423     if (result < 0) {
424         return AAudioConvert_androidToAAudioResult(result);
425     } else {
426         return result;
427     }
428 }
429 
getBufferSize() const430 int32_t AudioStreamTrack::getBufferSize() const
431 {
432     return static_cast<int32_t>(mAudioTrack->getBufferSizeInFrames());
433 }
434 
getBufferCapacity() const435 int32_t AudioStreamTrack::getBufferCapacity() const
436 {
437     return static_cast<int32_t>(mAudioTrack->frameCount());
438 }
439 
getXRunCount() const440 int32_t AudioStreamTrack::getXRunCount() const
441 {
442     return static_cast<int32_t>(mAudioTrack->getUnderrunCount());
443 }
444 
getFramesPerBurst() const445 int32_t AudioStreamTrack::getFramesPerBurst() const
446 {
447     return static_cast<int32_t>(mAudioTrack->getNotificationPeriodInFrames());
448 }
449 
getFramesRead()450 int64_t AudioStreamTrack::getFramesRead() {
451     aaudio_wrapping_frames_t position;
452     status_t result;
453     switch (getState()) {
454     case AAUDIO_STREAM_STATE_STARTING:
455     case AAUDIO_STREAM_STATE_STARTED:
456     case AAUDIO_STREAM_STATE_STOPPING:
457     case AAUDIO_STREAM_STATE_PAUSING:
458     case AAUDIO_STREAM_STATE_PAUSED:
459         result = mAudioTrack->getPosition(&position);
460         if (result == OK) {
461             mFramesRead.update32(position);
462         }
463         break;
464     default:
465         break;
466     }
467     return AudioStreamLegacy::getFramesRead();
468 }
469 
getTimestamp(clockid_t clockId,int64_t * framePosition,int64_t * timeNanoseconds)470 aaudio_result_t AudioStreamTrack::getTimestamp(clockid_t clockId,
471                                      int64_t *framePosition,
472                                      int64_t *timeNanoseconds) {
473     ExtendedTimestamp extendedTimestamp;
474     status_t status = mAudioTrack->getTimestamp(&extendedTimestamp);
475     if (status == WOULD_BLOCK) {
476         return AAUDIO_ERROR_INVALID_STATE;
477     } if (status != NO_ERROR) {
478         return AAudioConvert_androidToAAudioResult(status);
479     }
480     int64_t position = 0;
481     int64_t nanoseconds = 0;
482     aaudio_result_t result = getBestTimestamp(clockId, &position,
483                                               &nanoseconds, &extendedTimestamp);
484     if (result == AAUDIO_OK) {
485         if (position < getFramesWritten()) {
486             *framePosition = position;
487             *timeNanoseconds = nanoseconds;
488             return result;
489         } else {
490             return AAUDIO_ERROR_INVALID_STATE; // TODO review, documented but not consistent
491         }
492     }
493     return result;
494 }
495 
doSetVolume()496 status_t AudioStreamTrack::doSetVolume() {
497     status_t status = NO_INIT;
498     if (mAudioTrack.get() != nullptr) {
499         float volume = getDuckAndMuteVolume();
500         mAudioTrack->setVolume(volume, volume);
501         status = NO_ERROR;
502     }
503     return status;
504 }
505 
506 #if AAUDIO_USE_VOLUME_SHAPER
507 
508 using namespace android::media::VolumeShaper;
509 
applyVolumeShaper(const VolumeShaper::Configuration & configuration,const VolumeShaper::Operation & operation)510 binder::Status AudioStreamTrack::applyVolumeShaper(
511         const VolumeShaper::Configuration& configuration,
512         const VolumeShaper::Operation& operation) {
513 
514     sp<VolumeShaper::Configuration> spConfiguration = new VolumeShaper::Configuration(configuration);
515     sp<VolumeShaper::Operation> spOperation = new VolumeShaper::Operation(operation);
516 
517     if (mAudioTrack.get() != nullptr) {
518         ALOGD("applyVolumeShaper() from IPlayer");
519         binder::Status status = mAudioTrack->applyVolumeShaper(spConfiguration, spOperation);
520         if (status < 0) { // a non-negative value is the volume shaper id.
521             ALOGE("applyVolumeShaper() failed with status %d", status);
522         }
523         return binder::Status::fromStatusT(status);
524     } else {
525         ALOGD("applyVolumeShaper()"
526                       " no AudioTrack for volume control from IPlayer");
527         return binder::Status::ok();
528     }
529 }
530 #endif
531