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