1e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk/*
2e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk * Copyright 2015 The Android Open Source Project
3e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk *
4e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk * Licensed under the Apache License, Version 2.0 (the "License");
5e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk * you may not use this file except in compliance with the License.
6e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk * You may obtain a copy of the License at
7e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk *
8e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk *      http://www.apache.org/licenses/LICENSE-2.0
9e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk *
10e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk * Unless required by applicable law or agreed to in writing, software
11e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk * distributed under the License is distributed on an "AS IS" BASIS,
12e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk * See the License for the specific language governing permissions and
14e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk * limitations under the License.
15e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk */
16e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk
175ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk#define LOG_TAG "AAudio"
18e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk//#define LOG_NDEBUG 0
19e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk#include <utils/Log.h>
20e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk
21d8bdcabbac30d48ed17fa76c83cb9ee95c290a07Phil Burk#include <atomic>
22e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk#include <stdint.h>
235ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk#include <aaudio/AAudio.h>
24e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk
25e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk#include "AudioStreamBuilder.h"
26e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk#include "AudioStream.h"
27e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk#include "AudioClock.h"
28e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk
295ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burkusing namespace aaudio;
30e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk
31e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil BurkAudioStream::AudioStream()
32e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk        : mCallbackEnabled(false)
33e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk{
34d8bdcabbac30d48ed17fa76c83cb9ee95c290a07Phil Burk    // mThread is a pthread_t of unknown size so we need memset.
35d8bdcabbac30d48ed17fa76c83cb9ee95c290a07Phil Burk    memset(&mThread, 0, sizeof(mThread));
36d8bdcabbac30d48ed17fa76c83cb9ee95c290a07Phil Burk    setPeriodNanoseconds(0);
37e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk}
38e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk
395ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burkaaudio_result_t AudioStream::open(const AudioStreamBuilder& builder)
40e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk{
41e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk    // Copy parameters from the Builder because the Builder may be deleted after this call.
42e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk    mSamplesPerFrame = builder.getSamplesPerFrame();
43e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk    mSampleRate = builder.getSampleRate();
44e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk    mDeviceId = builder.getDeviceId();
45e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk    mFormat = builder.getFormat();
46c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    mSharingMode = builder.getSharingMode();
4771f35bb687476694882a617ba4a810a0bb56fe23Phil Burk    mSharingModeMatchRequired = builder.isSharingModeMatchRequired();
48e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk
49e2fbb59e729f6c3cade3b531f6f6411417ccbf40Phil Burk    mPerformanceMode = builder.getPerformanceMode();
50e2fbb59e729f6c3cade3b531f6f6411417ccbf40Phil Burk
51e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk    // callbacks
52e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk    mFramesPerDataCallback = builder.getFramesPerDataCallback();
53e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk    mDataCallbackProc = builder.getDataCallbackProc();
54e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk    mErrorCallbackProc = builder.getErrorCallbackProc();
55e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk    mDataCallbackUserData = builder.getDataCallbackUserData();
56098b883a7dc89b65b72c6d3f1d38c6afd477a0adPhil Burk    mErrorCallbackUserData = builder.getErrorCallbackUserData();
57e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk
58cf5f6d2825d9a8430a291042ca9c6f68e5b666d0Phil Burk    // This is very helpful for debugging in the future. Please leave it in.
59cf5f6d2825d9a8430a291042ca9c6f68e5b666d0Phil Burk    ALOGI("AudioStream::open() rate = %d, channels = %d, format = %d, sharing = %d, dir = %s",
60cf5f6d2825d9a8430a291042ca9c6f68e5b666d0Phil Burk          mSampleRate, mSamplesPerFrame, mFormat, mSharingMode,
61cf5f6d2825d9a8430a291042ca9c6f68e5b666d0Phil Burk          (getDirection() == AAUDIO_DIRECTION_OUTPUT) ? "OUTPUT" : "INPUT");
62cf5f6d2825d9a8430a291042ca9c6f68e5b666d0Phil Burk    ALOGI("AudioStream::open() device = %d, perfMode = %d, callbackFrames = %d",
63cf5f6d2825d9a8430a291042ca9c6f68e5b666d0Phil Burk          mDeviceId, mPerformanceMode, mFramesPerDataCallback);
6471f35bb687476694882a617ba4a810a0bb56fe23Phil Burk
6571f35bb687476694882a617ba4a810a0bb56fe23Phil Burk    // Check for values that are ridiculously out of range to prevent math overflow exploits.
6671f35bb687476694882a617ba4a810a0bb56fe23Phil Burk    // The service will do a better check.
6771f35bb687476694882a617ba4a810a0bb56fe23Phil Burk    if (mSamplesPerFrame < 0 || mSamplesPerFrame > 128) {
6871f35bb687476694882a617ba4a810a0bb56fe23Phil Burk        ALOGE("AudioStream::open(): samplesPerFrame out of range = %d", mSamplesPerFrame);
6971f35bb687476694882a617ba4a810a0bb56fe23Phil Burk        return AAUDIO_ERROR_OUT_OF_RANGE;
7071f35bb687476694882a617ba4a810a0bb56fe23Phil Burk    }
715204d315c6c6f53188f8d1414dd1b55b6c90142bPhil Burk
725204d315c6c6f53188f8d1414dd1b55b6c90142bPhil Burk    switch(mFormat) {
735204d315c6c6f53188f8d1414dd1b55b6c90142bPhil Burk        case AAUDIO_FORMAT_UNSPECIFIED:
745204d315c6c6f53188f8d1414dd1b55b6c90142bPhil Burk        case AAUDIO_FORMAT_PCM_I16:
755204d315c6c6f53188f8d1414dd1b55b6c90142bPhil Burk        case AAUDIO_FORMAT_PCM_FLOAT:
765204d315c6c6f53188f8d1414dd1b55b6c90142bPhil Burk            break; // valid
775204d315c6c6f53188f8d1414dd1b55b6c90142bPhil Burk        default:
785204d315c6c6f53188f8d1414dd1b55b6c90142bPhil Burk            ALOGE("AudioStream::open(): audioFormat not valid = %d", mFormat);
795204d315c6c6f53188f8d1414dd1b55b6c90142bPhil Burk            return AAUDIO_ERROR_INVALID_FORMAT;
805204d315c6c6f53188f8d1414dd1b55b6c90142bPhil Burk            // break;
815204d315c6c6f53188f8d1414dd1b55b6c90142bPhil Burk    }
825204d315c6c6f53188f8d1414dd1b55b6c90142bPhil Burk
8342ed0988847a3bf3db6c3fa696c9dd4768715b1fMikhail Naganov    if (mSampleRate != AAUDIO_UNSPECIFIED && (mSampleRate < 8000 || mSampleRate > 1000000)) {
8471f35bb687476694882a617ba4a810a0bb56fe23Phil Burk        ALOGE("AudioStream::open(): mSampleRate out of range = %d", mSampleRate);
8571f35bb687476694882a617ba4a810a0bb56fe23Phil Burk        return AAUDIO_ERROR_INVALID_RATE;
86e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk    }
87e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk
88e2fbb59e729f6c3cade3b531f6f6411417ccbf40Phil Burk    switch(mPerformanceMode) {
89e2fbb59e729f6c3cade3b531f6f6411417ccbf40Phil Burk        case AAUDIO_PERFORMANCE_MODE_NONE:
90e2fbb59e729f6c3cade3b531f6f6411417ccbf40Phil Burk        case AAUDIO_PERFORMANCE_MODE_POWER_SAVING:
91e2fbb59e729f6c3cade3b531f6f6411417ccbf40Phil Burk        case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY:
92e2fbb59e729f6c3cade3b531f6f6411417ccbf40Phil Burk            break;
93e2fbb59e729f6c3cade3b531f6f6411417ccbf40Phil Burk        default:
94e2fbb59e729f6c3cade3b531f6f6411417ccbf40Phil Burk            ALOGE("AudioStream::open(): illegal performanceMode %d", mPerformanceMode);
9517fff38dd9d467bc5fb6cd5b9a6b183951c7750dPhil Burk            return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
96e2fbb59e729f6c3cade3b531f6f6411417ccbf40Phil Burk    }
97e2fbb59e729f6c3cade3b531f6f6411417ccbf40Phil Burk
985ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk    return AAUDIO_OK;
99e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk}
100e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk
101e1ce491a25faf06fdeab00dd938515f71f28b095Phil BurkAudioStream::~AudioStream() {
102e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk    close();
103e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk}
104e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk
1055ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burkaaudio_result_t AudioStream::waitForStateChange(aaudio_stream_state_t currentState,
1065ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk                                                aaudio_stream_state_t *nextState,
1073316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk                                                int64_t timeoutNanoseconds)
108e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk{
109e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk    aaudio_result_t result = updateStateWhileWaiting();
110e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk    if (result != AAUDIO_OK) {
111e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk        return result;
112e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk    }
113e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk
114e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk    int64_t durationNanos = 20 * AAUDIO_NANOS_PER_MILLISECOND; // arbitrary
1155ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk    aaudio_stream_state_t state = getState();
116e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk    while (state == currentState && timeoutNanoseconds > 0) {
117e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk        if (durationNanos > timeoutNanoseconds) {
118e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk            durationNanos = timeoutNanoseconds;
119e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk        }
120e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk        AudioClock::sleepForNanos(durationNanos);
121e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk        timeoutNanoseconds -= durationNanos;
122e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk
123e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk        aaudio_result_t result = updateStateWhileWaiting();
1245ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk        if (result != AAUDIO_OK) {
125e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk            return result;
126e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk        }
127e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk
128e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk        state = getState();
129e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk    }
130d8bdcabbac30d48ed17fa76c83cb9ee95c290a07Phil Burk    if (nextState != nullptr) {
131e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk        *nextState = state;
132e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk    }
1335ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk    return (state == currentState) ? AAUDIO_ERROR_TIMEOUT : AAUDIO_OK;
134e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk}
135e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk
13671f35bb687476694882a617ba4a810a0bb56fe23Phil Burk// This registers the callback thread with the server before
137d8bdcabbac30d48ed17fa76c83cb9ee95c290a07Phil Burk// passing control to the app. This gives the server an opportunity to boost
138d8bdcabbac30d48ed17fa76c83cb9ee95c290a07Phil Burk// the thread's performance characteristics.
139d8bdcabbac30d48ed17fa76c83cb9ee95c290a07Phil Burkvoid* AudioStream::wrapUserThread() {
140d8bdcabbac30d48ed17fa76c83cb9ee95c290a07Phil Burk    void* procResult = nullptr;
141d8bdcabbac30d48ed17fa76c83cb9ee95c290a07Phil Burk    mThreadRegistrationResult = registerThread();
1425ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk    if (mThreadRegistrationResult == AAUDIO_OK) {
14371f35bb687476694882a617ba4a810a0bb56fe23Phil Burk        // Run callback loop. This may take a very long time.
144d8bdcabbac30d48ed17fa76c83cb9ee95c290a07Phil Burk        procResult = mThreadProc(mThreadArg);
145d8bdcabbac30d48ed17fa76c83cb9ee95c290a07Phil Burk        mThreadRegistrationResult = unregisterThread();
146d8bdcabbac30d48ed17fa76c83cb9ee95c290a07Phil Burk    }
147d8bdcabbac30d48ed17fa76c83cb9ee95c290a07Phil Burk    return procResult;
148d8bdcabbac30d48ed17fa76c83cb9ee95c290a07Phil Burk}
149d8bdcabbac30d48ed17fa76c83cb9ee95c290a07Phil Burk
150d8bdcabbac30d48ed17fa76c83cb9ee95c290a07Phil Burk// This is the entry point for the new thread created by createThread().
151d8bdcabbac30d48ed17fa76c83cb9ee95c290a07Phil Burk// It converts the 'C' function call to a C++ method call.
152d8bdcabbac30d48ed17fa76c83cb9ee95c290a07Phil Burkstatic void* AudioStream_internalThreadProc(void* threadArg) {
153d8bdcabbac30d48ed17fa76c83cb9ee95c290a07Phil Burk    AudioStream *audioStream = (AudioStream *) threadArg;
154d8bdcabbac30d48ed17fa76c83cb9ee95c290a07Phil Burk    return audioStream->wrapUserThread();
155d8bdcabbac30d48ed17fa76c83cb9ee95c290a07Phil Burk}
156d8bdcabbac30d48ed17fa76c83cb9ee95c290a07Phil Burk
1575204d315c6c6f53188f8d1414dd1b55b6c90142bPhil Burk// This is not exposed in the API.
1585204d315c6c6f53188f8d1414dd1b55b6c90142bPhil Burk// But it is still used internally to implement callbacks for MMAP mode.
1593316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burkaaudio_result_t AudioStream::createThread(int64_t periodNanoseconds,
160e2155ef0ec6742db7a3128c4ef4fb96e02828d1bPhil Burk                                     aaudio_audio_thread_proc_t threadProc,
161d8bdcabbac30d48ed17fa76c83cb9ee95c290a07Phil Burk                                     void* threadArg)
162e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk{
163e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk    if (mHasThread) {
1645ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk        return AAUDIO_ERROR_INVALID_STATE;
165e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk    }
166d8bdcabbac30d48ed17fa76c83cb9ee95c290a07Phil Burk    if (threadProc == nullptr) {
1675ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk        return AAUDIO_ERROR_NULL;
168e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk    }
169d8bdcabbac30d48ed17fa76c83cb9ee95c290a07Phil Burk    // Pass input parameters to the background thread.
170d8bdcabbac30d48ed17fa76c83cb9ee95c290a07Phil Burk    mThreadProc = threadProc;
171d8bdcabbac30d48ed17fa76c83cb9ee95c290a07Phil Burk    mThreadArg = threadArg;
172d8bdcabbac30d48ed17fa76c83cb9ee95c290a07Phil Burk    setPeriodNanoseconds(periodNanoseconds);
173d8bdcabbac30d48ed17fa76c83cb9ee95c290a07Phil Burk    int err = pthread_create(&mThread, nullptr, AudioStream_internalThreadProc, this);
174e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk    if (err != 0) {
1755204d315c6c6f53188f8d1414dd1b55b6c90142bPhil Burk        return AAudioConvert_androidToAAudioResult(-errno);
176e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk    } else {
177e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk        mHasThread = true;
1785ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk        return AAUDIO_OK;
179e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk    }
180e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk}
181e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk
1823316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burkaaudio_result_t AudioStream::joinThread(void** returnArg, int64_t timeoutNanoseconds)
183e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk{
184e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk    if (!mHasThread) {
1855ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk        return AAUDIO_ERROR_INVALID_STATE;
186e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk    }
187e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk#if 0
188e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk    // TODO implement equivalent of pthread_timedjoin_np()
189e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk    struct timespec abstime;
190e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk    int err = pthread_timedjoin_np(mThread, returnArg, &abstime);
191e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk#else
192e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk    int err = pthread_join(mThread, returnArg);
193e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk#endif
194e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk    mHasThread = false;
1955204d315c6c6f53188f8d1414dd1b55b6c90142bPhil Burk    return err ? AAudioConvert_androidToAAudioResult(-errno) : mThreadRegistrationResult;
196e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk}
197e1ce491a25faf06fdeab00dd938515f71f28b095Phil Burk
198