1 /*
2 * Copyright (C) 2016 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 <mutex>
22
23 #include "binding/IAAudioService.h"
24 #include "binding/AAudioServiceMessage.h"
25 #include "utility/AudioClock.h"
26
27 #include "AAudioServiceStreamBase.h"
28 #include "TimestampScheduler.h"
29
30 using namespace android; // TODO just import names needed
31 using namespace aaudio; // TODO just import names needed
32
33 /**
34 * Base class for streams in the service.
35 * @return
36 */
37
AAudioServiceStreamBase()38 AAudioServiceStreamBase::AAudioServiceStreamBase()
39 : mUpMessageQueue(nullptr)
40 , mAAudioThread() {
41 }
42
~AAudioServiceStreamBase()43 AAudioServiceStreamBase::~AAudioServiceStreamBase() {
44 close();
45 }
46
open(const aaudio::AAudioStreamRequest & request,aaudio::AAudioStreamConfiguration & configurationOutput)47 aaudio_result_t AAudioServiceStreamBase::open(const aaudio::AAudioStreamRequest &request,
48 aaudio::AAudioStreamConfiguration &configurationOutput) {
49 std::lock_guard<std::mutex> lock(mLockUpMessageQueue);
50 if (mUpMessageQueue != nullptr) {
51 return AAUDIO_ERROR_INVALID_STATE;
52 } else {
53 mUpMessageQueue = new SharedRingBuffer();
54 return mUpMessageQueue->allocate(sizeof(AAudioServiceMessage), QUEUE_UP_CAPACITY_COMMANDS);
55 }
56 }
57
close()58 aaudio_result_t AAudioServiceStreamBase::close() {
59 std::lock_guard<std::mutex> lock(mLockUpMessageQueue);
60 delete mUpMessageQueue;
61 mUpMessageQueue = nullptr;
62
63 return AAUDIO_OK;
64 }
65
start()66 aaudio_result_t AAudioServiceStreamBase::start() {
67 sendServiceEvent(AAUDIO_SERVICE_EVENT_STARTED);
68 mState = AAUDIO_STREAM_STATE_STARTED;
69 mThreadEnabled.store(true);
70 return mAAudioThread.start(this);
71 }
72
pause()73 aaudio_result_t AAudioServiceStreamBase::pause() {
74
75 sendCurrentTimestamp();
76 mThreadEnabled.store(false);
77 aaudio_result_t result = mAAudioThread.stop();
78 if (result != AAUDIO_OK) {
79 processError();
80 return result;
81 }
82 sendServiceEvent(AAUDIO_SERVICE_EVENT_PAUSED);
83 mState = AAUDIO_STREAM_STATE_PAUSED;
84 return result;
85 }
86
stop()87 aaudio_result_t AAudioServiceStreamBase::stop() {
88 // TODO wait for data to be played out
89 sendCurrentTimestamp();
90 mThreadEnabled.store(false);
91 aaudio_result_t result = mAAudioThread.stop();
92 if (result != AAUDIO_OK) {
93 processError();
94 return result;
95 }
96 sendServiceEvent(AAUDIO_SERVICE_EVENT_STOPPED);
97 mState = AAUDIO_STREAM_STATE_STOPPED;
98 return result;
99 }
100
flush()101 aaudio_result_t AAudioServiceStreamBase::flush() {
102 sendServiceEvent(AAUDIO_SERVICE_EVENT_FLUSHED);
103 mState = AAUDIO_STREAM_STATE_FLUSHED;
104 return AAUDIO_OK;
105 }
106
107 // implement Runnable, periodically send timestamps to client
run()108 void AAudioServiceStreamBase::run() {
109 ALOGD("AAudioServiceStreamBase::run() entering ----------------");
110 TimestampScheduler timestampScheduler;
111 timestampScheduler.setBurstPeriod(mFramesPerBurst, mSampleRate);
112 timestampScheduler.start(AudioClock::getNanoseconds());
113 int64_t nextTime = timestampScheduler.nextAbsoluteTime();
114 while(mThreadEnabled.load()) {
115 if (AudioClock::getNanoseconds() >= nextTime) {
116 aaudio_result_t result = sendCurrentTimestamp();
117 if (result != AAUDIO_OK) {
118 break;
119 }
120 nextTime = timestampScheduler.nextAbsoluteTime();
121 } else {
122 // Sleep until it is time to send the next timestamp.
123 AudioClock::sleepUntilNanoTime(nextTime);
124 }
125 }
126 ALOGD("AAudioServiceStreamBase::run() exiting ----------------");
127 }
128
processError()129 void AAudioServiceStreamBase::processError() {
130 sendServiceEvent(AAUDIO_SERVICE_EVENT_DISCONNECTED);
131 }
132
sendServiceEvent(aaudio_service_event_t event,double dataDouble,int64_t dataLong)133 aaudio_result_t AAudioServiceStreamBase::sendServiceEvent(aaudio_service_event_t event,
134 double dataDouble,
135 int64_t dataLong) {
136 AAudioServiceMessage command;
137 command.what = AAudioServiceMessage::code::EVENT;
138 command.event.event = event;
139 command.event.dataDouble = dataDouble;
140 command.event.dataLong = dataLong;
141 return writeUpMessageQueue(&command);
142 }
143
writeUpMessageQueue(AAudioServiceMessage * command)144 aaudio_result_t AAudioServiceStreamBase::writeUpMessageQueue(AAudioServiceMessage *command) {
145 std::lock_guard<std::mutex> lock(mLockUpMessageQueue);
146 if (mUpMessageQueue == nullptr) {
147 ALOGE("writeUpMessageQueue(): mUpMessageQueue null! - stream not open");
148 return AAUDIO_ERROR_NULL;
149 }
150 int32_t count = mUpMessageQueue->getFifoBuffer()->write(command, 1);
151 if (count != 1) {
152 ALOGE("writeUpMessageQueue(): Queue full. Did client die?");
153 return AAUDIO_ERROR_WOULD_BLOCK;
154 } else {
155 return AAUDIO_OK;
156 }
157 }
158
sendCurrentTimestamp()159 aaudio_result_t AAudioServiceStreamBase::sendCurrentTimestamp() {
160 AAudioServiceMessage command;
161 aaudio_result_t result = getFreeRunningPosition(&command.timestamp.position,
162 &command.timestamp.timestamp);
163 if (result == AAUDIO_OK) {
164 // ALOGD("sendCurrentTimestamp(): position = %lld, nanos = %lld",
165 // (long long) command.timestamp.position,
166 // (long long) command.timestamp.timestamp);
167 command.what = AAudioServiceMessage::code::TIMESTAMP;
168 result = writeUpMessageQueue(&command);
169 }
170 return result;
171 }
172
173 /**
174 * Get an immutable description of the in-memory queues
175 * used to communicate with the underlying HAL or Service.
176 */
getDescription(AudioEndpointParcelable & parcelable)177 aaudio_result_t AAudioServiceStreamBase::getDescription(AudioEndpointParcelable &parcelable) {
178 // Gather information on the message queue.
179 mUpMessageQueue->fillParcelable(parcelable,
180 parcelable.mUpMessageQueueParcelable);
181 return getDownDataDescription(parcelable);
182 }