1 /* 2 * Copyright (C) 2017 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 18 #define LOG_TAG "AAudioServiceEndpointShared" 19 //#define LOG_NDEBUG 0 20 #include <utils/Log.h> 21 22 #include <iomanip> 23 #include <iostream> 24 #include <sstream> 25 26 #include "binding/AAudioServiceMessage.h" 27 #include "client/AudioStreamInternal.h" 28 #include "client/AudioStreamInternalPlay.h" 29 #include "core/AudioStreamBuilder.h" 30 31 #include "AAudioServiceEndpointShared.h" 32 #include "AAudioServiceStreamShared.h" 33 #include "AAudioServiceStreamMMAP.h" 34 #include "AAudioMixer.h" 35 #include "AAudioService.h" 36 37 using namespace android; 38 using namespace aaudio; 39 40 // This is the maximum size in frames. The effective size can be tuned smaller at runtime. 41 #define DEFAULT_BUFFER_CAPACITY (48 * 8) 42 43 std::string AAudioServiceEndpointShared::dump() const { 44 std::stringstream result; 45 46 result << " SHARED: sharing exclusive stream with handle = 0x" 47 << std::setfill('0') << std::setw(8) 48 << std::hex << mStreamInternal->getServiceHandle() 49 << std::dec << std::setfill(' '); 50 result << ", XRuns = " << mStreamInternal->getXRunCount(); 51 result << "\n"; 52 result << " Running Stream Count: " << mRunningStreamCount << "\n"; 53 54 result << AAudioServiceEndpoint::dump(); 55 return result.str(); 56 } 57 58 // Share an AudioStreamInternal. 59 aaudio_result_t AAudioServiceEndpointShared::open(const aaudio::AAudioStreamRequest &request) { 60 aaudio_result_t result = AAUDIO_OK; 61 const AAudioStreamConfiguration &configuration = request.getConstantConfiguration(); 62 63 copyFrom(configuration); 64 mRequestedDeviceId = configuration.getDeviceId(); 65 66 AudioStreamBuilder builder; 67 builder.copyFrom(configuration); 68 69 builder.setSharingMode(AAUDIO_SHARING_MODE_EXCLUSIVE); 70 // Don't fall back to SHARED because that would cause recursion. 71 builder.setSharingModeMatchRequired(true); 72 73 builder.setBufferCapacity(DEFAULT_BUFFER_CAPACITY); 74 75 result = mStreamInternal->open(builder); 76 77 setSampleRate(mStreamInternal->getSampleRate()); 78 setSamplesPerFrame(mStreamInternal->getSamplesPerFrame()); 79 setDeviceId(mStreamInternal->getDeviceId()); 80 setSessionId(mStreamInternal->getSessionId()); 81 mFramesPerBurst = mStreamInternal->getFramesPerBurst(); 82 83 return result; 84 } 85 86 aaudio_result_t AAudioServiceEndpointShared::close() { 87 return getStreamInternal()->close(); 88 } 89 90 // Glue between C and C++ callbacks. 91 static void *aaudio_endpoint_thread_proc(void *arg) { 92 assert(arg != nullptr); 93 94 // The caller passed in a smart pointer to prevent the endpoint from getting deleted 95 // while the thread was launching. 96 sp<AAudioServiceEndpointShared> *endpointForThread = 97 static_cast<sp<AAudioServiceEndpointShared> *>(arg); 98 sp<AAudioServiceEndpointShared> endpoint = *endpointForThread; 99 delete endpointForThread; // Just use scoped smart pointer. Don't need this anymore. 100 void *result = endpoint->callbackLoop(); 101 // Close now so that the HW resource is freed and we can open a new device. 102 if (!endpoint->isConnected()) { 103 endpoint->close(); 104 } 105 106 return result; 107 } 108 109 aaudio_result_t aaudio::AAudioServiceEndpointShared::startSharingThread_l() { 110 // Launch the callback loop thread. 111 int64_t periodNanos = getStreamInternal()->getFramesPerBurst() 112 * AAUDIO_NANOS_PER_SECOND 113 / getSampleRate(); 114 mCallbackEnabled.store(true); 115 // Pass a smart pointer so the thread can hold a reference. 116 sp<AAudioServiceEndpointShared> *endpointForThread = new sp<AAudioServiceEndpointShared>(this); 117 aaudio_result_t result = getStreamInternal()->createThread(periodNanos, 118 aaudio_endpoint_thread_proc, 119 endpointForThread); 120 if (result != AAUDIO_OK) { 121 // The thread can't delete it so we have to do it here. 122 delete endpointForThread; 123 } 124 return result; 125 } 126 127 aaudio_result_t aaudio::AAudioServiceEndpointShared::stopSharingThread() { 128 mCallbackEnabled.store(false); 129 aaudio_result_t result = getStreamInternal()->joinThread(NULL); 130 return result; 131 } 132 133 aaudio_result_t AAudioServiceEndpointShared::startStream(sp<AAudioServiceStreamBase> sharedStream, 134 audio_port_handle_t *clientHandle) { 135 aaudio_result_t result = AAUDIO_OK; 136 137 { 138 std::lock_guard<std::mutex> lock(mLockStreams); 139 if (++mRunningStreamCount == 1) { // atomic 140 result = getStreamInternal()->requestStart(); 141 if (result != AAUDIO_OK) { 142 --mRunningStreamCount; 143 } else { 144 result = startSharingThread_l(); 145 if (result != AAUDIO_OK) { 146 getStreamInternal()->requestStop(); 147 --mRunningStreamCount; 148 } 149 } 150 } 151 } 152 153 if (result == AAUDIO_OK) { 154 result = getStreamInternal()->startClient(sharedStream->getAudioClient(), clientHandle); 155 if (result != AAUDIO_OK) { 156 if (--mRunningStreamCount == 0) { // atomic 157 stopSharingThread(); 158 getStreamInternal()->requestStop(); 159 } 160 } 161 } 162 163 return result; 164 } 165 166 aaudio_result_t AAudioServiceEndpointShared::stopStream(sp<AAudioServiceStreamBase> sharedStream, 167 audio_port_handle_t clientHandle) { 168 // Don't lock here because the disconnectRegisteredStreams also uses the lock. 169 170 // Ignore result. 171 (void) getStreamInternal()->stopClient(clientHandle); 172 173 if (--mRunningStreamCount == 0) { // atomic 174 stopSharingThread(); 175 getStreamInternal()->requestStop(); 176 } 177 return AAUDIO_OK; 178 } 179 180 // Get timestamp that was written by the real-time service thread, eg. mixer. 181 aaudio_result_t AAudioServiceEndpointShared::getFreeRunningPosition(int64_t *positionFrames, 182 int64_t *timeNanos) { 183 if (mAtomicTimestamp.isValid()) { 184 Timestamp timestamp = mAtomicTimestamp.read(); 185 *positionFrames = timestamp.getPosition(); 186 *timeNanos = timestamp.getNanoseconds(); 187 return AAUDIO_OK; 188 } else { 189 return AAUDIO_ERROR_UNAVAILABLE; 190 } 191 } 192 193 aaudio_result_t AAudioServiceEndpointShared::getTimestamp(int64_t *positionFrames, 194 int64_t *timeNanos) { 195 return mStreamInternal->getTimestamp(CLOCK_MONOTONIC, positionFrames, timeNanos); 196 } 197