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 #define LOG_TAG "AAudioService"
18 //#define LOG_NDEBUG 0
19 #include <utils/Log.h>
20
21 #include <assert.h>
22 #include <map>
23 #include <mutex>
24 #include <utils/Singleton.h>
25
26 #include "AAudioEndpointManager.h"
27 #include "AAudioServiceEndpoint.h"
28 #include <algorithm>
29 #include <mutex>
30 #include <vector>
31
32 #include "core/AudioStreamBuilder.h"
33 #include "AAudioServiceEndpoint.h"
34 #include "AAudioServiceStreamShared.h"
35
36 using namespace android; // TODO just import names needed
37 using namespace aaudio; // TODO just import names needed
38
39 #define MIN_TIMEOUT_NANOS (1000 * AAUDIO_NANOS_PER_MILLISECOND)
40
41 // Wait at least this many times longer than the operation should take.
42 #define MIN_TIMEOUT_OPERATIONS 4
43
44 // This is the maximum size in frames. The effective size can be tuned smaller at runtime.
45 #define DEFAULT_BUFFER_CAPACITY (48 * 8)
46
47 // Set up an EXCLUSIVE MMAP stream that will be shared.
open(int32_t deviceId)48 aaudio_result_t AAudioServiceEndpoint::open(int32_t deviceId) {
49 mStreamInternal = getStreamInternal();
50
51 AudioStreamBuilder builder;
52 builder.setSharingMode(AAUDIO_SHARING_MODE_EXCLUSIVE);
53 // Don't fall back to SHARED because that would cause recursion.
54 builder.setSharingModeMatchRequired(true);
55 builder.setDeviceId(deviceId);
56 builder.setDirection(getDirection());
57 builder.setBufferCapacity(DEFAULT_BUFFER_CAPACITY);
58
59 return getStreamInternal()->open(builder);
60 }
61
close()62 aaudio_result_t AAudioServiceEndpoint::close() {
63 return getStreamInternal()->close();
64 }
65
66 // TODO, maybe use an interface to reduce exposure
registerStream(AAudioServiceStreamShared * sharedStream)67 aaudio_result_t AAudioServiceEndpoint::registerStream(AAudioServiceStreamShared *sharedStream) {
68 std::lock_guard<std::mutex> lock(mLockStreams);
69 mRegisteredStreams.push_back(sharedStream);
70 return AAUDIO_OK;
71 }
72
unregisterStream(AAudioServiceStreamShared * sharedStream)73 aaudio_result_t AAudioServiceEndpoint::unregisterStream(AAudioServiceStreamShared *sharedStream) {
74 std::lock_guard<std::mutex> lock(mLockStreams);
75 mRegisteredStreams.erase(std::remove(mRegisteredStreams.begin(), mRegisteredStreams.end(), sharedStream),
76 mRegisteredStreams.end());
77 return AAUDIO_OK;
78 }
79
startStream(AAudioServiceStreamShared * sharedStream)80 aaudio_result_t AAudioServiceEndpoint::startStream(AAudioServiceStreamShared *sharedStream) {
81 // TODO use real-time technique to avoid mutex, eg. atomic command FIFO
82 std::lock_guard<std::mutex> lock(mLockStreams);
83 mRunningStreams.push_back(sharedStream);
84 if (mRunningStreams.size() == 1) {
85 startSharingThread_l();
86 }
87 return AAUDIO_OK;
88 }
89
stopStream(AAudioServiceStreamShared * sharedStream)90 aaudio_result_t AAudioServiceEndpoint::stopStream(AAudioServiceStreamShared *sharedStream) {
91 int numRunningStreams = 0;
92 {
93 std::lock_guard<std::mutex> lock(mLockStreams);
94 mRunningStreams.erase(
95 std::remove(mRunningStreams.begin(), mRunningStreams.end(), sharedStream),
96 mRunningStreams.end());
97 numRunningStreams = mRunningStreams.size();
98 }
99 if (numRunningStreams == 0) {
100 // Don't call this under a lock because the callbackLoop also uses the lock.
101 stopSharingThread();
102 }
103 return AAUDIO_OK;
104 }
105
aaudio_endpoint_thread_proc(void * context)106 static void *aaudio_endpoint_thread_proc(void *context) {
107 AAudioServiceEndpoint *endpoint = (AAudioServiceEndpoint *) context;
108 if (endpoint != NULL) {
109 return endpoint->callbackLoop();
110 } else {
111 return NULL;
112 }
113 }
114
startSharingThread_l()115 aaudio_result_t AAudioServiceEndpoint::startSharingThread_l() {
116 // Launch the callback loop thread.
117 int64_t periodNanos = getStreamInternal()->getFramesPerBurst()
118 * AAUDIO_NANOS_PER_SECOND
119 / getSampleRate();
120 mCallbackEnabled.store(true);
121 return getStreamInternal()->createThread(periodNanos, aaudio_endpoint_thread_proc, this);
122 }
123
stopSharingThread()124 aaudio_result_t AAudioServiceEndpoint::stopSharingThread() {
125 mCallbackEnabled.store(false);
126 aaudio_result_t result = getStreamInternal()->joinThread(NULL);
127 return result;
128 }
129
disconnectRegisteredStreams()130 void AAudioServiceEndpoint::disconnectRegisteredStreams() {
131 std::lock_guard<std::mutex> lock(mLockStreams);
132 for(AAudioServiceStreamShared *sharedStream : mRunningStreams) {
133 sharedStream->onStop();
134 }
135 mRunningStreams.clear();
136 for(AAudioServiceStreamShared *sharedStream : mRegisteredStreams) {
137 sharedStream->onDisconnect();
138 }
139 mRegisteredStreams.clear();
140 }
141