AudioStream.cpp revision 17fff38dd9d467bc5fb6cd5b9a6b183951c7750d
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 mSharingMode = builder.getSharingMode(); 47 mSharingModeMatchRequired = builder.isSharingModeMatchRequired(); 48 49 mPerformanceMode = builder.getPerformanceMode(); 50 51 // callbacks 52 mFramesPerDataCallback = builder.getFramesPerDataCallback(); 53 mDataCallbackProc = builder.getDataCallbackProc(); 54 mErrorCallbackProc = builder.getErrorCallbackProc(); 55 mDataCallbackUserData = builder.getDataCallbackUserData(); 56 mErrorCallbackUserData = builder.getErrorCallbackUserData(); 57 58 // This is very helpful for debugging in the future. 59 ALOGI("AudioStream.open(): rate = %d, channels = %d, format = %d, sharing = %d", 60 mSampleRate, mSamplesPerFrame, mFormat, mSharingMode); 61 62 // Check for values that are ridiculously out of range to prevent math overflow exploits. 63 // The service will do a better check. 64 if (mSamplesPerFrame < 0 || mSamplesPerFrame > 128) { 65 ALOGE("AudioStream::open(): samplesPerFrame out of range = %d", mSamplesPerFrame); 66 return AAUDIO_ERROR_OUT_OF_RANGE; 67 } 68 69 switch(mFormat) { 70 case AAUDIO_FORMAT_UNSPECIFIED: 71 case AAUDIO_FORMAT_PCM_I16: 72 case AAUDIO_FORMAT_PCM_FLOAT: 73 break; // valid 74 default: 75 ALOGE("AudioStream::open(): audioFormat not valid = %d", mFormat); 76 return AAUDIO_ERROR_INVALID_FORMAT; 77 // break; 78 } 79 80 if (mSampleRate != AAUDIO_UNSPECIFIED && (mSampleRate < 8000 || mSampleRate > 1000000)) { 81 ALOGE("AudioStream::open(): mSampleRate out of range = %d", mSampleRate); 82 return AAUDIO_ERROR_INVALID_RATE; 83 } 84 85 switch(mPerformanceMode) { 86 case AAUDIO_PERFORMANCE_MODE_NONE: 87 case AAUDIO_PERFORMANCE_MODE_POWER_SAVING: 88 case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY: 89 break; 90 default: 91 ALOGE("AudioStream::open(): illegal performanceMode %d", mPerformanceMode); 92 return AAUDIO_ERROR_ILLEGAL_ARGUMENT; 93 } 94 95 return AAUDIO_OK; 96} 97 98AudioStream::~AudioStream() { 99 close(); 100} 101 102aaudio_result_t AudioStream::waitForStateChange(aaudio_stream_state_t currentState, 103 aaudio_stream_state_t *nextState, 104 int64_t timeoutNanoseconds) 105{ 106 aaudio_result_t result = updateStateWhileWaiting(); 107 if (result != AAUDIO_OK) { 108 return result; 109 } 110 111 int64_t durationNanos = 20 * AAUDIO_NANOS_PER_MILLISECOND; // arbitrary 112 aaudio_stream_state_t state = getState(); 113 while (state == currentState && timeoutNanoseconds > 0) { 114 if (durationNanos > timeoutNanoseconds) { 115 durationNanos = timeoutNanoseconds; 116 } 117 AudioClock::sleepForNanos(durationNanos); 118 timeoutNanoseconds -= durationNanos; 119 120 aaudio_result_t result = updateStateWhileWaiting(); 121 if (result != AAUDIO_OK) { 122 return result; 123 } 124 125 state = getState(); 126 } 127 if (nextState != nullptr) { 128 *nextState = state; 129 } 130 return (state == currentState) ? AAUDIO_ERROR_TIMEOUT : AAUDIO_OK; 131} 132 133// This registers the callback thread with the server before 134// passing control to the app. This gives the server an opportunity to boost 135// the thread's performance characteristics. 136void* AudioStream::wrapUserThread() { 137 void* procResult = nullptr; 138 mThreadRegistrationResult = registerThread(); 139 if (mThreadRegistrationResult == AAUDIO_OK) { 140 // Run callback loop. This may take a very long time. 141 procResult = mThreadProc(mThreadArg); 142 mThreadRegistrationResult = unregisterThread(); 143 } 144 return procResult; 145} 146 147// This is the entry point for the new thread created by createThread(). 148// It converts the 'C' function call to a C++ method call. 149static void* AudioStream_internalThreadProc(void* threadArg) { 150 AudioStream *audioStream = (AudioStream *) threadArg; 151 return audioStream->wrapUserThread(); 152} 153 154// This is not exposed in the API. 155// But it is still used internally to implement callbacks for MMAP mode. 156aaudio_result_t AudioStream::createThread(int64_t periodNanoseconds, 157 aaudio_audio_thread_proc_t threadProc, 158 void* threadArg) 159{ 160 if (mHasThread) { 161 return AAUDIO_ERROR_INVALID_STATE; 162 } 163 if (threadProc == nullptr) { 164 return AAUDIO_ERROR_NULL; 165 } 166 // Pass input parameters to the background thread. 167 mThreadProc = threadProc; 168 mThreadArg = threadArg; 169 setPeriodNanoseconds(periodNanoseconds); 170 int err = pthread_create(&mThread, nullptr, AudioStream_internalThreadProc, this); 171 if (err != 0) { 172 return AAudioConvert_androidToAAudioResult(-errno); 173 } else { 174 mHasThread = true; 175 return AAUDIO_OK; 176 } 177} 178 179aaudio_result_t AudioStream::joinThread(void** returnArg, int64_t timeoutNanoseconds) 180{ 181 if (!mHasThread) { 182 return AAUDIO_ERROR_INVALID_STATE; 183 } 184#if 0 185 // TODO implement equivalent of pthread_timedjoin_np() 186 struct timespec abstime; 187 int err = pthread_timedjoin_np(mThread, returnArg, &abstime); 188#else 189 int err = pthread_join(mThread, returnArg); 190#endif 191 mHasThread = false; 192 return err ? AAudioConvert_androidToAAudioResult(-errno) : mThreadRegistrationResult; 193} 194 195