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