AudioStream.cpp revision 4c5129b410884ec0400cbe65fce56d0ade12d11b
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        : mCallbackEnabled(false)
33{
34    // mThread is a pthread_t of unknown size so we need memset.
35    memset(&mThread, 0, sizeof(mThread));
36    setPeriodNanoseconds(0);
37}
38
39aaudio_result_t AudioStream::open(const AudioStreamBuilder& builder)
40{
41    // Copy parameters from the Builder because the Builder may be deleted after this call.
42    mSamplesPerFrame = builder.getSamplesPerFrame();
43    mSampleRate = builder.getSampleRate();
44    mDeviceId = builder.getDeviceId();
45    mFormat = builder.getFormat();
46    mDirection = builder.getDirection();
47    mSharingMode = builder.getSharingMode();
48    mSharingModeMatchRequired = builder.isSharingModeMatchRequired();
49
50    // callbacks
51    mFramesPerDataCallback = builder.getFramesPerDataCallback();
52    mDataCallbackProc = builder.getDataCallbackProc();
53    mErrorCallbackProc = builder.getErrorCallbackProc();
54    mDataCallbackUserData = builder.getDataCallbackUserData();
55    mErrorCallbackUserData = builder.getErrorCallbackUserData();
56
57    // This is very helpful for debugging in the future.
58    ALOGI("AudioStream.open(): rate = %d, channels = %d, format = %d, sharing = %d",
59          mSampleRate, mSamplesPerFrame, mFormat, mSharingMode);
60
61    // Check for values that are ridiculously out of range to prevent math overflow exploits.
62    // The service will do a better check.
63    if (mSamplesPerFrame < 0 || mSamplesPerFrame > 128) {
64        ALOGE("AudioStream::open(): samplesPerFrame out of range = %d", mSamplesPerFrame);
65        return AAUDIO_ERROR_OUT_OF_RANGE;
66    }
67    if (mSampleRate < 0 || mSampleRate > 1000000) {
68        ALOGE("AudioStream::open(): mSampleRate out of range = %d", mSampleRate);
69        return AAUDIO_ERROR_INVALID_RATE;
70    }
71    if (mDirection != AAUDIO_DIRECTION_INPUT && mDirection != AAUDIO_DIRECTION_OUTPUT) {
72        ALOGE("AudioStream::open(): illegal direction %d", mDirection);
73        return AAUDIO_ERROR_UNEXPECTED_VALUE;
74    }
75
76    return AAUDIO_OK;
77}
78
79AudioStream::~AudioStream() {
80    close();
81}
82
83aaudio_result_t AudioStream::waitForStateChange(aaudio_stream_state_t currentState,
84                                                aaudio_stream_state_t *nextState,
85                                                int64_t timeoutNanoseconds)
86{
87    aaudio_result_t result = updateStateWhileWaiting();
88    if (result != AAUDIO_OK) {
89        return result;
90    }
91
92    // TODO replace this when similar functionality added to AudioTrack.cpp
93    int64_t durationNanos = 20 * AAUDIO_NANOS_PER_MILLISECOND; // arbitrary
94    aaudio_stream_state_t state = getState();
95    while (state == currentState && timeoutNanoseconds > 0) {
96        if (durationNanos > timeoutNanoseconds) {
97            durationNanos = timeoutNanoseconds;
98        }
99        AudioClock::sleepForNanos(durationNanos);
100        timeoutNanoseconds -= durationNanos;
101
102        aaudio_result_t result = updateStateWhileWaiting();
103        if (result != AAUDIO_OK) {
104            return result;
105        }
106
107        state = getState();
108    }
109    if (nextState != nullptr) {
110        *nextState = state;
111    }
112    return (state == currentState) ? AAUDIO_ERROR_TIMEOUT : AAUDIO_OK;
113}
114
115// This registers the callback thread with the server before
116// passing control to the app. This gives the server an opportunity to boost
117// the thread's performance characteristics.
118void* AudioStream::wrapUserThread() {
119    void* procResult = nullptr;
120    mThreadRegistrationResult = registerThread();
121    if (mThreadRegistrationResult == AAUDIO_OK) {
122        // Run callback loop. This may take a very long time.
123        procResult = mThreadProc(mThreadArg);
124        mThreadRegistrationResult = unregisterThread();
125    }
126    return procResult;
127}
128
129// This is the entry point for the new thread created by createThread().
130// It converts the 'C' function call to a C++ method call.
131static void* AudioStream_internalThreadProc(void* threadArg) {
132    AudioStream *audioStream = (AudioStream *) threadArg;
133    return audioStream->wrapUserThread();
134}
135
136aaudio_result_t AudioStream::createThread(int64_t periodNanoseconds,
137                                     aaudio_audio_thread_proc_t threadProc,
138                                     void* threadArg)
139{
140    if (mHasThread) {
141        return AAUDIO_ERROR_INVALID_STATE;
142    }
143    if (threadProc == nullptr) {
144        return AAUDIO_ERROR_NULL;
145    }
146    // Pass input parameters to the background thread.
147    mThreadProc = threadProc;
148    mThreadArg = threadArg;
149    setPeriodNanoseconds(periodNanoseconds);
150    int err = pthread_create(&mThread, nullptr, AudioStream_internalThreadProc, this);
151    if (err != 0) {
152        // TODO convert errno to aaudio_result_t
153        return AAUDIO_ERROR_INTERNAL;
154    } else {
155        mHasThread = true;
156        return AAUDIO_OK;
157    }
158}
159
160aaudio_result_t AudioStream::joinThread(void** returnArg, int64_t timeoutNanoseconds)
161{
162    if (!mHasThread) {
163        return AAUDIO_ERROR_INVALID_STATE;
164    }
165#if 0
166    // TODO implement equivalent of pthread_timedjoin_np()
167    struct timespec abstime;
168    int err = pthread_timedjoin_np(mThread, returnArg, &abstime);
169#else
170    int err = pthread_join(mThread, returnArg);
171#endif
172    mHasThread = false;
173    // TODO convert errno to aaudio_result_t
174    return err ? AAUDIO_ERROR_INTERNAL : mThreadRegistrationResult;
175}
176
177