blob: 1df236561349c6dbf057d33850e0a94dcbbf7a08 [file] [log] [blame]
Phil Burkc0c70e32017-02-09 13:18:38 -08001/*
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
Phil Burk71f35bb2017-04-13 16:05:07 -070017#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"
Phil Burkc0c70e32017-02-09 13:18:38 -080028#include <algorithm>
29#include <mutex>
30#include <vector>
31
32#include "core/AudioStreamBuilder.h"
33#include "AAudioServiceEndpoint.h"
34#include "AAudioServiceStreamShared.h"
35
36using namespace android; // TODO just import names needed
37using 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
Phil Burk71f35bb2017-04-13 16:05:07 -070044// This is the maximum size in frames. The effective size can be tuned smaller at runtime.
45#define DEFAULT_BUFFER_CAPACITY (48 * 8)
46
Phil Burkc0c70e32017-02-09 13:18:38 -080047// Set up an EXCLUSIVE MMAP stream that will be shared.
Eric Laurenta17ae742017-06-29 15:43:55 -070048aaudio_result_t AAudioServiceEndpoint::open(const AAudioStreamConfiguration& configuration) {
49 mRequestedDeviceId = configuration.getDeviceId();
Phil Burk87c9f642017-05-17 07:22:39 -070050 mStreamInternal = getStreamInternal();
51
Phil Burkc0c70e32017-02-09 13:18:38 -080052 AudioStreamBuilder builder;
53 builder.setSharingMode(AAUDIO_SHARING_MODE_EXCLUSIVE);
Phil Burk71f35bb2017-04-13 16:05:07 -070054 // Don't fall back to SHARED because that would cause recursion.
55 builder.setSharingModeMatchRequired(true);
Eric Laurenta17ae742017-06-29 15:43:55 -070056 builder.setDeviceId(mRequestedDeviceId);
57 builder.setFormat(configuration.getAudioFormat());
58 builder.setSampleRate(configuration.getSampleRate());
59 builder.setSamplesPerFrame(configuration.getSamplesPerFrame());
Phil Burk87c9f642017-05-17 07:22:39 -070060 builder.setDirection(getDirection());
Phil Burk71f35bb2017-04-13 16:05:07 -070061 builder.setBufferCapacity(DEFAULT_BUFFER_CAPACITY);
62
Phil Burk87c9f642017-05-17 07:22:39 -070063 return getStreamInternal()->open(builder);
Phil Burkc0c70e32017-02-09 13:18:38 -080064}
65
66aaudio_result_t AAudioServiceEndpoint::close() {
Phil Burk87c9f642017-05-17 07:22:39 -070067 return getStreamInternal()->close();
Phil Burkc0c70e32017-02-09 13:18:38 -080068}
69
70// TODO, maybe use an interface to reduce exposure
Phil Burk11e8d332017-05-24 09:59:02 -070071aaudio_result_t AAudioServiceEndpoint::registerStream(sp<AAudioServiceStreamShared>sharedStream) {
Phil Burkc0c70e32017-02-09 13:18:38 -080072 std::lock_guard<std::mutex> lock(mLockStreams);
73 mRegisteredStreams.push_back(sharedStream);
74 return AAUDIO_OK;
75}
76
Phil Burk11e8d332017-05-24 09:59:02 -070077aaudio_result_t AAudioServiceEndpoint::unregisterStream(sp<AAudioServiceStreamShared>sharedStream) {
Phil Burkc0c70e32017-02-09 13:18:38 -080078 std::lock_guard<std::mutex> lock(mLockStreams);
79 mRegisteredStreams.erase(std::remove(mRegisteredStreams.begin(), mRegisteredStreams.end(), sharedStream),
80 mRegisteredStreams.end());
81 return AAUDIO_OK;
82}
83
Phil Burk11e8d332017-05-24 09:59:02 -070084aaudio_result_t AAudioServiceEndpoint::startStream(sp<AAudioServiceStreamShared> sharedStream) {
Phil Burkc0c70e32017-02-09 13:18:38 -080085 // TODO use real-time technique to avoid mutex, eg. atomic command FIFO
Phil Burkc0c70e32017-02-09 13:18:38 -080086 std::lock_guard<std::mutex> lock(mLockStreams);
87 mRunningStreams.push_back(sharedStream);
88 if (mRunningStreams.size() == 1) {
Phil Burk87c9f642017-05-17 07:22:39 -070089 startSharingThread_l();
Phil Burkc0c70e32017-02-09 13:18:38 -080090 }
91 return AAUDIO_OK;
92}
93
Phil Burk11e8d332017-05-24 09:59:02 -070094aaudio_result_t AAudioServiceEndpoint::stopStream(sp<AAudioServiceStreamShared> sharedStream) {
Phil Burk87c9f642017-05-17 07:22:39 -070095 int numRunningStreams = 0;
96 {
97 std::lock_guard<std::mutex> lock(mLockStreams);
98 mRunningStreams.erase(
99 std::remove(mRunningStreams.begin(), mRunningStreams.end(), sharedStream),
100 mRunningStreams.end());
101 numRunningStreams = mRunningStreams.size();
102 }
103 if (numRunningStreams == 0) {
104 // Don't call this under a lock because the callbackLoop also uses the lock.
105 stopSharingThread();
Phil Burkc0c70e32017-02-09 13:18:38 -0800106 }
107 return AAUDIO_OK;
108}
109
Phil Burk87c9f642017-05-17 07:22:39 -0700110static void *aaudio_endpoint_thread_proc(void *context) {
111 AAudioServiceEndpoint *endpoint = (AAudioServiceEndpoint *) context;
112 if (endpoint != NULL) {
113 return endpoint->callbackLoop();
Phil Burkc0c70e32017-02-09 13:18:38 -0800114 } else {
115 return NULL;
116 }
117}
118
Phil Burk87c9f642017-05-17 07:22:39 -0700119aaudio_result_t AAudioServiceEndpoint::startSharingThread_l() {
Phil Burkc0c70e32017-02-09 13:18:38 -0800120 // Launch the callback loop thread.
Phil Burk87c9f642017-05-17 07:22:39 -0700121 int64_t periodNanos = getStreamInternal()->getFramesPerBurst()
Phil Burkc0c70e32017-02-09 13:18:38 -0800122 * AAUDIO_NANOS_PER_SECOND
123 / getSampleRate();
124 mCallbackEnabled.store(true);
Phil Burk87c9f642017-05-17 07:22:39 -0700125 return getStreamInternal()->createThread(periodNanos, aaudio_endpoint_thread_proc, this);
Phil Burkc0c70e32017-02-09 13:18:38 -0800126}
127
Phil Burk87c9f642017-05-17 07:22:39 -0700128aaudio_result_t AAudioServiceEndpoint::stopSharingThread() {
Phil Burkc0c70e32017-02-09 13:18:38 -0800129 mCallbackEnabled.store(false);
Phil Burk87c9f642017-05-17 07:22:39 -0700130 aaudio_result_t result = getStreamInternal()->joinThread(NULL);
Phil Burk87c9f642017-05-17 07:22:39 -0700131 return result;
Phil Burkc0c70e32017-02-09 13:18:38 -0800132}
133
134void AAudioServiceEndpoint::disconnectRegisteredStreams() {
135 std::lock_guard<std::mutex> lock(mLockStreams);
Phil Burk11e8d332017-05-24 09:59:02 -0700136 for(auto baseStream : mRunningStreams) {
137 baseStream->onStop();
Phil Burkc0c70e32017-02-09 13:18:38 -0800138 }
139 mRunningStreams.clear();
Phil Burk11e8d332017-05-24 09:59:02 -0700140 for(auto sharedStream : mRegisteredStreams) {
Phil Burk5ef003b2017-06-30 11:43:37 -0700141 sharedStream->disconnect();
Phil Burkc0c70e32017-02-09 13:18:38 -0800142 }
143 mRegisteredStreams.clear();
144}
Eric Laurenta17ae742017-06-29 15:43:55 -0700145
146bool AAudioServiceEndpoint::matches(const AAudioStreamConfiguration& configuration) {
147 if (configuration.getDeviceId() != AAUDIO_UNSPECIFIED &&
148 configuration.getDeviceId() != mStreamInternal->getDeviceId()) {
149 return false;
150 }
151 if (configuration.getSampleRate() != AAUDIO_UNSPECIFIED &&
152 configuration.getSampleRate() != mStreamInternal->getSampleRate()) {
153 return false;
154 }
155 if (configuration.getSamplesPerFrame() != AAUDIO_UNSPECIFIED &&
156 configuration.getSamplesPerFrame() != mStreamInternal->getSamplesPerFrame()) {
157 return false;
158 }
159
160 return true;
161}