blob: 91d2eff7cce78a4468eac6eadcdce8988d08cd96 [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
29#include "core/AudioStream.h"
30#include "legacy/AudioStreamLegacy.h"
31
32using namespace android;
33using namespace aaudio;
34
35AudioStreamLegacy::AudioStreamLegacy()
Phil Burk2d5ba532017-09-06 14:36:11 -070036 : AudioStream()
37 , mDeviceCallback(new StreamDeviceCallback(this)) {
Phil Burke4d7bb42017-03-28 11:32:39 -070038}
39
40AudioStreamLegacy::~AudioStreamLegacy() {
41}
42
43// Called from AudioTrack.cpp or AudioRecord.cpp
44static void AudioStreamLegacy_callback(int event, void* userData, void *info) {
45 AudioStreamLegacy *streamLegacy = (AudioStreamLegacy *) userData;
46 streamLegacy->processCallback(event, info);
47}
48
49aaudio_legacy_callback_t AudioStreamLegacy::getLegacyCallback() {
50 return AudioStreamLegacy_callback;
51}
52
Phil Burk3d786cb2018-04-09 11:58:09 -070053aaudio_data_callback_result_t AudioStreamLegacy::callDataCallbackFrames(uint8_t *buffer,
54 int32_t numFrames) {
55 void *finalAudioData = buffer;
Phil Burk7328a802017-08-30 09:29:48 -070056 if (getDirection() == AAUDIO_DIRECTION_INPUT) {
57 // Increment before because we already got the data from the device.
58 incrementFramesRead(numFrames);
Phil Burk3d786cb2018-04-09 11:58:09 -070059 finalAudioData = (void *) maybeConvertDeviceData(buffer, numFrames);
Phil Burk7328a802017-08-30 09:29:48 -070060 }
61
Phil Burke4d7bb42017-03-28 11:32:39 -070062 // Call using the AAudio callback interface.
Phil Burk3d786cb2018-04-09 11:58:09 -070063 aaudio_data_callback_result_t callbackResult = maybeCallDataCallback(finalAudioData, numFrames);
Phil Burk7328a802017-08-30 09:29:48 -070064
65 if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE
66 && getDirection() == AAUDIO_DIRECTION_OUTPUT) {
67 // Increment after because we are going to write the data to the device.
68 incrementFramesWritten(numFrames);
69 }
70 return callbackResult;
71}
72
73// Implement FixedBlockProcessor
74int32_t AudioStreamLegacy::onProcessFixedBlock(uint8_t *buffer, int32_t numBytes) {
Phil Burk3d786cb2018-04-09 11:58:09 -070075 int32_t numFrames = numBytes / getBytesPerDeviceFrame();
Phil Burk134f1972017-12-08 13:06:11 -080076 return (int32_t) callDataCallbackFrames(buffer, numFrames);
Phil Burke4d7bb42017-03-28 11:32:39 -070077}
78
79void AudioStreamLegacy::processCallbackCommon(aaudio_callback_operation_t opcode, void *info) {
80 aaudio_data_callback_result_t callbackResult;
Phil Burk1e83bee2018-12-17 14:15:20 -080081 // This illegal size can be used to tell AudioRecord or AudioTrack to stop calling us.
82 // This takes advantage of them killing the stream when they see a size out of range.
83 // That is an undocumented behavior.
Phil Burk3d786cb2018-04-09 11:58:09 -070084 // TODO add to API in AudioRecord and AudioTrack
Phil Burk134f1972017-12-08 13:06:11 -080085 const size_t SIZE_STOP_CALLBACKS = SIZE_MAX;
Eric Laurentfb00fc72017-05-25 18:17:12 -070086
Phil Burke4d7bb42017-03-28 11:32:39 -070087 switch (opcode) {
88 case AAUDIO_CALLBACK_OPERATION_PROCESS_DATA: {
Phil Burk134f1972017-12-08 13:06:11 -080089 (void) checkForDisconnectRequest(true);
Phil Burk2d5ba532017-09-06 14:36:11 -070090
91 // Note that this code assumes an AudioTrack::Buffer is the same as
92 // AudioRecord::Buffer
93 // TODO define our own AudioBuffer and pass it from the subclasses.
94 AudioTrack::Buffer *audioBuffer = static_cast<AudioTrack::Buffer *>(info);
Phil Burk9e9a95b2018-01-18 12:14:15 -080095 if (getState() == AAUDIO_STREAM_STATE_DISCONNECTED) {
96 ALOGW("processCallbackCommon() data, stream disconnected");
97 audioBuffer->size = SIZE_STOP_CALLBACKS;
98 } else if (!mCallbackEnabled.load()) {
Phil Burk1e83bee2018-12-17 14:15:20 -080099 ALOGW("processCallbackCommon() no data because callback disabled");
Phil Burk134f1972017-12-08 13:06:11 -0800100 audioBuffer->size = SIZE_STOP_CALLBACKS;
Phil Burk2d5ba532017-09-06 14:36:11 -0700101 } else {
102 if (audioBuffer->frameCount == 0) {
Phil Burk9e9a95b2018-01-18 12:14:15 -0800103 ALOGW("processCallbackCommon() data, frameCount is zero");
Phil Burk2d5ba532017-09-06 14:36:11 -0700104 return;
105 }
Phil Burke4d7bb42017-03-28 11:32:39 -0700106
Eric Laurentfb00fc72017-05-25 18:17:12 -0700107 // If the caller specified an exact size then use a block size adapter.
108 if (mBlockAdapter != nullptr) {
Phil Burk3d786cb2018-04-09 11:58:09 -0700109 int32_t byteCount = audioBuffer->frameCount * getBytesPerDeviceFrame();
Eric Laurentfb00fc72017-05-25 18:17:12 -0700110 callbackResult = mBlockAdapter->processVariableBlock(
111 (uint8_t *) audioBuffer->raw, byteCount);
112 } else {
113 // Call using the AAudio callback interface.
Phil Burk7328a802017-08-30 09:29:48 -0700114 callbackResult = callDataCallbackFrames((uint8_t *)audioBuffer->raw,
115 audioBuffer->frameCount);
Eric Laurentfb00fc72017-05-25 18:17:12 -0700116 }
117 if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE) {
Phil Burk3d786cb2018-04-09 11:58:09 -0700118 audioBuffer->size = audioBuffer->frameCount * getBytesPerDeviceFrame();
Phil Burk1e83bee2018-12-17 14:15:20 -0800119 } else {
120 if (callbackResult == AAUDIO_CALLBACK_RESULT_STOP) {
121 ALOGD("%s() callback returned AAUDIO_CALLBACK_RESULT_STOP", __func__);
122 } else {
123 ALOGW("%s() callback returned invalid result = %d",
124 __func__, callbackResult);
125 }
126 audioBuffer->size = 0;
127 systemStopFromCallback();
128 // Disable the callback just in case the system keeps trying to call us.
Phil Burk134f1972017-12-08 13:06:11 -0800129 mCallbackEnabled.store(false);
Eric Laurentfb00fc72017-05-25 18:17:12 -0700130 }
Phil Burk0befec62017-07-28 15:12:13 -0700131
Phil Burk2d5ba532017-09-06 14:36:11 -0700132 if (updateStateMachine() != AAUDIO_OK) {
133 forceDisconnect();
134 mCallbackEnabled.store(false);
Phil Burk0befec62017-07-28 15:12:13 -0700135 }
Phil Burke4d7bb42017-03-28 11:32:39 -0700136 }
137 }
Phil Burk2d5ba532017-09-06 14:36:11 -0700138 break;
Phil Burke4d7bb42017-03-28 11:32:39 -0700139
Phil Burk0befec62017-07-28 15:12:13 -0700140 // Stream got rerouted so we disconnect.
Phil Burk2d5ba532017-09-06 14:36:11 -0700141 case AAUDIO_CALLBACK_OPERATION_DISCONNECTED:
Eric Laurentfb00fc72017-05-25 18:17:12 -0700142 ALOGD("processCallbackCommon() stream disconnected");
Phil Burk2d5ba532017-09-06 14:36:11 -0700143 forceDisconnect();
Phil Burke4d7bb42017-03-28 11:32:39 -0700144 mCallbackEnabled.store(false);
Phil Burke4d7bb42017-03-28 11:32:39 -0700145 break;
146
147 default:
148 break;
149 }
150}
Phil Burk5204d312017-05-04 17:16:13 -0700151
Phil Burk134f1972017-12-08 13:06:11 -0800152aaudio_result_t AudioStreamLegacy::checkForDisconnectRequest(bool errorCallbackEnabled) {
Phil Burk2d5ba532017-09-06 14:36:11 -0700153 if (mRequestDisconnect.isRequested()) {
154 ALOGD("checkForDisconnectRequest() mRequestDisconnect acknowledged");
Phil Burk134f1972017-12-08 13:06:11 -0800155 forceDisconnect(errorCallbackEnabled);
Phil Burk2d5ba532017-09-06 14:36:11 -0700156 mRequestDisconnect.acknowledge();
157 mCallbackEnabled.store(false);
Phil Burk134f1972017-12-08 13:06:11 -0800158 return AAUDIO_ERROR_DISCONNECTED;
159 } else {
160 return AAUDIO_OK;
Phil Burk2d5ba532017-09-06 14:36:11 -0700161 }
162}
163
Phil Burk134f1972017-12-08 13:06:11 -0800164void AudioStreamLegacy::forceDisconnect(bool errorCallbackEnabled) {
Phil Burk2d5ba532017-09-06 14:36:11 -0700165 if (getState() != AAUDIO_STREAM_STATE_DISCONNECTED) {
166 setState(AAUDIO_STREAM_STATE_DISCONNECTED);
Phil Burk134f1972017-12-08 13:06:11 -0800167 if (errorCallbackEnabled) {
168 maybeCallErrorCallback(AAUDIO_ERROR_DISCONNECTED);
Phil Burk2d5ba532017-09-06 14:36:11 -0700169 }
170 }
171}
172
Phil Burk5204d312017-05-04 17:16:13 -0700173aaudio_result_t AudioStreamLegacy::getBestTimestamp(clockid_t clockId,
174 int64_t *framePosition,
175 int64_t *timeNanoseconds,
176 ExtendedTimestamp *extendedTimestamp) {
177 int timebase;
178 switch (clockId) {
179 case CLOCK_BOOTTIME:
180 timebase = ExtendedTimestamp::TIMEBASE_BOOTTIME;
181 break;
182 case CLOCK_MONOTONIC:
183 timebase = ExtendedTimestamp::TIMEBASE_MONOTONIC;
184 break;
185 default:
186 ALOGE("getTimestamp() - Unrecognized clock type %d", (int) clockId);
Phil Burk17fff382017-05-16 14:06:45 -0700187 return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
Phil Burk5204d312017-05-04 17:16:13 -0700188 break;
189 }
Phil Burk7328a802017-08-30 09:29:48 -0700190 ExtendedTimestamp::Location location = ExtendedTimestamp::Location::LOCATION_INVALID;
191 int64_t localPosition;
192 status_t status = extendedTimestamp->getBestTimestamp(&localPosition, timeNanoseconds,
193 timebase, &location);
Phil Burkc0959642018-04-05 18:11:01 -0700194 if (status == OK) {
195 // use MonotonicCounter to prevent retrograde motion.
196 mTimestampPosition.update32((int32_t) localPosition);
197 *framePosition = mTimestampPosition.get();
198 }
Phil Burk7328a802017-08-30 09:29:48 -0700199
200// ALOGD("getBestTimestamp() fposition: server = %6lld, kernel = %6lld, location = %d",
201// (long long) extendedTimestamp->mPosition[ExtendedTimestamp::Location::LOCATION_SERVER],
202// (long long) extendedTimestamp->mPosition[ExtendedTimestamp::Location::LOCATION_KERNEL],
203// (int)location);
Phil Burkc0959642018-04-05 18:11:01 -0700204 return AAudioConvert_androidToAAudioResult(status);
Phil Burk5204d312017-05-04 17:16:13 -0700205}
Eric Laurentfb00fc72017-05-25 18:17:12 -0700206
207void AudioStreamLegacy::onAudioDeviceUpdate(audio_port_handle_t deviceId)
208{
Phil Burk29ccc292019-04-15 08:58:08 -0700209 // Device routing is a common source of errors and DISCONNECTS.
210 // Please leave this log in place.
211 ALOGD("%s() devId %d => %d", __func__, (int) getDeviceId(), (int)deviceId);
Eric Laurentfb00fc72017-05-25 18:17:12 -0700212 if (getDeviceId() != AAUDIO_UNSPECIFIED && getDeviceId() != deviceId &&
213 getState() != AAUDIO_STREAM_STATE_DISCONNECTED) {
Phil Burk2d5ba532017-09-06 14:36:11 -0700214 // Note that isDataCallbackActive() is affected by state so call it before DISCONNECTING.
215 // If we have a data callback and the stream is active, then ask the data callback
216 // to DISCONNECT and call the error callback.
217 if (isDataCallbackActive()) {
218 ALOGD("onAudioDeviceUpdate() request DISCONNECT in data callback due to device change");
219 // If the stream is stopped before the data callback has a chance to handle the
220 // request then the requestStop() and requestPause() methods will handle it after
221 // the callback has stopped.
222 mRequestDisconnect.request();
223 } else {
224 ALOGD("onAudioDeviceUpdate() DISCONNECT the stream now");
225 forceDisconnect();
Eric Laurentfb00fc72017-05-25 18:17:12 -0700226 }
227 }
228 setDeviceId(deviceId);
229}