blob: 0bc6588372bbfbd6680fbeeacd532ad800c46b31 [file] [log] [blame]
Don Turner3bf32ae2017-11-27 13:25:05 +00001/*
2 * Copyright 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#include <assert.h>
18#include <stdint.h>
Mikhail Naganovd35c5722018-02-05 17:26:45 -080019#include <stdlib.h>
Don Turner3bf32ae2017-11-27 13:25:05 +000020
21#include "aaudio/AAudioLoader.h"
Don Turner379e8e52017-11-29 15:49:29 +000022#include "aaudio/AudioStreamAAudio.h"
Don Turner3bf32ae2017-11-27 13:25:05 +000023#include "common/OboeDebug.h"
24#include "oboe/Utilities.h"
25
Mikhail Naganovd35c5722018-02-05 17:26:45 -080026#ifdef __ANDROID__
27#include <sys/system_properties.h>
28#endif
Don Turner3bf32ae2017-11-27 13:25:05 +000029
Don Turner3bf32ae2017-11-27 13:25:05 +000030using namespace oboe;
Don Turner379e8e52017-11-29 15:49:29 +000031AAudioLoader *AudioStreamAAudio::mLibLoader = nullptr;
Don Turner3bf32ae2017-11-27 13:25:05 +000032
Don Turner3bf32ae2017-11-27 13:25:05 +000033// 'C' wrapper for the data callback method
34static aaudio_data_callback_result_t oboe_aaudio_data_callback_proc(
35 AAudioStream *stream,
36 void *userData,
37 void *audioData,
38 int32_t numFrames) {
39
Don Turner379e8e52017-11-29 15:49:29 +000040 AudioStreamAAudio *oboeStream = (AudioStreamAAudio *)userData;
Don Turner3bf32ae2017-11-27 13:25:05 +000041 if (oboeStream != NULL) {
42 return static_cast<aaudio_data_callback_result_t>(
43 oboeStream->callOnAudioReady(stream, audioData, numFrames));
44 } else {
45 return static_cast<aaudio_data_callback_result_t>(DataCallbackResult::Stop);
46 }
47}
48
Don Turner379e8e52017-11-29 15:49:29 +000049static void oboe_aaudio_error_thread_proc(AudioStreamAAudio *oboeStream,
Don Turner3bf32ae2017-11-27 13:25:05 +000050 AAudioStream *stream,
51 Result error) {
52 if (oboeStream != NULL) {
53 oboeStream->onErrorInThread(stream, error);
54 }
55}
56
57// 'C' wrapper for the error callback method
58static void oboe_aaudio_error_callback_proc(
59 AAudioStream *stream,
60 void *userData,
61 aaudio_result_t error) {
62
Don Turner379e8e52017-11-29 15:49:29 +000063 AudioStreamAAudio *oboeStream = (AudioStreamAAudio *)userData;
Don Turner3bf32ae2017-11-27 13:25:05 +000064 if (oboeStream != NULL) {
65 // Handle error on a separate thread
66 std::thread t(oboe_aaudio_error_thread_proc, oboeStream, stream, static_cast<Result>(error));
67 t.detach();
68 }
69}
70
Don Turner3bf32ae2017-11-27 13:25:05 +000071namespace oboe {
72
73/*
74 * Create a stream that uses Oboe Audio API.
75 */
Don Turner379e8e52017-11-29 15:49:29 +000076AudioStreamAAudio::AudioStreamAAudio(const AudioStreamBuilder &builder)
77 : AudioStream(builder)
Don Turner3bf32ae2017-11-27 13:25:05 +000078 , mFloatCallbackBuffer(nullptr)
79 , mShortCallbackBuffer(nullptr)
Phil Burkf9fc01d2018-02-09 14:53:22 -080080 , mAAudioStream(nullptr) {
Don Turner3bf32ae2017-11-27 13:25:05 +000081 mCallbackThreadEnabled.store(false);
Don Turner379e8e52017-11-29 15:49:29 +000082 LOGD("AudioStreamAAudio() call isSupported()");
Don Turner3bf32ae2017-11-27 13:25:05 +000083 isSupported();
84}
85
Phil Burkf3c46fb2018-02-14 17:40:17 -080086AudioStreamAAudio::~AudioStreamAAudio() {
Don Turner3bf32ae2017-11-27 13:25:05 +000087 delete[] mFloatCallbackBuffer;
88 delete[] mShortCallbackBuffer;
89}
90
Don Turner379e8e52017-11-29 15:49:29 +000091bool AudioStreamAAudio::isSupported() {
Don Turner3bf32ae2017-11-27 13:25:05 +000092 mLibLoader = AAudioLoader::getInstance();
93 int openResult = mLibLoader->open();
94 return openResult == 0;
95}
96
Don Turner379e8e52017-11-29 15:49:29 +000097Result AudioStreamAAudio::open() {
Don Turner3bf32ae2017-11-27 13:25:05 +000098 Result result = Result::OK;
99
100 if (mAAudioStream != nullptr) {
101 return Result::ErrorInvalidState;
102 }
103
Don Turner379e8e52017-11-29 15:49:29 +0000104 result = AudioStream::open();
Don Turner3bf32ae2017-11-27 13:25:05 +0000105 if (result != Result::OK) {
106 return result;
107 }
108
Don Turner379e8e52017-11-29 15:49:29 +0000109 LOGD("AudioStreamAAudio(): AAudio_createStreamBuilder()");
Don Turner3bf32ae2017-11-27 13:25:05 +0000110 AAudioStreamBuilder *aaudioBuilder;
111 result = static_cast<Result>(mLibLoader->createStreamBuilder(&aaudioBuilder));
112 if (result != Result::OK) {
113 return result;
114 }
115
Don Turner379e8e52017-11-29 15:49:29 +0000116 LOGD("AudioStreamAAudio.open() try with deviceId = %d", (int) mDeviceId);
Don Turner3bf32ae2017-11-27 13:25:05 +0000117 mLibLoader->builder_setBufferCapacityInFrames(aaudioBuilder, mBufferCapacityInFrames);
118 mLibLoader->builder_setChannelCount(aaudioBuilder, mChannelCount);
119 mLibLoader->builder_setDeviceId(aaudioBuilder, mDeviceId);
120 mLibLoader->builder_setDirection(aaudioBuilder, static_cast<aaudio_direction_t>(mDirection));
121 mLibLoader->builder_setFormat(aaudioBuilder, static_cast<aaudio_format_t>(mFormat));
122 mLibLoader->builder_setSampleRate(aaudioBuilder, mSampleRate);
123 mLibLoader->builder_setSharingMode(aaudioBuilder,
124 static_cast<aaudio_sharing_mode_t>(mSharingMode));
125 mLibLoader->builder_setPerformanceMode(aaudioBuilder,
126 static_cast<aaudio_performance_mode_t>(mPerformanceMode));
127
128 // TODO get more parameters from the builder?
129
130 if (mStreamCallback != nullptr) {
131 mLibLoader->builder_setDataCallback(aaudioBuilder, oboe_aaudio_data_callback_proc, this);
132 mLibLoader->builder_setFramesPerDataCallback(aaudioBuilder, getFramesPerCallback());
133 }
134 mLibLoader->builder_setErrorCallback(aaudioBuilder, oboe_aaudio_error_callback_proc, this);
135
136 {
137 AAudioStream *stream = nullptr;
138 result = static_cast<Result>(mLibLoader->builder_openStream(aaudioBuilder, &stream));
139 mAAudioStream.store(stream);
140 }
141 if (result != Result::OK) {
142 goto error2;
143 }
144
145 // Query and cache the values that will not change.
146 mDeviceId = mLibLoader->stream_getDeviceId(mAAudioStream);
147 mChannelCount = mLibLoader->stream_getChannelCount(mAAudioStream);
148 mSampleRate = mLibLoader->stream_getSampleRate(mAAudioStream);
149 mNativeFormat = static_cast<AudioFormat>(mLibLoader->stream_getFormat(mAAudioStream));
150 if (mFormat == AudioFormat::Unspecified) {
151 mFormat = mNativeFormat;
152 }
153 mSharingMode = static_cast<SharingMode>(mLibLoader->stream_getSharingMode(mAAudioStream));
154 mPerformanceMode = static_cast<PerformanceMode>(
155 mLibLoader->stream_getPerformanceMode(mAAudioStream));
156 mBufferCapacityInFrames = mLibLoader->stream_getBufferCapacity(mAAudioStream);
157
Don Turner379e8e52017-11-29 15:49:29 +0000158 LOGD("AudioStreamAAudio.open() app format = %d", (int) mFormat);
159 LOGD("AudioStreamAAudio.open() native format = %d", (int) mNativeFormat);
160 LOGD("AudioStreamAAudio.open() sample rate = %d", (int) mSampleRate);
161 LOGD("AudioStreamAAudio.open() capacity = %d", (int) mBufferCapacityInFrames);
Don Turner3bf32ae2017-11-27 13:25:05 +0000162
163error2:
164 mLibLoader->builder_delete(aaudioBuilder);
Don Turner379e8e52017-11-29 15:49:29 +0000165 LOGD("AudioStreamAAudio.open: AAudioStream_Open() returned %s, mAAudioStream = %p",
Don Turner3bf32ae2017-11-27 13:25:05 +0000166 mLibLoader->convertResultToText(static_cast<aaudio_result_t>(result)),
167 mAAudioStream.load());
168 return result;
169}
170
Don Turner379e8e52017-11-29 15:49:29 +0000171Result AudioStreamAAudio::close()
Don Turner3bf32ae2017-11-27 13:25:05 +0000172{
173 // The main reason we have this mutex if to prevent a collision between a call
174 // by the application to stop a stream at the same time that an onError callback
175 // is being executed because of a disconnect. The close will delete the stream,
176 // which could otherwise cause the requestStop() to crash.
177 std::lock_guard<std::mutex> lock(mLock);
178 Result result = Result::OK;
179 // This will delete the AAudio stream object so we need to null out the pointer.
180 AAudioStream *stream = mAAudioStream.exchange(nullptr);
181 if (stream != nullptr) {
182 result = static_cast<Result>(mLibLoader->stream_close(stream));
183 }
184 return result;
185}
186
Don Turner379e8e52017-11-29 15:49:29 +0000187DataCallbackResult AudioStreamAAudio::callOnAudioReady(AAudioStream *stream,
Don Turner3bf32ae2017-11-27 13:25:05 +0000188 void *audioData,
189 int32_t numFrames) {
190 return mStreamCallback->onAudioReady(
191 this,
192 audioData,
193 numFrames);
194}
195
Don Turner379e8e52017-11-29 15:49:29 +0000196void AudioStreamAAudio::onErrorInThread(AAudioStream *stream, Result error) {
Don Turner3bf32ae2017-11-27 13:25:05 +0000197 LOGD("onErrorInThread() - entering ===================================");
198 assert(stream == mAAudioStream.load());
199 requestStop();
200 if (mStreamCallback != nullptr) {
201 mStreamCallback->onErrorBeforeClose(this, error);
202 }
203 close();
204 if (mStreamCallback != nullptr) {
205 mStreamCallback->onErrorAfterClose(this, error);
206 }
207 LOGD("onErrorInThread() - exiting ===================================");
208}
209
Don Turner379e8e52017-11-29 15:49:29 +0000210Result AudioStreamAAudio::convertApplicationDataToNative(int32_t numFrames) {
Don Turner3bf32ae2017-11-27 13:25:05 +0000211 Result result = Result::ErrorUnimplemented;
212 int32_t numSamples = numFrames * getChannelCount();
213 if (mFormat == AudioFormat::Float) {
214 if (mNativeFormat == AudioFormat::I16) {
215 convertFloatToPcm16(mFloatCallbackBuffer, mShortCallbackBuffer, numSamples);
216 result = Result::OK;
217 }
218 } else if (mFormat == AudioFormat::I16) {
219 if (mNativeFormat == AudioFormat::Float) {
220 convertPcm16ToFloat(mShortCallbackBuffer, mFloatCallbackBuffer, numSamples);
221 result = Result::OK;
222 }
223 }
224 return result;
225}
226
Phil Burkf9fc01d2018-02-09 14:53:22 -0800227Result AudioStreamAAudio::requestStart() {
Don Turner3bf32ae2017-11-27 13:25:05 +0000228 std::lock_guard<std::mutex> lock(mLock);
229 AAudioStream *stream = mAAudioStream.load();
230 if (stream != nullptr) {
231 return static_cast<Result>(mLibLoader->stream_requestStart(stream));
232 } else {
233 return Result::ErrorNull;
234 }
235}
236
Phil Burkf9fc01d2018-02-09 14:53:22 -0800237Result AudioStreamAAudio::requestPause() {
Don Turner3bf32ae2017-11-27 13:25:05 +0000238 std::lock_guard<std::mutex> lock(mLock);
239 AAudioStream *stream = mAAudioStream.load();
240 if (stream != nullptr) {
241 return static_cast<Result>(mLibLoader->stream_requestPause(stream));
242 } else {
243 return Result::ErrorNull;
244 }
245}
246
Don Turner379e8e52017-11-29 15:49:29 +0000247Result AudioStreamAAudio::requestFlush() {
Don Turner3bf32ae2017-11-27 13:25:05 +0000248 std::lock_guard<std::mutex> lock(mLock);
249 AAudioStream *stream = mAAudioStream.load();
250 if (stream != nullptr) {
251 return static_cast<Result>(mLibLoader->stream_requestFlush(stream));
252 } else {
253 return Result::ErrorNull;
254 }
255}
256
Phil Burkf9fc01d2018-02-09 14:53:22 -0800257Result AudioStreamAAudio::requestStop() {
Don Turner3bf32ae2017-11-27 13:25:05 +0000258 std::lock_guard<std::mutex> lock(mLock);
259 AAudioStream *stream = mAAudioStream.load();
260 if (stream != nullptr) {
261 return static_cast<Result>(mLibLoader->stream_requestStop(stream));
262 } else {
263 return Result::ErrorNull;
264 }
265}
266
Phil Burk4cf25f12018-02-14 08:05:01 -0800267ErrorOrValue<int32_t> AudioStreamAAudio::write(const void *buffer,
Don Turner3bf32ae2017-11-27 13:25:05 +0000268 int32_t numFrames,
Phil Burkf9fc01d2018-02-09 14:53:22 -0800269 int64_t timeoutNanoseconds) {
Don Turner3bf32ae2017-11-27 13:25:05 +0000270 AAudioStream *stream = mAAudioStream.load();
271 if (stream != nullptr) {
Phil Burk4cf25f12018-02-14 08:05:01 -0800272 int32_t result = mLibLoader->stream_write(mAAudioStream, buffer,
273 numFrames, timeoutNanoseconds);
Phil Burk7c193522018-02-15 08:07:52 -0800274 if (result < 0) {
275 return ErrorOrValue<int32_t>(static_cast<Result>(result));
276 } else {
277 return ErrorOrValue<int32_t>(result);
278 }
Don Turner3bf32ae2017-11-27 13:25:05 +0000279 } else {
Phil Burk4cf25f12018-02-14 08:05:01 -0800280 return ErrorOrValue<int32_t>(Result::ErrorNull);
Don Turner3bf32ae2017-11-27 13:25:05 +0000281 }
282}
283
Phil Burk4cf25f12018-02-14 08:05:01 -0800284ErrorOrValue<int32_t> AudioStreamAAudio::read(void *buffer,
Phil Burk34217a72018-02-07 20:37:17 -0800285 int32_t numFrames,
Phil Burkf9fc01d2018-02-09 14:53:22 -0800286 int64_t timeoutNanoseconds) {
Phil Burk34217a72018-02-07 20:37:17 -0800287 AAudioStream *stream = mAAudioStream.load();
288 if (stream != nullptr) {
Phil Burk4cf25f12018-02-14 08:05:01 -0800289 int32_t result = mLibLoader->stream_read(mAAudioStream, buffer,
290 numFrames, timeoutNanoseconds);
Phil Burk7c193522018-02-15 08:07:52 -0800291 if (result < 0) {
292 return ErrorOrValue<int32_t>(static_cast<Result>(result));
293 } else {
294 return ErrorOrValue<int32_t>(result);
295 }
Phil Burk34217a72018-02-07 20:37:17 -0800296 } else {
Phil Burk4cf25f12018-02-14 08:05:01 -0800297 return ErrorOrValue<int32_t>(Result::ErrorNull);
Phil Burk34217a72018-02-07 20:37:17 -0800298 }
299}
300
Don Turner379e8e52017-11-29 15:49:29 +0000301Result AudioStreamAAudio::waitForStateChange(StreamState currentState,
Don Turner3bf32ae2017-11-27 13:25:05 +0000302 StreamState *nextState,
Phil Burkf9fc01d2018-02-09 14:53:22 -0800303 int64_t timeoutNanoseconds) {
Don Turner3bf32ae2017-11-27 13:25:05 +0000304 AAudioStream *stream = mAAudioStream.load();
305 if (stream != nullptr) {
306
307 aaudio_stream_state_t aaudioNextState;
308 aaudio_result_t result = mLibLoader->stream_waitForStateChange(
309 mAAudioStream,
310 static_cast<aaudio_stream_state_t>(currentState),
311 &aaudioNextState,
312 timeoutNanoseconds);
313 *nextState = static_cast<StreamState>(aaudioNextState);
314 return static_cast<Result>(result);
315 } else {
316 return Result::ErrorNull;
317 }
318}
319
Phil Burkf9fc01d2018-02-09 14:53:22 -0800320Result AudioStreamAAudio::setBufferSizeInFrames(int32_t requestedFrames) {
Don Turner3bf32ae2017-11-27 13:25:05 +0000321 if (requestedFrames > mBufferCapacityInFrames) {
322 requestedFrames = mBufferCapacityInFrames;
323 }
324 return static_cast<Result>(mLibLoader->stream_setBufferSize(mAAudioStream, requestedFrames));
325}
326
Phil Burkf9fc01d2018-02-09 14:53:22 -0800327StreamState AudioStreamAAudio::getState() {
Don Turner3bf32ae2017-11-27 13:25:05 +0000328 AAudioStream *stream = mAAudioStream.load();
329 if (stream != nullptr) {
330 return static_cast<StreamState>(mLibLoader->stream_getState(stream));
331 } else {
332 return StreamState::Closed;
333 }
334}
335
Don Turner379e8e52017-11-29 15:49:29 +0000336int32_t AudioStreamAAudio::getBufferSizeInFrames() const {
Don Turner3bf32ae2017-11-27 13:25:05 +0000337 AAudioStream *stream = mAAudioStream.load();
338 if (stream != nullptr) {
339 return mLibLoader->stream_getBufferSize(stream);
340 } else {
341 return static_cast<int32_t>(Result::ErrorNull);
342 }
343}
344
Phil Burkf9fc01d2018-02-09 14:53:22 -0800345int32_t AudioStreamAAudio::getFramesPerBurst() {
Don Turner3bf32ae2017-11-27 13:25:05 +0000346 AAudioStream *stream = mAAudioStream.load();
347 if (stream != nullptr) {
348 return mLibLoader->stream_getFramesPerBurst(stream);
349 } else {
350 return static_cast<int32_t>(Result::ErrorNull);
351 }
352}
353
Phil Burk34217a72018-02-07 20:37:17 -0800354int64_t AudioStreamAAudio::getFramesRead() const {
Don Turner3bf32ae2017-11-27 13:25:05 +0000355 AAudioStream *stream = mAAudioStream.load();
356 if (stream != nullptr) {
357 return mLibLoader->stream_getFramesRead(stream);
358 } else {
359 return static_cast<int32_t>(Result::ErrorNull);
360 }
361}
Phil Burk34217a72018-02-07 20:37:17 -0800362
363int64_t AudioStreamAAudio::getFramesWritten() const {
Don Turner3bf32ae2017-11-27 13:25:05 +0000364 AAudioStream *stream = mAAudioStream.load();
365 if (stream != nullptr) {
366 return mLibLoader->stream_getFramesWritten(stream);
367 } else {
368 return static_cast<int64_t>(Result::ErrorNull);
369 }
370}
371
Phil Burka5d66372018-02-09 14:38:23 -0800372int32_t AudioStreamAAudio::getXRunCount() const {
Don Turner3bf32ae2017-11-27 13:25:05 +0000373 AAudioStream *stream = mAAudioStream.load();
374 if (stream != nullptr) {
375 return mLibLoader->stream_getXRunCount(stream);
376 } else {
377 return static_cast<int32_t>(Result::ErrorNull);
378 }
379}
380
Don Turner379e8e52017-11-29 15:49:29 +0000381Result AudioStreamAAudio::getTimestamp(clockid_t clockId,
Don Turner3bf32ae2017-11-27 13:25:05 +0000382 int64_t *framePosition,
383 int64_t *timeNanoseconds) {
384 AAudioStream *stream = mAAudioStream.load();
385 if (stream != nullptr) {
386 return static_cast<Result>(mLibLoader->stream_getTimestamp(stream, clockId,
387 framePosition, timeNanoseconds));
388 } else {
389 return Result::ErrorNull;
390 }
391}
392
Mikhail Naganovd35c5722018-02-05 17:26:45 -0800393} // namespace oboe