AudioStreamTrack.cpp revision 35e80f34a9649752fceafa53e2094cd8eda50a0a
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#include <aaudio/AAudio.h>
24
25#include "utility/AudioClock.h"
26#include "AudioStreamTrack.h"
27#include "utility/AAudioUtilities.h"
28
29using namespace android;
30using namespace aaudio;
31
32/*
33 * Create a stream that uses the AudioTrack.
34 */
35AudioStreamTrack::AudioStreamTrack()
36    : AudioStream()
37{
38}
39
40AudioStreamTrack::~AudioStreamTrack()
41{
42    const aaudio_stream_state_t state = getState();
43    bool bad = !(state == AAUDIO_STREAM_STATE_UNINITIALIZED || state == AAUDIO_STREAM_STATE_CLOSED);
44    ALOGE_IF(bad, "stream not closed, in state %d", state);
45}
46
47aaudio_result_t AudioStreamTrack::open(const AudioStreamBuilder& builder)
48{
49    aaudio_result_t result = AAUDIO_OK;
50
51    result = AudioStream::open(builder);
52    if (result != OK) {
53        return result;
54    }
55
56    // Try to create an AudioTrack
57    // TODO Support UNSPECIFIED in AudioTrack. For now, use stereo if unspecified.
58    int32_t samplesPerFrame = (getSamplesPerFrame() == AAUDIO_UNSPECIFIED)
59                              ? 2 : getSamplesPerFrame();
60    audio_channel_mask_t channelMask = audio_channel_out_mask_from_count(samplesPerFrame);
61    ALOGD("AudioStreamTrack::open(), samplesPerFrame = %d, channelMask = 0x%08x",
62            samplesPerFrame, channelMask);
63
64    AudioTrack::callback_t callback = nullptr;
65    // TODO add more performance options
66    audio_output_flags_t flags = (audio_output_flags_t) AUDIO_OUTPUT_FLAG_FAST;
67    size_t frameCount = (builder.getBufferCapacity() == AAUDIO_UNSPECIFIED) ? 0
68                        : builder.getBufferCapacity();
69    // TODO implement an unspecified AudioTrack format then use that.
70    audio_format_t format = (getFormat() == AAUDIO_UNSPECIFIED)
71            ? AUDIO_FORMAT_PCM_FLOAT
72            : AAudioConvert_aaudioToAndroidDataFormat(getFormat());
73
74    mAudioTrack = new AudioTrack(
75            (audio_stream_type_t) AUDIO_STREAM_MUSIC,
76            getSampleRate(),
77            format,
78            channelMask,
79            frameCount,
80            flags,
81            callback,
82            nullptr,    // user callback data
83            0,          // notificationFrames
84            AUDIO_SESSION_ALLOCATE,
85            AudioTrack::transfer_type::TRANSFER_SYNC // TODO - this does not allow FAST
86            );
87
88    // Did we get a valid track?
89    status_t status = mAudioTrack->initCheck();
90    ALOGD("AudioStreamTrack::open(), initCheck() returned %d", status);
91    if (status != NO_ERROR) {
92        close();
93        ALOGE("AudioStreamTrack::open(), initCheck() returned %d", status);
94        return AAudioConvert_androidToAAudioResult(status);
95    }
96
97    // Get the actual values from the AudioTrack.
98    setSamplesPerFrame(mAudioTrack->channelCount());
99    setSampleRate(mAudioTrack->getSampleRate());
100    setFormat(AAudioConvert_androidToAAudioDataFormat(mAudioTrack->format()));
101
102    setState(AAUDIO_STREAM_STATE_OPEN);
103
104    return AAUDIO_OK;
105}
106
107aaudio_result_t AudioStreamTrack::close()
108{
109    // TODO maybe add close() or release() to AudioTrack API then call it from here
110    if (getState() != AAUDIO_STREAM_STATE_CLOSED) {
111        mAudioTrack.clear(); // TODO is this right?
112        setState(AAUDIO_STREAM_STATE_CLOSED);
113    }
114    return AAUDIO_OK;
115}
116
117aaudio_result_t AudioStreamTrack::requestStart()
118{
119    if (mAudioTrack.get() == nullptr) {
120        return AAUDIO_ERROR_INVALID_STATE;
121    }
122    // Get current position so we can detect when the track is playing.
123    status_t err = mAudioTrack->getPosition(&mPositionWhenStarting);
124    if (err != OK) {
125        return AAudioConvert_androidToAAudioResult(err);
126    }
127    err = mAudioTrack->start();
128    if (err != OK) {
129        return AAudioConvert_androidToAAudioResult(err);
130    } else {
131        setState(AAUDIO_STREAM_STATE_STARTING);
132    }
133    return AAUDIO_OK;
134}
135
136aaudio_result_t AudioStreamTrack::requestPause()
137{
138    if (mAudioTrack.get() == nullptr) {
139        return AAUDIO_ERROR_INVALID_STATE;
140    } else if (getState() != AAUDIO_STREAM_STATE_STARTING
141            && getState() != AAUDIO_STREAM_STATE_STARTED) {
142        ALOGE("requestPause(), called when state is %s", AAudio_convertStreamStateToText(getState()));
143        return AAUDIO_ERROR_INVALID_STATE;
144    }
145    setState(AAUDIO_STREAM_STATE_PAUSING);
146    mAudioTrack->pause();
147    status_t err = mAudioTrack->getPosition(&mPositionWhenPausing);
148    if (err != OK) {
149        return AAudioConvert_androidToAAudioResult(err);
150    }
151    return AAUDIO_OK;
152}
153
154aaudio_result_t AudioStreamTrack::requestFlush() {
155    if (mAudioTrack.get() == nullptr) {
156        return AAUDIO_ERROR_INVALID_STATE;
157    } else if (getState() != AAUDIO_STREAM_STATE_PAUSED) {
158        return AAUDIO_ERROR_INVALID_STATE;
159    }
160    setState(AAUDIO_STREAM_STATE_FLUSHING);
161    incrementFramesRead(getFramesWritten() - getFramesRead());
162    mAudioTrack->flush();
163    mFramesWritten.reset32();
164    return AAUDIO_OK;
165}
166
167aaudio_result_t AudioStreamTrack::requestStop() {
168    if (mAudioTrack.get() == nullptr) {
169        return AAUDIO_ERROR_INVALID_STATE;
170    }
171    setState(AAUDIO_STREAM_STATE_STOPPING);
172    incrementFramesRead(getFramesWritten() - getFramesRead()); // TODO review
173    mAudioTrack->stop();
174    mFramesWritten.reset32();
175    return AAUDIO_OK;
176}
177
178aaudio_result_t AudioStreamTrack::updateState()
179{
180    status_t err;
181    aaudio_wrapping_frames_t position;
182    switch (getState()) {
183    // TODO add better state visibility to AudioTrack
184    case AAUDIO_STREAM_STATE_STARTING:
185        if (mAudioTrack->hasStarted()) {
186            setState(AAUDIO_STREAM_STATE_STARTED);
187        }
188        break;
189    case AAUDIO_STREAM_STATE_PAUSING:
190        if (mAudioTrack->stopped()) {
191            err = mAudioTrack->getPosition(&position);
192            if (err != OK) {
193                return AAudioConvert_androidToAAudioResult(err);
194            } else if (position == mPositionWhenPausing) {
195                // Has stream really stopped advancing?
196                setState(AAUDIO_STREAM_STATE_PAUSED);
197            }
198            mPositionWhenPausing = position;
199        }
200        break;
201    case AAUDIO_STREAM_STATE_FLUSHING:
202        {
203            err = mAudioTrack->getPosition(&position);
204            if (err != OK) {
205                return AAudioConvert_androidToAAudioResult(err);
206            } else if (position == 0) {
207                // Advance frames read to match written.
208                setState(AAUDIO_STREAM_STATE_FLUSHED);
209            }
210        }
211        break;
212    case AAUDIO_STREAM_STATE_STOPPING:
213        if (mAudioTrack->stopped()) {
214            setState(AAUDIO_STREAM_STATE_STOPPED);
215        }
216        break;
217    default:
218        break;
219    }
220    return AAUDIO_OK;
221}
222
223aaudio_result_t AudioStreamTrack::write(const void *buffer,
224                                      int32_t numFrames,
225                                      int64_t timeoutNanoseconds)
226{
227    int32_t bytesPerFrame = getBytesPerFrame();
228    int32_t numBytes;
229    aaudio_result_t result = AAudioConvert_framesToBytes(numFrames, bytesPerFrame, &numBytes);
230    if (result != AAUDIO_OK) {
231        return result;
232    }
233
234    // TODO add timeout to AudioTrack
235    bool blocking = timeoutNanoseconds > 0;
236    ssize_t bytesWritten = mAudioTrack->write(buffer, numBytes, blocking);
237    if (bytesWritten == WOULD_BLOCK) {
238        return 0;
239    } else if (bytesWritten < 0) {
240        ALOGE("invalid write, returned %d", (int)bytesWritten);
241        return AAudioConvert_androidToAAudioResult(bytesWritten);
242    }
243    int32_t framesWritten = (int32_t)(bytesWritten / bytesPerFrame);
244    incrementFramesWritten(framesWritten);
245    return framesWritten;
246}
247
248aaudio_result_t AudioStreamTrack::setBufferSize(int32_t requestedFrames)
249{
250    ssize_t result = mAudioTrack->setBufferSizeInFrames(requestedFrames);
251    if (result < 0) {
252        return AAudioConvert_androidToAAudioResult(result);
253    } else {
254        return result;
255    }
256}
257
258int32_t AudioStreamTrack::getBufferSize() const
259{
260    return static_cast<int32_t>(mAudioTrack->getBufferSizeInFrames());
261}
262
263int32_t AudioStreamTrack::getBufferCapacity() const
264{
265    return static_cast<int32_t>(mAudioTrack->frameCount());
266}
267
268int32_t AudioStreamTrack::getXRunCount() const
269{
270    return static_cast<int32_t>(mAudioTrack->getUnderrunCount());
271}
272
273int32_t AudioStreamTrack::getFramesPerBurst() const
274{
275    return 192; // TODO add query to AudioTrack.cpp
276}
277
278int64_t AudioStreamTrack::getFramesRead() {
279    aaudio_wrapping_frames_t position;
280    status_t result;
281    switch (getState()) {
282    case AAUDIO_STREAM_STATE_STARTING:
283    case AAUDIO_STREAM_STATE_STARTED:
284    case AAUDIO_STREAM_STATE_STOPPING:
285        result = mAudioTrack->getPosition(&position);
286        if (result == OK) {
287            mFramesRead.update32(position);
288        }
289        break;
290    default:
291        break;
292    }
293    return AudioStream::getFramesRead();
294}
295
296aaudio_result_t AudioStreamTrack::getTimestamp(clockid_t clockId,
297                                     int64_t *framePosition,
298                                     int64_t *timeNanoseconds) {
299    ExtendedTimestamp extendedTimestamp;
300    status_t status = mAudioTrack->getTimestamp(&extendedTimestamp);
301    if (status != NO_ERROR) {
302        return AAudioConvert_androidToAAudioResult(status);
303    }
304    // TODO Merge common code into AudioStreamLegacy after rebasing.
305    int timebase;
306    switch(clockId) {
307        case CLOCK_BOOTTIME:
308            timebase = ExtendedTimestamp::TIMEBASE_BOOTTIME;
309            break;
310        case CLOCK_MONOTONIC:
311            timebase = ExtendedTimestamp::TIMEBASE_MONOTONIC;
312            break;
313        default:
314            ALOGE("getTimestamp() - Unrecognized clock type %d", (int) clockId);
315            return AAUDIO_ERROR_UNEXPECTED_VALUE;
316            break;
317    }
318    status = extendedTimestamp.getBestTimestamp(framePosition, timeNanoseconds, timebase);
319    return AAudioConvert_androidToAAudioResult(status);
320}
321