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 "AAudioStream" 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 29 using namespace aaudio; 30 31 AudioStream::AudioStream() 32 : mPlayerBase(new MyPlayerBase(this)) 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 39 AudioStream::~AudioStream() { 40 ALOGD("destroying %p, state = %s", this, AAudio_convertStreamStateToText(getState())); 41 // If the stream is deleted when OPEN or in use then audio resources will leak. 42 // This would indicate an internal error. So we want to find this ASAP. 43 LOG_ALWAYS_FATAL_IF(!(getState() == AAUDIO_STREAM_STATE_CLOSED 44 || getState() == AAUDIO_STREAM_STATE_UNINITIALIZED 45 || getState() == AAUDIO_STREAM_STATE_DISCONNECTED), 46 "aaudio stream still in use, state = %s", 47 AAudio_convertStreamStateToText(getState())); 48 49 mPlayerBase->clearParentReference(); // remove reference to this AudioStream 50 } 51 52 static const char *AudioStream_convertSharingModeToShortText(aaudio_sharing_mode_t sharingMode) { 53 const char *result; 54 switch (sharingMode) { 55 case AAUDIO_SHARING_MODE_EXCLUSIVE: 56 result = "EX"; 57 break; 58 case AAUDIO_SHARING_MODE_SHARED: 59 result = "SH"; 60 break; 61 default: 62 result = "?!"; 63 break; 64 } 65 return result; 66 } 67 68 aaudio_result_t AudioStream::open(const AudioStreamBuilder& builder) 69 { 70 // Call here as well because the AAudioService will call this without calling build(). 71 aaudio_result_t result = builder.validate(); 72 if (result != AAUDIO_OK) { 73 return result; 74 } 75 76 // Copy parameters from the Builder because the Builder may be deleted after this call. 77 mSamplesPerFrame = builder.getSamplesPerFrame(); 78 mSampleRate = builder.getSampleRate(); 79 mDeviceId = builder.getDeviceId(); 80 mFormat = builder.getFormat(); 81 mSharingMode = builder.getSharingMode(); 82 mSharingModeMatchRequired = builder.isSharingModeMatchRequired(); 83 84 mPerformanceMode = builder.getPerformanceMode(); 85 86 // callbacks 87 mFramesPerDataCallback = builder.getFramesPerDataCallback(); 88 mDataCallbackProc = builder.getDataCallbackProc(); 89 mErrorCallbackProc = builder.getErrorCallbackProc(); 90 mDataCallbackUserData = builder.getDataCallbackUserData(); 91 mErrorCallbackUserData = builder.getErrorCallbackUserData(); 92 93 // This is very helpful for debugging in the future. Please leave it in. 94 ALOGI("AudioStream::open() rate = %d, channels = %d, format = %d, sharing = %s, dir = %s", 95 mSampleRate, mSamplesPerFrame, mFormat, 96 AudioStream_convertSharingModeToShortText(mSharingMode), 97 (getDirection() == AAUDIO_DIRECTION_OUTPUT) ? "OUTPUT" : "INPUT"); 98 ALOGI("AudioStream::open() device = %d, perfMode = %d, callback: %s with frames = %d", 99 mDeviceId, mPerformanceMode, 100 (mDataCallbackProc == nullptr ? "OFF" : "ON"), 101 mFramesPerDataCallback); 102 103 return AAUDIO_OK; 104 } 105 106 107 aaudio_result_t AudioStream::waitForStateChange(aaudio_stream_state_t currentState, 108 aaudio_stream_state_t *nextState, 109 int64_t timeoutNanoseconds) 110 { 111 aaudio_result_t result = updateStateMachine(); 112 if (result != AAUDIO_OK) { 113 return result; 114 } 115 116 int64_t durationNanos = 20 * AAUDIO_NANOS_PER_MILLISECOND; // arbitrary 117 aaudio_stream_state_t state = getState(); 118 while (state == currentState && timeoutNanoseconds > 0) { 119 if (durationNanos > timeoutNanoseconds) { 120 durationNanos = timeoutNanoseconds; 121 } 122 AudioClock::sleepForNanos(durationNanos); 123 timeoutNanoseconds -= durationNanos; 124 125 aaudio_result_t result = updateStateMachine(); 126 if (result != AAUDIO_OK) { 127 return result; 128 } 129 130 state = getState(); 131 } 132 if (nextState != nullptr) { 133 *nextState = state; 134 } 135 return (state == currentState) ? AAUDIO_ERROR_TIMEOUT : AAUDIO_OK; 136 } 137 138 // This registers the callback thread with the server before 139 // passing control to the app. This gives the server an opportunity to boost 140 // the thread's performance characteristics. 141 void* AudioStream::wrapUserThread() { 142 void* procResult = nullptr; 143 mThreadRegistrationResult = registerThread(); 144 if (mThreadRegistrationResult == AAUDIO_OK) { 145 // Run callback loop. This may take a very long time. 146 procResult = mThreadProc(mThreadArg); 147 mThreadRegistrationResult = unregisterThread(); 148 } 149 return procResult; 150 } 151 152 // This is the entry point for the new thread created by createThread(). 153 // It converts the 'C' function call to a C++ method call. 154 static void* AudioStream_internalThreadProc(void* threadArg) { 155 AudioStream *audioStream = (AudioStream *) threadArg; 156 return audioStream->wrapUserThread(); 157 } 158 159 // This is not exposed in the API. 160 // But it is still used internally to implement callbacks for MMAP mode. 161 aaudio_result_t AudioStream::createThread(int64_t periodNanoseconds, 162 aaudio_audio_thread_proc_t threadProc, 163 void* threadArg) 164 { 165 if (mHasThread) { 166 ALOGE("AudioStream::createThread() - mHasThread already true"); 167 return AAUDIO_ERROR_INVALID_STATE; 168 } 169 if (threadProc == nullptr) { 170 return AAUDIO_ERROR_NULL; 171 } 172 // Pass input parameters to the background thread. 173 mThreadProc = threadProc; 174 mThreadArg = threadArg; 175 setPeriodNanoseconds(periodNanoseconds); 176 int err = pthread_create(&mThread, nullptr, AudioStream_internalThreadProc, this); 177 if (err != 0) { 178 return AAudioConvert_androidToAAudioResult(-errno); 179 } else { 180 mHasThread = true; 181 return AAUDIO_OK; 182 } 183 } 184 185 aaudio_result_t AudioStream::joinThread(void** returnArg, int64_t timeoutNanoseconds) 186 { 187 if (!mHasThread) { 188 ALOGE("AudioStream::joinThread() - but has no thread"); 189 return AAUDIO_ERROR_INVALID_STATE; 190 } 191 #if 0 192 // TODO implement equivalent of pthread_timedjoin_np() 193 struct timespec abstime; 194 int err = pthread_timedjoin_np(mThread, returnArg, &abstime); 195 #else 196 int err = pthread_join(mThread, returnArg); 197 #endif 198 mHasThread = false; 199 return err ? AAudioConvert_androidToAAudioResult(-errno) : mThreadRegistrationResult; 200 } 201 202 203 #if AAUDIO_USE_VOLUME_SHAPER 204 android::media::VolumeShaper::Status AudioStream::applyVolumeShaper( 205 const android::media::VolumeShaper::Configuration& configuration __unused, 206 const android::media::VolumeShaper::Operation& operation __unused) { 207 ALOGW("applyVolumeShaper() is not supported"); 208 return android::media::VolumeShaper::Status::ok(); 209 } 210 #endif 211 212 AudioStream::MyPlayerBase::MyPlayerBase(AudioStream *parent) : mParent(parent) { 213 } 214 215 AudioStream::MyPlayerBase::~MyPlayerBase() { 216 ALOGV("MyPlayerBase::~MyPlayerBase(%p) deleted", this); 217 } 218 219 void AudioStream::MyPlayerBase::registerWithAudioManager() { 220 if (!mRegistered) { 221 init(android::PLAYER_TYPE_AAUDIO, AUDIO_USAGE_MEDIA); 222 mRegistered = true; 223 } 224 } 225 226 void AudioStream::MyPlayerBase::unregisterWithAudioManager() { 227 if (mRegistered) { 228 baseDestroy(); 229 mRegistered = false; 230 } 231 } 232 233 234 void AudioStream::MyPlayerBase::destroy() { 235 unregisterWithAudioManager(); 236 } 237