AudioStream.cpp revision e2155ef0ec6742db7a3128c4ef4fb96e02828d1b
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 // mThread is a pthread_t of unknown size so we need memset. 33 memset(&mThread, 0, sizeof(mThread)); 34 setPeriodNanoseconds(0); 35} 36 37aaudio_result_t AudioStream::open(const AudioStreamBuilder& builder) 38{ 39 // TODO validate parameters. 40 // Copy parameters from the Builder because the Builder may be deleted after this call. 41 mSamplesPerFrame = builder.getSamplesPerFrame(); 42 mSampleRate = builder.getSampleRate(); 43 mDeviceId = builder.getDeviceId(); 44 mFormat = builder.getFormat(); 45 mSharingMode = builder.getSharingMode(); 46 return AAUDIO_OK; 47} 48 49AudioStream::~AudioStream() { 50 close(); 51} 52 53aaudio_result_t AudioStream::waitForStateTransition(aaudio_stream_state_t startingState, 54 aaudio_stream_state_t endingState, 55 int64_t timeoutNanoseconds) 56{ 57 aaudio_stream_state_t state = getState(); 58 aaudio_stream_state_t nextState = state; 59 if (state == startingState && state != endingState) { 60 aaudio_result_t result = waitForStateChange(state, &nextState, timeoutNanoseconds); 61 if (result != AAUDIO_OK) { 62 return result; 63 } 64 } 65// It's OK if the expected transition has already occurred. 66// But if we reach an unexpected state then that is an error. 67 if (nextState != endingState) { 68 return AAUDIO_ERROR_UNEXPECTED_STATE; 69 } else { 70 return AAUDIO_OK; 71 } 72} 73 74aaudio_result_t AudioStream::waitForStateChange(aaudio_stream_state_t currentState, 75 aaudio_stream_state_t *nextState, 76 int64_t timeoutNanoseconds) 77{ 78 // TODO replace this when similar functionality added to AudioTrack.cpp 79 int64_t durationNanos = 20 * AAUDIO_NANOS_PER_MILLISECOND; 80 aaudio_stream_state_t state = getState(); 81 while (state == currentState && timeoutNanoseconds > 0) { 82 if (durationNanos > timeoutNanoseconds) { 83 durationNanos = timeoutNanoseconds; 84 } 85 AudioClock::sleepForNanos(durationNanos); 86 timeoutNanoseconds -= durationNanos; 87 88 aaudio_result_t result = updateState(); 89 if (result != AAUDIO_OK) { 90 return result; 91 } 92 93 state = getState(); 94 } 95 if (nextState != nullptr) { 96 *nextState = state; 97 } 98 return (state == currentState) ? AAUDIO_ERROR_TIMEOUT : AAUDIO_OK; 99} 100 101// This registers the app's background audio thread with the server before 102// passing control to the app. This gives the server an opportunity to boost 103// the thread's performance characteristics. 104void* AudioStream::wrapUserThread() { 105 void* procResult = nullptr; 106 mThreadRegistrationResult = registerThread(); 107 if (mThreadRegistrationResult == AAUDIO_OK) { 108 // Call application procedure. This may take a very long time. 109 procResult = mThreadProc(mThreadArg); 110 ALOGD("AudioStream::mThreadProc() returned"); 111 mThreadRegistrationResult = unregisterThread(); 112 } 113 return procResult; 114} 115 116// This is the entry point for the new thread created by createThread(). 117// It converts the 'C' function call to a C++ method call. 118static void* AudioStream_internalThreadProc(void* threadArg) { 119 AudioStream *audioStream = (AudioStream *) threadArg; 120 return audioStream->wrapUserThread(); 121} 122 123aaudio_result_t AudioStream::createThread(int64_t periodNanoseconds, 124 aaudio_audio_thread_proc_t threadProc, 125 void* threadArg) 126{ 127 if (mHasThread) { 128 return AAUDIO_ERROR_INVALID_STATE; 129 } 130 if (threadProc == nullptr) { 131 return AAUDIO_ERROR_NULL; 132 } 133 // Pass input parameters to the background thread. 134 mThreadProc = threadProc; 135 mThreadArg = threadArg; 136 setPeriodNanoseconds(periodNanoseconds); 137 int err = pthread_create(&mThread, nullptr, AudioStream_internalThreadProc, this); 138 if (err != 0) { 139 // TODO convert errno to aaudio_result_t 140 return AAUDIO_ERROR_INTERNAL; 141 } else { 142 mHasThread = true; 143 return AAUDIO_OK; 144 } 145} 146 147aaudio_result_t AudioStream::joinThread(void** returnArg, int64_t timeoutNanoseconds) 148{ 149 if (!mHasThread) { 150 return AAUDIO_ERROR_INVALID_STATE; 151 } 152#if 0 153 // TODO implement equivalent of pthread_timedjoin_np() 154 struct timespec abstime; 155 int err = pthread_timedjoin_np(mThread, returnArg, &abstime); 156#else 157 int err = pthread_join(mThread, returnArg); 158#endif 159 mHasThread = false; 160 // TODO convert errno to aaudio_result_t 161 return err ? AAUDIO_ERROR_INTERNAL : mThreadRegistrationResult; 162} 163 164