blob: 0f24771729b0068cd6693d09ffaf1d3cc5ebce48 [file] [log] [blame]
Phil Burke4d7bb42017-03-28 11:32:39 -07001/*
2 * Copyright 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 "AudioStreamLegacy"
18//#define LOG_NDEBUG 0
19#include <utils/Log.h>
20
21#include <stdint.h>
Phil Burk3d786cb2018-04-09 11:58:09 -070022
23#include <aaudio/AAudio.h>
24#include <audio_utils/primitives.h>
Phil Burke4d7bb42017-03-28 11:32:39 -070025#include <media/AudioTrack.h>
Phil Burk7328a802017-08-30 09:29:48 -070026#include <media/AudioTimestamp.h>
Phil Burk3d786cb2018-04-09 11:58:09 -070027#include <utils/String16.h>
Phil Burke4d7bb42017-03-28 11:32:39 -070028
Phil Burka9876702020-04-20 18:16:15 -070029#include "core/AudioGlobal.h"
Phil Burke4d7bb42017-03-28 11:32:39 -070030#include "core/AudioStream.h"
31#include "legacy/AudioStreamLegacy.h"
32
33using namespace android;
34using namespace aaudio;
35
36AudioStreamLegacy::AudioStreamLegacy()
Phil Burk58f5ce12020-08-12 14:29:10 +000037 : AudioStream() {
Phil Burke4d7bb42017-03-28 11:32:39 -070038}
39
Phil Burke4d7bb42017-03-28 11:32:39 -070040// Called from AudioTrack.cpp or AudioRecord.cpp
41static void AudioStreamLegacy_callback(int event, void* userData, void *info) {
42 AudioStreamLegacy *streamLegacy = (AudioStreamLegacy *) userData;
43 streamLegacy->processCallback(event, info);
44}
45
46aaudio_legacy_callback_t AudioStreamLegacy::getLegacyCallback() {
47 return AudioStreamLegacy_callback;
48}
49
Phil Burk3d786cb2018-04-09 11:58:09 -070050aaudio_data_callback_result_t AudioStreamLegacy::callDataCallbackFrames(uint8_t *buffer,
51 int32_t numFrames) {
52 void *finalAudioData = buffer;
Phil Burk7328a802017-08-30 09:29:48 -070053 if (getDirection() == AAUDIO_DIRECTION_INPUT) {
54 // Increment before because we already got the data from the device.
55 incrementFramesRead(numFrames);
Phil Burk3d786cb2018-04-09 11:58:09 -070056 finalAudioData = (void *) maybeConvertDeviceData(buffer, numFrames);
Phil Burk7328a802017-08-30 09:29:48 -070057 }
58
Phil Burke4d7bb42017-03-28 11:32:39 -070059 // Call using the AAudio callback interface.
Phil Burk3d786cb2018-04-09 11:58:09 -070060 aaudio_data_callback_result_t callbackResult = maybeCallDataCallback(finalAudioData, numFrames);
Phil Burk7328a802017-08-30 09:29:48 -070061
62 if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE
63 && getDirection() == AAUDIO_DIRECTION_OUTPUT) {
64 // Increment after because we are going to write the data to the device.
65 incrementFramesWritten(numFrames);
66 }
67 return callbackResult;
68}
69
70// Implement FixedBlockProcessor
71int32_t AudioStreamLegacy::onProcessFixedBlock(uint8_t *buffer, int32_t numBytes) {
Phil Burk4b867492020-02-12 10:58:05 -080072 int32_t numFrames = numBytes / mBlockAdapterBytesPerFrame;
Phil Burk134f1972017-12-08 13:06:11 -080073 return (int32_t) callDataCallbackFrames(buffer, numFrames);
Phil Burke4d7bb42017-03-28 11:32:39 -070074}
75
76void AudioStreamLegacy::processCallbackCommon(aaudio_callback_operation_t opcode, void *info) {
77 aaudio_data_callback_result_t callbackResult;
Phil Burk1e83bee2018-12-17 14:15:20 -080078 // This illegal size can be used to tell AudioRecord or AudioTrack to stop calling us.
79 // This takes advantage of them killing the stream when they see a size out of range.
80 // That is an undocumented behavior.
Phil Burk3d786cb2018-04-09 11:58:09 -070081 // TODO add to API in AudioRecord and AudioTrack
Phil Burk134f1972017-12-08 13:06:11 -080082 const size_t SIZE_STOP_CALLBACKS = SIZE_MAX;
Eric Laurentfb00fc72017-05-25 18:17:12 -070083
Phil Burke4d7bb42017-03-28 11:32:39 -070084 switch (opcode) {
85 case AAUDIO_CALLBACK_OPERATION_PROCESS_DATA: {
Phil Burk134f1972017-12-08 13:06:11 -080086 (void) checkForDisconnectRequest(true);
Phil Burk2d5ba532017-09-06 14:36:11 -070087
88 // Note that this code assumes an AudioTrack::Buffer is the same as
89 // AudioRecord::Buffer
90 // TODO define our own AudioBuffer and pass it from the subclasses.
91 AudioTrack::Buffer *audioBuffer = static_cast<AudioTrack::Buffer *>(info);
Phil Burk9e9a95b2018-01-18 12:14:15 -080092 if (getState() == AAUDIO_STREAM_STATE_DISCONNECTED) {
93 ALOGW("processCallbackCommon() data, stream disconnected");
Phil Burkdf3a3142021-06-25 21:29:39 +000094 // This will kill the stream and prevent it from being restarted.
95 // That is OK because the stream is disconnected.
Phil Burk9e9a95b2018-01-18 12:14:15 -080096 audioBuffer->size = SIZE_STOP_CALLBACKS;
97 } else if (!mCallbackEnabled.load()) {
Phil Burkdf3a3142021-06-25 21:29:39 +000098 ALOGW("processCallbackCommon() no data because callback disabled, set size=0");
99 // Do NOT use SIZE_STOP_CALLBACKS here because that will kill the stream and
100 // prevent it from being restarted. This can occur because of a race condition
101 // caused by Legacy callbacks running after the track is "stopped".
102 audioBuffer->size = 0;
Phil Burk2d5ba532017-09-06 14:36:11 -0700103 } else {
104 if (audioBuffer->frameCount == 0) {
Phil Burk9e9a95b2018-01-18 12:14:15 -0800105 ALOGW("processCallbackCommon() data, frameCount is zero");
Phil Burk2d5ba532017-09-06 14:36:11 -0700106 return;
107 }
Phil Burke4d7bb42017-03-28 11:32:39 -0700108
Eric Laurentfb00fc72017-05-25 18:17:12 -0700109 // If the caller specified an exact size then use a block size adapter.
110 if (mBlockAdapter != nullptr) {
Phil Burk3d786cb2018-04-09 11:58:09 -0700111 int32_t byteCount = audioBuffer->frameCount * getBytesPerDeviceFrame();
Eric Laurentfb00fc72017-05-25 18:17:12 -0700112 callbackResult = mBlockAdapter->processVariableBlock(
113 (uint8_t *) audioBuffer->raw, byteCount);
114 } else {
115 // Call using the AAudio callback interface.
Phil Burk7328a802017-08-30 09:29:48 -0700116 callbackResult = callDataCallbackFrames((uint8_t *)audioBuffer->raw,
117 audioBuffer->frameCount);
Eric Laurentfb00fc72017-05-25 18:17:12 -0700118 }
119 if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE) {
Phil Burk3d786cb2018-04-09 11:58:09 -0700120 audioBuffer->size = audioBuffer->frameCount * getBytesPerDeviceFrame();
Phil Burk1e83bee2018-12-17 14:15:20 -0800121 } else {
122 if (callbackResult == AAUDIO_CALLBACK_RESULT_STOP) {
123 ALOGD("%s() callback returned AAUDIO_CALLBACK_RESULT_STOP", __func__);
124 } else {
125 ALOGW("%s() callback returned invalid result = %d",
126 __func__, callbackResult);
127 }
128 audioBuffer->size = 0;
Phil Burk5ff3b952021-04-02 17:29:11 +0000129 systemStopInternal();
Phil Burk1e83bee2018-12-17 14:15:20 -0800130 // Disable the callback just in case the system keeps trying to call us.
Phil Burk134f1972017-12-08 13:06:11 -0800131 mCallbackEnabled.store(false);
Eric Laurentfb00fc72017-05-25 18:17:12 -0700132 }
Phil Burk0befec62017-07-28 15:12:13 -0700133
Phil Burk2d5ba532017-09-06 14:36:11 -0700134 if (updateStateMachine() != AAUDIO_OK) {
135 forceDisconnect();
136 mCallbackEnabled.store(false);
Phil Burk0befec62017-07-28 15:12:13 -0700137 }
Phil Burke4d7bb42017-03-28 11:32:39 -0700138 }
139 }
Phil Burk2d5ba532017-09-06 14:36:11 -0700140 break;
Phil Burke4d7bb42017-03-28 11:32:39 -0700141
Phil Burk0befec62017-07-28 15:12:13 -0700142 // Stream got rerouted so we disconnect.
Phil Burk2d5ba532017-09-06 14:36:11 -0700143 case AAUDIO_CALLBACK_OPERATION_DISCONNECTED:
Eric Laurentfb00fc72017-05-25 18:17:12 -0700144 ALOGD("processCallbackCommon() stream disconnected");
Phil Burk2d5ba532017-09-06 14:36:11 -0700145 forceDisconnect();
Phil Burke4d7bb42017-03-28 11:32:39 -0700146 mCallbackEnabled.store(false);
Phil Burke4d7bb42017-03-28 11:32:39 -0700147 break;
148
149 default:
150 break;
151 }
152}
Phil Burk5204d312017-05-04 17:16:13 -0700153
Phil Burk134f1972017-12-08 13:06:11 -0800154aaudio_result_t AudioStreamLegacy::checkForDisconnectRequest(bool errorCallbackEnabled) {
Phil Burk2d5ba532017-09-06 14:36:11 -0700155 if (mRequestDisconnect.isRequested()) {
156 ALOGD("checkForDisconnectRequest() mRequestDisconnect acknowledged");
Phil Burk134f1972017-12-08 13:06:11 -0800157 forceDisconnect(errorCallbackEnabled);
Phil Burk2d5ba532017-09-06 14:36:11 -0700158 mRequestDisconnect.acknowledge();
159 mCallbackEnabled.store(false);
Phil Burk134f1972017-12-08 13:06:11 -0800160 return AAUDIO_ERROR_DISCONNECTED;
161 } else {
162 return AAUDIO_OK;
Phil Burk2d5ba532017-09-06 14:36:11 -0700163 }
164}
165
Phil Burk134f1972017-12-08 13:06:11 -0800166void AudioStreamLegacy::forceDisconnect(bool errorCallbackEnabled) {
Phil Burk58f5ce12020-08-12 14:29:10 +0000167 // There is no need to disconnect if already in these states.
168 if (getState() != AAUDIO_STREAM_STATE_DISCONNECTED
169 && getState() != AAUDIO_STREAM_STATE_CLOSING
170 && getState() != AAUDIO_STREAM_STATE_CLOSED
171 ) {
Phil Burk2d5ba532017-09-06 14:36:11 -0700172 setState(AAUDIO_STREAM_STATE_DISCONNECTED);
Phil Burk134f1972017-12-08 13:06:11 -0800173 if (errorCallbackEnabled) {
174 maybeCallErrorCallback(AAUDIO_ERROR_DISCONNECTED);
Phil Burk2d5ba532017-09-06 14:36:11 -0700175 }
176 }
177}
178
Phil Burk5204d312017-05-04 17:16:13 -0700179aaudio_result_t AudioStreamLegacy::getBestTimestamp(clockid_t clockId,
180 int64_t *framePosition,
181 int64_t *timeNanoseconds,
182 ExtendedTimestamp *extendedTimestamp) {
183 int timebase;
184 switch (clockId) {
185 case CLOCK_BOOTTIME:
186 timebase = ExtendedTimestamp::TIMEBASE_BOOTTIME;
187 break;
188 case CLOCK_MONOTONIC:
189 timebase = ExtendedTimestamp::TIMEBASE_MONOTONIC;
190 break;
191 default:
192 ALOGE("getTimestamp() - Unrecognized clock type %d", (int) clockId);
Phil Burk17fff382017-05-16 14:06:45 -0700193 return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
Phil Burk5204d312017-05-04 17:16:13 -0700194 break;
195 }
Phil Burk7328a802017-08-30 09:29:48 -0700196 ExtendedTimestamp::Location location = ExtendedTimestamp::Location::LOCATION_INVALID;
197 int64_t localPosition;
198 status_t status = extendedTimestamp->getBestTimestamp(&localPosition, timeNanoseconds,
199 timebase, &location);
Phil Burkc0959642018-04-05 18:11:01 -0700200 if (status == OK) {
201 // use MonotonicCounter to prevent retrograde motion.
202 mTimestampPosition.update32((int32_t) localPosition);
203 *framePosition = mTimestampPosition.get();
204 }
Phil Burk7328a802017-08-30 09:29:48 -0700205
206// ALOGD("getBestTimestamp() fposition: server = %6lld, kernel = %6lld, location = %d",
207// (long long) extendedTimestamp->mPosition[ExtendedTimestamp::Location::LOCATION_SERVER],
208// (long long) extendedTimestamp->mPosition[ExtendedTimestamp::Location::LOCATION_KERNEL],
209// (int)location);
Phil Burkc0959642018-04-05 18:11:01 -0700210 return AAudioConvert_androidToAAudioResult(status);
Phil Burk5204d312017-05-04 17:16:13 -0700211}
Eric Laurentfb00fc72017-05-25 18:17:12 -0700212
Phil Burk58f5ce12020-08-12 14:29:10 +0000213void AudioStreamLegacy::onAudioDeviceUpdate(audio_io_handle_t /* audioIo */,
214 audio_port_handle_t deviceId) {
Phil Burk7ba46552019-04-15 08:58:08 -0700215 // Device routing is a common source of errors and DISCONNECTS.
Phil Burk58f5ce12020-08-12 14:29:10 +0000216 // Please leave this log in place. If there is a bug then this might
217 // get called after the stream has been deleted so log before we
218 // touch the stream object.
219 ALOGD("%s(deviceId = %d)", __func__, (int)deviceId);
220 if (getDeviceId() != AAUDIO_UNSPECIFIED
221 && getDeviceId() != deviceId
222 && getState() != AAUDIO_STREAM_STATE_DISCONNECTED
223 ) {
Phil Burk2d5ba532017-09-06 14:36:11 -0700224 // Note that isDataCallbackActive() is affected by state so call it before DISCONNECTING.
225 // If we have a data callback and the stream is active, then ask the data callback
226 // to DISCONNECT and call the error callback.
227 if (isDataCallbackActive()) {
Phil Burk58f5ce12020-08-12 14:29:10 +0000228 ALOGD("%s() request DISCONNECT in data callback, device %d => %d",
229 __func__, (int) getDeviceId(), (int) deviceId);
Phil Burk2d5ba532017-09-06 14:36:11 -0700230 // If the stream is stopped before the data callback has a chance to handle the
Phil Burkdd582922020-10-15 20:29:51 +0000231 // request then the requestStop_l() and requestPause() methods will handle it after
Phil Burk2d5ba532017-09-06 14:36:11 -0700232 // the callback has stopped.
233 mRequestDisconnect.request();
234 } else {
Phil Burk58f5ce12020-08-12 14:29:10 +0000235 ALOGD("%s() DISCONNECT the stream now, device %d => %d",
236 __func__, (int) getDeviceId(), (int) deviceId);
Phil Burk2d5ba532017-09-06 14:36:11 -0700237 forceDisconnect();
Eric Laurentfb00fc72017-05-25 18:17:12 -0700238 }
239 }
240 setDeviceId(deviceId);
241}