• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "AAudio"
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 "utility/AudioClock.h"
26 #include "legacy/AudioStreamLegacy.h"
27 #include "legacy/AudioStreamTrack.h"
28 #include "utility/FixedBlockReader.h"
29 
30 using namespace android;
31 using namespace aaudio;
32 
33 // Arbitrary and somewhat generous number of bursts.
34 #define DEFAULT_BURSTS_PER_BUFFER_CAPACITY     8
35 
36 /*
37  * Create a stream that uses the AudioTrack.
38  */
AudioStreamTrack()39 AudioStreamTrack::AudioStreamTrack()
40     : AudioStreamLegacy()
41     , mFixedBlockReader(*this)
42 {
43 }
44 
~AudioStreamTrack()45 AudioStreamTrack::~AudioStreamTrack()
46 {
47     const aaudio_stream_state_t state = getState();
48     bool bad = !(state == AAUDIO_STREAM_STATE_UNINITIALIZED || state == AAUDIO_STREAM_STATE_CLOSED);
49     ALOGE_IF(bad, "stream not closed, in state %d", state);
50 }
51 
open(const AudioStreamBuilder & builder)52 aaudio_result_t AudioStreamTrack::open(const AudioStreamBuilder& builder)
53 {
54     aaudio_result_t result = AAUDIO_OK;
55 
56     result = AudioStream::open(builder);
57     if (result != OK) {
58         return result;
59     }
60 
61     // Try to create an AudioTrack
62     // Use stereo if unspecified.
63     int32_t samplesPerFrame = (getSamplesPerFrame() == AAUDIO_UNSPECIFIED)
64                               ? 2 : getSamplesPerFrame();
65     audio_channel_mask_t channelMask = audio_channel_out_mask_from_count(samplesPerFrame);
66 
67     audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE;
68     aaudio_performance_mode_t perfMode = getPerformanceMode();
69     switch(perfMode) {
70         case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY:
71             // Bypass the normal mixer and go straight to the FAST mixer.
72             flags = (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_RAW);
73             break;
74 
75         case AAUDIO_PERFORMANCE_MODE_POWER_SAVING:
76             // This uses a mixer that wakes up less often than the FAST mixer.
77             flags = AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
78             break;
79 
80         case AAUDIO_PERFORMANCE_MODE_NONE:
81         default:
82             // No flags. Use a normal mixer in front of the FAST mixer.
83             break;
84     }
85 
86     size_t frameCount = (size_t)builder.getBufferCapacity();
87 
88     int32_t notificationFrames = 0;
89 
90     audio_format_t format = (getFormat() == AAUDIO_FORMAT_UNSPECIFIED)
91             ? AUDIO_FORMAT_PCM_FLOAT
92             : AAudioConvert_aaudioToAndroidDataFormat(getFormat());
93 
94     // Setup the callback if there is one.
95     AudioTrack::callback_t callback = nullptr;
96     void *callbackData = nullptr;
97     // Note that TRANSFER_SYNC does not allow FAST track
98     AudioTrack::transfer_type streamTransferType = AudioTrack::transfer_type::TRANSFER_SYNC;
99     if (builder.getDataCallbackProc() != nullptr) {
100         streamTransferType = AudioTrack::transfer_type::TRANSFER_CALLBACK;
101         callback = getLegacyCallback();
102         callbackData = this;
103 
104         // If the total buffer size is unspecified then base the size on the burst size.
105         if (frameCount == 0
106                 && ((flags & AUDIO_OUTPUT_FLAG_FAST) != 0)) {
107             // Take advantage of a special trick that allows us to create a buffer
108             // that is some multiple of the burst size.
109             notificationFrames = 0 - DEFAULT_BURSTS_PER_BUFFER_CAPACITY;
110         } else {
111             notificationFrames = builder.getFramesPerDataCallback();
112         }
113     }
114     mCallbackBufferSize = builder.getFramesPerDataCallback();
115 
116     ALOGD("AudioStreamTrack::open(), request notificationFrames = %d, frameCount = %u",
117           notificationFrames, (uint)frameCount);
118     mAudioTrack = new AudioTrack();
119     if (getDeviceId() != AAUDIO_UNSPECIFIED) {
120         mAudioTrack->setOutputDevice(getDeviceId());
121     }
122     mAudioTrack->set(
123             (audio_stream_type_t) AUDIO_STREAM_MUSIC,
124             getSampleRate(),
125             format,
126             channelMask,
127             frameCount,
128             flags,
129             callback,
130             callbackData,
131             notificationFrames,
132             0 /*sharedBuffer*/,
133             false /*threadCanCallJava*/,
134             AUDIO_SESSION_ALLOCATE,
135             streamTransferType
136             );
137 
138     // Did we get a valid track?
139     status_t status = mAudioTrack->initCheck();
140     if (status != NO_ERROR) {
141         close();
142         ALOGE("AudioStreamTrack::open(), initCheck() returned %d", status);
143         return AAudioConvert_androidToAAudioResult(status);
144     }
145 
146     //TrackPlayerBase init
147     init(mAudioTrack.get(), PLAYER_TYPE_AAUDIO, AUDIO_USAGE_MEDIA);
148 
149     // Get the actual values from the AudioTrack.
150     setSamplesPerFrame(mAudioTrack->channelCount());
151     aaudio_format_t aaudioFormat =
152             AAudioConvert_androidToAAudioDataFormat(mAudioTrack->format());
153     setFormat(aaudioFormat);
154 
155     int32_t actualSampleRate = mAudioTrack->getSampleRate();
156     ALOGW_IF(actualSampleRate != getSampleRate(),
157              "AudioStreamTrack::open() sampleRate changed from %d to %d",
158              getSampleRate(), actualSampleRate);
159     setSampleRate(actualSampleRate);
160 
161     // We may need to pass the data through a block size adapter to guarantee constant size.
162     if (mCallbackBufferSize != AAUDIO_UNSPECIFIED) {
163         int callbackSizeBytes = getBytesPerFrame() * mCallbackBufferSize;
164         mFixedBlockReader.open(callbackSizeBytes);
165         mBlockAdapter = &mFixedBlockReader;
166     } else {
167         mBlockAdapter = nullptr;
168     }
169 
170     setState(AAUDIO_STREAM_STATE_OPEN);
171     setDeviceId(mAudioTrack->getRoutedDeviceId());
172     mAudioTrack->addAudioDeviceCallback(mDeviceCallback);
173 
174     // Update performance mode based on the actual stream.
175     // For example, if the sample rate is not allowed then you won't get a FAST track.
176     audio_output_flags_t actualFlags = mAudioTrack->getFlags();
177     aaudio_performance_mode_t actualPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE;
178     if ((actualFlags & (AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_RAW))
179         == (AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_RAW)) {
180         actualPerformanceMode = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
181 
182     } else if ((actualFlags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) != 0) {
183         actualPerformanceMode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING;
184     }
185     setPerformanceMode(actualPerformanceMode);
186     // Log warning if we did not get what we asked for.
187     ALOGW_IF(actualFlags != flags,
188              "AudioStreamTrack::open() flags changed from 0x%08X to 0x%08X",
189              flags, actualFlags);
190     ALOGW_IF(actualPerformanceMode != perfMode,
191              "AudioStreamTrack::open() perfMode changed from %d to %d",
192              perfMode, actualPerformanceMode);
193 
194     return AAUDIO_OK;
195 }
196 
close()197 aaudio_result_t AudioStreamTrack::close()
198 {
199     if (getState() != AAUDIO_STREAM_STATE_CLOSED) {
200         destroy();
201         setState(AAUDIO_STREAM_STATE_CLOSED);
202     }
203     mFixedBlockReader.close();
204     return AAUDIO_OK;
205 }
206 
processCallback(int event,void * info)207 void AudioStreamTrack::processCallback(int event, void *info) {
208 
209     switch (event) {
210         case AudioTrack::EVENT_MORE_DATA:
211             processCallbackCommon(AAUDIO_CALLBACK_OPERATION_PROCESS_DATA, info);
212             break;
213 
214             // Stream got rerouted so we disconnect.
215         case AudioTrack::EVENT_NEW_IAUDIOTRACK:
216             processCallbackCommon(AAUDIO_CALLBACK_OPERATION_DISCONNECTED, info);
217             break;
218 
219         default:
220             break;
221     }
222     return;
223 }
224 
requestStart()225 aaudio_result_t AudioStreamTrack::requestStart()
226 {
227     std::lock_guard<std::mutex> lock(mStreamMutex);
228 
229     if (mAudioTrack.get() == nullptr) {
230         return AAUDIO_ERROR_INVALID_STATE;
231     }
232     // Get current position so we can detect when the track is playing.
233     status_t err = mAudioTrack->getPosition(&mPositionWhenStarting);
234     if (err != OK) {
235         return AAudioConvert_androidToAAudioResult(err);
236     }
237 
238     err = startWithStatus();
239     if (err != OK) {
240         return AAudioConvert_androidToAAudioResult(err);
241     } else {
242         onStart();
243         setState(AAUDIO_STREAM_STATE_STARTING);
244     }
245     return AAUDIO_OK;
246 }
247 
requestPause()248 aaudio_result_t AudioStreamTrack::requestPause()
249 {
250     std::lock_guard<std::mutex> lock(mStreamMutex);
251 
252     if (mAudioTrack.get() == nullptr) {
253         return AAUDIO_ERROR_INVALID_STATE;
254     } else if (getState() != AAUDIO_STREAM_STATE_STARTING
255             && getState() != AAUDIO_STREAM_STATE_STARTED) {
256         ALOGE("requestPause(), called when state is %s",
257               AAudio_convertStreamStateToText(getState()));
258         return AAUDIO_ERROR_INVALID_STATE;
259     }
260     onStop();
261     setState(AAUDIO_STREAM_STATE_PAUSING);
262     pause();
263     status_t err = mAudioTrack->getPosition(&mPositionWhenPausing);
264     if (err != OK) {
265         return AAudioConvert_androidToAAudioResult(err);
266     }
267     return AAUDIO_OK;
268 }
269 
requestFlush()270 aaudio_result_t AudioStreamTrack::requestFlush() {
271     std::lock_guard<std::mutex> lock(mStreamMutex);
272 
273     if (mAudioTrack.get() == nullptr) {
274         return AAUDIO_ERROR_INVALID_STATE;
275     } else if (getState() != AAUDIO_STREAM_STATE_PAUSED) {
276         return AAUDIO_ERROR_INVALID_STATE;
277     }
278     setState(AAUDIO_STREAM_STATE_FLUSHING);
279     incrementFramesRead(getFramesWritten() - getFramesRead());
280     mAudioTrack->flush();
281     mFramesWritten.reset32();
282     return AAUDIO_OK;
283 }
284 
requestStop()285 aaudio_result_t AudioStreamTrack::requestStop() {
286     std::lock_guard<std::mutex> lock(mStreamMutex);
287 
288     if (mAudioTrack.get() == nullptr) {
289         return AAUDIO_ERROR_INVALID_STATE;
290     }
291     onStop();
292     setState(AAUDIO_STREAM_STATE_STOPPING);
293     incrementFramesRead(getFramesWritten() - getFramesRead()); // TODO review
294     stop();
295     mFramesWritten.reset32();
296     return AAUDIO_OK;
297 }
298 
updateStateWhileWaiting()299 aaudio_result_t AudioStreamTrack::updateStateWhileWaiting()
300 {
301     status_t err;
302     aaudio_wrapping_frames_t position;
303     switch (getState()) {
304     // TODO add better state visibility to AudioTrack
305     case AAUDIO_STREAM_STATE_STARTING:
306         if (mAudioTrack->hasStarted()) {
307             setState(AAUDIO_STREAM_STATE_STARTED);
308         }
309         break;
310     case AAUDIO_STREAM_STATE_PAUSING:
311         if (mAudioTrack->stopped()) {
312             err = mAudioTrack->getPosition(&position);
313             if (err != OK) {
314                 return AAudioConvert_androidToAAudioResult(err);
315             } else if (position == mPositionWhenPausing) {
316                 // Has stream really stopped advancing?
317                 setState(AAUDIO_STREAM_STATE_PAUSED);
318             }
319             mPositionWhenPausing = position;
320         }
321         break;
322     case AAUDIO_STREAM_STATE_FLUSHING:
323         {
324             err = mAudioTrack->getPosition(&position);
325             if (err != OK) {
326                 return AAudioConvert_androidToAAudioResult(err);
327             } else if (position == 0) {
328                 // TODO Advance frames read to match written.
329                 setState(AAUDIO_STREAM_STATE_FLUSHED);
330             }
331         }
332         break;
333     case AAUDIO_STREAM_STATE_STOPPING:
334         if (mAudioTrack->stopped()) {
335             setState(AAUDIO_STREAM_STATE_STOPPED);
336         }
337         break;
338     default:
339         break;
340     }
341     return AAUDIO_OK;
342 }
343 
write(const void * buffer,int32_t numFrames,int64_t timeoutNanoseconds)344 aaudio_result_t AudioStreamTrack::write(const void *buffer,
345                                       int32_t numFrames,
346                                       int64_t timeoutNanoseconds)
347 {
348     int32_t bytesPerFrame = getBytesPerFrame();
349     int32_t numBytes;
350     aaudio_result_t result = AAudioConvert_framesToBytes(numFrames, bytesPerFrame, &numBytes);
351     if (result != AAUDIO_OK) {
352         return result;
353     }
354 
355     if (getState() == AAUDIO_STREAM_STATE_DISCONNECTED) {
356         return AAUDIO_ERROR_DISCONNECTED;
357     }
358 
359     // TODO add timeout to AudioTrack
360     bool blocking = timeoutNanoseconds > 0;
361     ssize_t bytesWritten = mAudioTrack->write(buffer, numBytes, blocking);
362     if (bytesWritten == WOULD_BLOCK) {
363         return 0;
364     } else if (bytesWritten < 0) {
365         ALOGE("invalid write, returned %d", (int)bytesWritten);
366         // in this context, a DEAD_OBJECT is more likely to be a disconnect notification due to
367         // AudioTrack invalidation
368         if (bytesWritten == DEAD_OBJECT) {
369             setState(AAUDIO_STREAM_STATE_DISCONNECTED);
370             return AAUDIO_ERROR_DISCONNECTED;
371         }
372         return AAudioConvert_androidToAAudioResult(bytesWritten);
373     }
374     int32_t framesWritten = (int32_t)(bytesWritten / bytesPerFrame);
375     incrementFramesWritten(framesWritten);
376     return framesWritten;
377 }
378 
setBufferSize(int32_t requestedFrames)379 aaudio_result_t AudioStreamTrack::setBufferSize(int32_t requestedFrames)
380 {
381     ssize_t result = mAudioTrack->setBufferSizeInFrames(requestedFrames);
382     if (result < 0) {
383         return AAudioConvert_androidToAAudioResult(result);
384     } else {
385         return result;
386     }
387 }
388 
getBufferSize() const389 int32_t AudioStreamTrack::getBufferSize() const
390 {
391     return static_cast<int32_t>(mAudioTrack->getBufferSizeInFrames());
392 }
393 
getBufferCapacity() const394 int32_t AudioStreamTrack::getBufferCapacity() const
395 {
396     return static_cast<int32_t>(mAudioTrack->frameCount());
397 }
398 
getXRunCount() const399 int32_t AudioStreamTrack::getXRunCount() const
400 {
401     return static_cast<int32_t>(mAudioTrack->getUnderrunCount());
402 }
403 
getFramesPerBurst() const404 int32_t AudioStreamTrack::getFramesPerBurst() const
405 {
406     return static_cast<int32_t>(mAudioTrack->getNotificationPeriodInFrames());
407 }
408 
getFramesRead()409 int64_t AudioStreamTrack::getFramesRead() {
410     aaudio_wrapping_frames_t position;
411     status_t result;
412     switch (getState()) {
413     case AAUDIO_STREAM_STATE_STARTING:
414     case AAUDIO_STREAM_STATE_STARTED:
415     case AAUDIO_STREAM_STATE_STOPPING:
416     case AAUDIO_STREAM_STATE_PAUSING:
417     case AAUDIO_STREAM_STATE_PAUSED:
418         result = mAudioTrack->getPosition(&position);
419         if (result == OK) {
420             mFramesRead.update32(position);
421         }
422         break;
423     default:
424         break;
425     }
426     return AudioStream::getFramesRead();
427 }
428 
getTimestamp(clockid_t clockId,int64_t * framePosition,int64_t * timeNanoseconds)429 aaudio_result_t AudioStreamTrack::getTimestamp(clockid_t clockId,
430                                      int64_t *framePosition,
431                                      int64_t *timeNanoseconds) {
432     ExtendedTimestamp extendedTimestamp;
433     status_t status = mAudioTrack->getTimestamp(&extendedTimestamp);
434     if (status != NO_ERROR) {
435         return AAudioConvert_androidToAAudioResult(status);
436     }
437     return getBestTimestamp(clockId, framePosition, timeNanoseconds, &extendedTimestamp);
438 }
439