AudioStream.cpp revision e2155ef0ec6742db7a3128c4ef4fb96e02828d1b
1/*
2 * Copyright 2015 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 <atomic>
22#include <stdint.h>
23#include <aaudio/AAudio.h>
24
25#include "AudioStreamBuilder.h"
26#include "AudioStream.h"
27#include "AudioClock.h"
28
29using namespace aaudio;
30
31AudioStream::AudioStream() {
32    // mThread is a pthread_t of unknown size so we need memset.
33    memset(&mThread, 0, sizeof(mThread));
34    setPeriodNanoseconds(0);
35}
36
37aaudio_result_t AudioStream::open(const AudioStreamBuilder& builder)
38{
39    // TODO validate parameters.
40    // Copy parameters from the Builder because the Builder may be deleted after this call.
41    mSamplesPerFrame = builder.getSamplesPerFrame();
42    mSampleRate = builder.getSampleRate();
43    mDeviceId = builder.getDeviceId();
44    mFormat = builder.getFormat();
45    mSharingMode = builder.getSharingMode();
46    return AAUDIO_OK;
47}
48
49AudioStream::~AudioStream() {
50    close();
51}
52
53aaudio_result_t AudioStream::waitForStateTransition(aaudio_stream_state_t startingState,
54                                               aaudio_stream_state_t endingState,
55                                               int64_t timeoutNanoseconds)
56{
57    aaudio_stream_state_t state = getState();
58    aaudio_stream_state_t nextState = state;
59    if (state == startingState && state != endingState) {
60        aaudio_result_t result = waitForStateChange(state, &nextState, timeoutNanoseconds);
61        if (result != AAUDIO_OK) {
62            return result;
63        }
64    }
65// It's OK if the expected transition has already occurred.
66// But if we reach an unexpected state then that is an error.
67    if (nextState != endingState) {
68        return AAUDIO_ERROR_UNEXPECTED_STATE;
69    } else {
70        return AAUDIO_OK;
71    }
72}
73
74aaudio_result_t AudioStream::waitForStateChange(aaudio_stream_state_t currentState,
75                                                aaudio_stream_state_t *nextState,
76                                                int64_t timeoutNanoseconds)
77{
78    // TODO replace this when similar functionality added to AudioTrack.cpp
79    int64_t durationNanos = 20 * AAUDIO_NANOS_PER_MILLISECOND;
80    aaudio_stream_state_t state = getState();
81    while (state == currentState && timeoutNanoseconds > 0) {
82        if (durationNanos > timeoutNanoseconds) {
83            durationNanos = timeoutNanoseconds;
84        }
85        AudioClock::sleepForNanos(durationNanos);
86        timeoutNanoseconds -= durationNanos;
87
88        aaudio_result_t result = updateState();
89        if (result != AAUDIO_OK) {
90            return result;
91        }
92
93        state = getState();
94    }
95    if (nextState != nullptr) {
96        *nextState = state;
97    }
98    return (state == currentState) ? AAUDIO_ERROR_TIMEOUT : AAUDIO_OK;
99}
100
101// This registers the app's background audio thread with the server before
102// passing control to the app. This gives the server an opportunity to boost
103// the thread's performance characteristics.
104void* AudioStream::wrapUserThread() {
105    void* procResult = nullptr;
106    mThreadRegistrationResult = registerThread();
107    if (mThreadRegistrationResult == AAUDIO_OK) {
108        // Call application procedure. This may take a very long time.
109        procResult = mThreadProc(mThreadArg);
110        ALOGD("AudioStream::mThreadProc() returned");
111        mThreadRegistrationResult = unregisterThread();
112    }
113    return procResult;
114}
115
116// This is the entry point for the new thread created by createThread().
117// It converts the 'C' function call to a C++ method call.
118static void* AudioStream_internalThreadProc(void* threadArg) {
119    AudioStream *audioStream = (AudioStream *) threadArg;
120    return audioStream->wrapUserThread();
121}
122
123aaudio_result_t AudioStream::createThread(int64_t periodNanoseconds,
124                                     aaudio_audio_thread_proc_t threadProc,
125                                     void* threadArg)
126{
127    if (mHasThread) {
128        return AAUDIO_ERROR_INVALID_STATE;
129    }
130    if (threadProc == nullptr) {
131        return AAUDIO_ERROR_NULL;
132    }
133    // Pass input parameters to the background thread.
134    mThreadProc = threadProc;
135    mThreadArg = threadArg;
136    setPeriodNanoseconds(periodNanoseconds);
137    int err = pthread_create(&mThread, nullptr, AudioStream_internalThreadProc, this);
138    if (err != 0) {
139        // TODO convert errno to aaudio_result_t
140        return AAUDIO_ERROR_INTERNAL;
141    } else {
142        mHasThread = true;
143        return AAUDIO_OK;
144    }
145}
146
147aaudio_result_t AudioStream::joinThread(void** returnArg, int64_t timeoutNanoseconds)
148{
149    if (!mHasThread) {
150        return AAUDIO_ERROR_INVALID_STATE;
151    }
152#if 0
153    // TODO implement equivalent of pthread_timedjoin_np()
154    struct timespec abstime;
155    int err = pthread_timedjoin_np(mThread, returnArg, &abstime);
156#else
157    int err = pthread_join(mThread, returnArg);
158#endif
159    mHasThread = false;
160    // TODO convert errno to aaudio_result_t
161    return err ? AAUDIO_ERROR_INTERNAL : mThreadRegistrationResult;
162}
163
164