blob: c0628825243bb208f26a189571714335993f5b90 [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 Burk2d5ba532017-09-06 14:36:11 -070037 : AudioStream()
38 , mDeviceCallback(new StreamDeviceCallback(this)) {
Phil Burke4d7bb42017-03-28 11:32:39 -070039}
40
41AudioStreamLegacy::~AudioStreamLegacy() {
42}
43
44// Called from AudioTrack.cpp or AudioRecord.cpp
45static void AudioStreamLegacy_callback(int event, void* userData, void *info) {
46 AudioStreamLegacy *streamLegacy = (AudioStreamLegacy *) userData;
47 streamLegacy->processCallback(event, info);
48}
49
50aaudio_legacy_callback_t AudioStreamLegacy::getLegacyCallback() {
51 return AudioStreamLegacy_callback;
52}
53
Phil Burk3d786cb2018-04-09 11:58:09 -070054aaudio_data_callback_result_t AudioStreamLegacy::callDataCallbackFrames(uint8_t *buffer,
55 int32_t numFrames) {
56 void *finalAudioData = buffer;
Phil Burk7328a802017-08-30 09:29:48 -070057 if (getDirection() == AAUDIO_DIRECTION_INPUT) {
58 // Increment before because we already got the data from the device.
59 incrementFramesRead(numFrames);
Phil Burk3d786cb2018-04-09 11:58:09 -070060 finalAudioData = (void *) maybeConvertDeviceData(buffer, numFrames);
Phil Burk7328a802017-08-30 09:29:48 -070061 }
62
Phil Burke4d7bb42017-03-28 11:32:39 -070063 // Call using the AAudio callback interface.
Phil Burk3d786cb2018-04-09 11:58:09 -070064 aaudio_data_callback_result_t callbackResult = maybeCallDataCallback(finalAudioData, numFrames);
Phil Burk7328a802017-08-30 09:29:48 -070065
66 if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE
67 && getDirection() == AAUDIO_DIRECTION_OUTPUT) {
68 // Increment after because we are going to write the data to the device.
69 incrementFramesWritten(numFrames);
70 }
71 return callbackResult;
72}
73
74// Implement FixedBlockProcessor
75int32_t AudioStreamLegacy::onProcessFixedBlock(uint8_t *buffer, int32_t numBytes) {
Phil Burk4b867492020-02-12 10:58:05 -080076 int32_t numFrames = numBytes / mBlockAdapterBytesPerFrame;
Phil Burk134f1972017-12-08 13:06:11 -080077 return (int32_t) callDataCallbackFrames(buffer, numFrames);
Phil Burke4d7bb42017-03-28 11:32:39 -070078}
79
80void AudioStreamLegacy::processCallbackCommon(aaudio_callback_operation_t opcode, void *info) {
81 aaudio_data_callback_result_t callbackResult;
Phil Burk1e83bee2018-12-17 14:15:20 -080082 // This illegal size can be used to tell AudioRecord or AudioTrack to stop calling us.
83 // This takes advantage of them killing the stream when they see a size out of range.
84 // That is an undocumented behavior.
Phil Burk3d786cb2018-04-09 11:58:09 -070085 // TODO add to API in AudioRecord and AudioTrack
Phil Burk134f1972017-12-08 13:06:11 -080086 const size_t SIZE_STOP_CALLBACKS = SIZE_MAX;
Eric Laurentfb00fc72017-05-25 18:17:12 -070087
Phil Burke4d7bb42017-03-28 11:32:39 -070088 switch (opcode) {
89 case AAUDIO_CALLBACK_OPERATION_PROCESS_DATA: {
Phil Burk134f1972017-12-08 13:06:11 -080090 (void) checkForDisconnectRequest(true);
Phil Burk2d5ba532017-09-06 14:36:11 -070091
92 // Note that this code assumes an AudioTrack::Buffer is the same as
93 // AudioRecord::Buffer
94 // TODO define our own AudioBuffer and pass it from the subclasses.
95 AudioTrack::Buffer *audioBuffer = static_cast<AudioTrack::Buffer *>(info);
Phil Burk9e9a95b2018-01-18 12:14:15 -080096 if (getState() == AAUDIO_STREAM_STATE_DISCONNECTED) {
97 ALOGW("processCallbackCommon() data, stream disconnected");
98 audioBuffer->size = SIZE_STOP_CALLBACKS;
99 } else if (!mCallbackEnabled.load()) {
Phil Burk1e83bee2018-12-17 14:15:20 -0800100 ALOGW("processCallbackCommon() no data because callback disabled");
Phil Burk134f1972017-12-08 13:06:11 -0800101 audioBuffer->size = SIZE_STOP_CALLBACKS;
Phil Burk2d5ba532017-09-06 14:36:11 -0700102 } else {
103 if (audioBuffer->frameCount == 0) {
Phil Burk9e9a95b2018-01-18 12:14:15 -0800104 ALOGW("processCallbackCommon() data, frameCount is zero");
Phil Burk2d5ba532017-09-06 14:36:11 -0700105 return;
106 }
Phil Burke4d7bb42017-03-28 11:32:39 -0700107
Eric Laurentfb00fc72017-05-25 18:17:12 -0700108 // If the caller specified an exact size then use a block size adapter.
109 if (mBlockAdapter != nullptr) {
Phil Burk3d786cb2018-04-09 11:58:09 -0700110 int32_t byteCount = audioBuffer->frameCount * getBytesPerDeviceFrame();
Eric Laurentfb00fc72017-05-25 18:17:12 -0700111 callbackResult = mBlockAdapter->processVariableBlock(
112 (uint8_t *) audioBuffer->raw, byteCount);
113 } else {
114 // Call using the AAudio callback interface.
Phil Burk7328a802017-08-30 09:29:48 -0700115 callbackResult = callDataCallbackFrames((uint8_t *)audioBuffer->raw,
116 audioBuffer->frameCount);
Eric Laurentfb00fc72017-05-25 18:17:12 -0700117 }
118 if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE) {
Phil Burk3d786cb2018-04-09 11:58:09 -0700119 audioBuffer->size = audioBuffer->frameCount * getBytesPerDeviceFrame();
Phil Burk1e83bee2018-12-17 14:15:20 -0800120 } else {
121 if (callbackResult == AAUDIO_CALLBACK_RESULT_STOP) {
122 ALOGD("%s() callback returned AAUDIO_CALLBACK_RESULT_STOP", __func__);
123 } else {
124 ALOGW("%s() callback returned invalid result = %d",
125 __func__, callbackResult);
126 }
127 audioBuffer->size = 0;
128 systemStopFromCallback();
129 // Disable the callback just in case the system keeps trying to call us.
Phil Burk134f1972017-12-08 13:06:11 -0800130 mCallbackEnabled.store(false);
Eric Laurentfb00fc72017-05-25 18:17:12 -0700131 }
Phil Burk0befec62017-07-28 15:12:13 -0700132
Phil Burk2d5ba532017-09-06 14:36:11 -0700133 if (updateStateMachine() != AAUDIO_OK) {
134 forceDisconnect();
135 mCallbackEnabled.store(false);
Phil Burk0befec62017-07-28 15:12:13 -0700136 }
Phil Burke4d7bb42017-03-28 11:32:39 -0700137 }
138 }
Phil Burk2d5ba532017-09-06 14:36:11 -0700139 break;
Phil Burke4d7bb42017-03-28 11:32:39 -0700140
Phil Burk0befec62017-07-28 15:12:13 -0700141 // Stream got rerouted so we disconnect.
Phil Burk2d5ba532017-09-06 14:36:11 -0700142 case AAUDIO_CALLBACK_OPERATION_DISCONNECTED:
Eric Laurentfb00fc72017-05-25 18:17:12 -0700143 ALOGD("processCallbackCommon() stream disconnected");
Phil Burk2d5ba532017-09-06 14:36:11 -0700144 forceDisconnect();
Phil Burke4d7bb42017-03-28 11:32:39 -0700145 mCallbackEnabled.store(false);
Phil Burke4d7bb42017-03-28 11:32:39 -0700146 break;
147
148 default:
149 break;
150 }
151}
Phil Burk5204d312017-05-04 17:16:13 -0700152
Phil Burk134f1972017-12-08 13:06:11 -0800153aaudio_result_t AudioStreamLegacy::checkForDisconnectRequest(bool errorCallbackEnabled) {
Phil Burk2d5ba532017-09-06 14:36:11 -0700154 if (mRequestDisconnect.isRequested()) {
155 ALOGD("checkForDisconnectRequest() mRequestDisconnect acknowledged");
Phil Burk134f1972017-12-08 13:06:11 -0800156 forceDisconnect(errorCallbackEnabled);
Phil Burk2d5ba532017-09-06 14:36:11 -0700157 mRequestDisconnect.acknowledge();
158 mCallbackEnabled.store(false);
Phil Burk134f1972017-12-08 13:06:11 -0800159 return AAUDIO_ERROR_DISCONNECTED;
160 } else {
161 return AAUDIO_OK;
Phil Burk2d5ba532017-09-06 14:36:11 -0700162 }
163}
164
Phil Burk134f1972017-12-08 13:06:11 -0800165void AudioStreamLegacy::forceDisconnect(bool errorCallbackEnabled) {
Phil Burk2d5ba532017-09-06 14:36:11 -0700166 if (getState() != AAUDIO_STREAM_STATE_DISCONNECTED) {
167 setState(AAUDIO_STREAM_STATE_DISCONNECTED);
Phil Burk134f1972017-12-08 13:06:11 -0800168 if (errorCallbackEnabled) {
169 maybeCallErrorCallback(AAUDIO_ERROR_DISCONNECTED);
Phil Burk2d5ba532017-09-06 14:36:11 -0700170 }
171 }
172}
173
Phil Burk5204d312017-05-04 17:16:13 -0700174aaudio_result_t AudioStreamLegacy::getBestTimestamp(clockid_t clockId,
175 int64_t *framePosition,
176 int64_t *timeNanoseconds,
177 ExtendedTimestamp *extendedTimestamp) {
178 int timebase;
179 switch (clockId) {
180 case CLOCK_BOOTTIME:
181 timebase = ExtendedTimestamp::TIMEBASE_BOOTTIME;
182 break;
183 case CLOCK_MONOTONIC:
184 timebase = ExtendedTimestamp::TIMEBASE_MONOTONIC;
185 break;
186 default:
187 ALOGE("getTimestamp() - Unrecognized clock type %d", (int) clockId);
Phil Burk17fff382017-05-16 14:06:45 -0700188 return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
Phil Burk5204d312017-05-04 17:16:13 -0700189 break;
190 }
Phil Burk7328a802017-08-30 09:29:48 -0700191 ExtendedTimestamp::Location location = ExtendedTimestamp::Location::LOCATION_INVALID;
192 int64_t localPosition;
193 status_t status = extendedTimestamp->getBestTimestamp(&localPosition, timeNanoseconds,
194 timebase, &location);
Phil Burkc0959642018-04-05 18:11:01 -0700195 if (status == OK) {
196 // use MonotonicCounter to prevent retrograde motion.
197 mTimestampPosition.update32((int32_t) localPosition);
198 *framePosition = mTimestampPosition.get();
199 }
Phil Burk7328a802017-08-30 09:29:48 -0700200
201// ALOGD("getBestTimestamp() fposition: server = %6lld, kernel = %6lld, location = %d",
202// (long long) extendedTimestamp->mPosition[ExtendedTimestamp::Location::LOCATION_SERVER],
203// (long long) extendedTimestamp->mPosition[ExtendedTimestamp::Location::LOCATION_KERNEL],
204// (int)location);
Phil Burkc0959642018-04-05 18:11:01 -0700205 return AAudioConvert_androidToAAudioResult(status);
Phil Burk5204d312017-05-04 17:16:13 -0700206}
Eric Laurentfb00fc72017-05-25 18:17:12 -0700207
208void AudioStreamLegacy::onAudioDeviceUpdate(audio_port_handle_t deviceId)
209{
Phil Burk7ba46552019-04-15 08:58:08 -0700210 // Device routing is a common source of errors and DISCONNECTS.
211 // Please leave this log in place.
212 ALOGD("%s() devId %d => %d", __func__, (int) getDeviceId(), (int)deviceId);
Eric Laurentfb00fc72017-05-25 18:17:12 -0700213 if (getDeviceId() != AAUDIO_UNSPECIFIED && getDeviceId() != deviceId &&
214 getState() != AAUDIO_STREAM_STATE_DISCONNECTED) {
Phil Burk2d5ba532017-09-06 14:36:11 -0700215 // Note that isDataCallbackActive() is affected by state so call it before DISCONNECTING.
216 // If we have a data callback and the stream is active, then ask the data callback
217 // to DISCONNECT and call the error callback.
218 if (isDataCallbackActive()) {
219 ALOGD("onAudioDeviceUpdate() request DISCONNECT in data callback due to device change");
220 // If the stream is stopped before the data callback has a chance to handle the
221 // request then the requestStop() and requestPause() methods will handle it after
222 // the callback has stopped.
223 mRequestDisconnect.request();
224 } else {
225 ALOGD("onAudioDeviceUpdate() DISCONNECT the stream now");
226 forceDisconnect();
Eric Laurentfb00fc72017-05-25 18:17:12 -0700227 }
228 }
229 setDeviceId(deviceId);
230}