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