AudioStreamTrack.cpp revision 1d32e9f8e5ba52d69c6319270c8a63a995d2c4f2
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
30using namespace android;
31using 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 */
39AudioStreamTrack::AudioStreamTrack()
40    : AudioStreamLegacy()
41    , mFixedBlockReader(*this)
42{
43}
44
45AudioStreamTrack::~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
52aaudio_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
197aaudio_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
207void 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
225aaudio_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
248aaudio_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
270aaudio_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
285aaudio_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
299aaudio_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
344aaudio_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
379aaudio_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
389int32_t AudioStreamTrack::getBufferSize() const
390{
391    return static_cast<int32_t>(mAudioTrack->getBufferSizeInFrames());
392}
393
394int32_t AudioStreamTrack::getBufferCapacity() const
395{
396    return static_cast<int32_t>(mAudioTrack->frameCount());
397}
398
399int32_t AudioStreamTrack::getXRunCount() const
400{
401    return static_cast<int32_t>(mAudioTrack->getUnderrunCount());
402}
403
404int32_t AudioStreamTrack::getFramesPerBurst() const
405{
406    return static_cast<int32_t>(mAudioTrack->getNotificationPeriodInFrames());
407}
408
409int64_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
429aaudio_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