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