blob: 3352b335039512677fa8057de31b9d5ceffdd166 [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>
22#include <utils/String16.h>
23#include <media/AudioTrack.h>
Phil Burk7328a802017-08-30 09:29:48 -070024#include <media/AudioTimestamp.h>
Phil Burke4d7bb42017-03-28 11:32:39 -070025#include <aaudio/AAudio.h>
26
27#include "core/AudioStream.h"
28#include "legacy/AudioStreamLegacy.h"
29
30using namespace android;
31using namespace aaudio;
32
33AudioStreamLegacy::AudioStreamLegacy()
Phil Burk2d5ba532017-09-06 14:36:11 -070034 : AudioStream()
35 , mDeviceCallback(new StreamDeviceCallback(this)) {
Phil Burke4d7bb42017-03-28 11:32:39 -070036}
37
38AudioStreamLegacy::~AudioStreamLegacy() {
39}
40
41// Called from AudioTrack.cpp or AudioRecord.cpp
42static void AudioStreamLegacy_callback(int event, void* userData, void *info) {
43 AudioStreamLegacy *streamLegacy = (AudioStreamLegacy *) userData;
44 streamLegacy->processCallback(event, info);
45}
46
47aaudio_legacy_callback_t AudioStreamLegacy::getLegacyCallback() {
48 return AudioStreamLegacy_callback;
49}
50
Phil Burk134f1972017-12-08 13:06:11 -080051aaudio_data_callback_result_t AudioStreamLegacy::callDataCallbackFrames(uint8_t *buffer, int32_t numFrames) {
Phil Burk7328a802017-08-30 09:29:48 -070052 if (getDirection() == AAUDIO_DIRECTION_INPUT) {
53 // Increment before because we already got the data from the device.
54 incrementFramesRead(numFrames);
55 }
56
Phil Burke4d7bb42017-03-28 11:32:39 -070057 // Call using the AAudio callback interface.
Phil Burk134f1972017-12-08 13:06:11 -080058 aaudio_data_callback_result_t callbackResult = maybeCallDataCallback(buffer, numFrames);
Phil Burk7328a802017-08-30 09:29:48 -070059
60 if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE
61 && getDirection() == AAUDIO_DIRECTION_OUTPUT) {
62 // Increment after because we are going to write the data to the device.
63 incrementFramesWritten(numFrames);
64 }
65 return callbackResult;
66}
67
68// Implement FixedBlockProcessor
69int32_t AudioStreamLegacy::onProcessFixedBlock(uint8_t *buffer, int32_t numBytes) {
70 int32_t numFrames = numBytes / getBytesPerFrame();
Phil Burk134f1972017-12-08 13:06:11 -080071 return (int32_t) callDataCallbackFrames(buffer, numFrames);
Phil Burke4d7bb42017-03-28 11:32:39 -070072}
73
74void AudioStreamLegacy::processCallbackCommon(aaudio_callback_operation_t opcode, void *info) {
75 aaudio_data_callback_result_t callbackResult;
Phil Burk134f1972017-12-08 13:06:11 -080076 // This illegal size can be used to AudioFlinger to stop calling us.
77 // This takes advantage of AudioFlinger killing the stream.
78 // TODO need API change in AudioRecord and AudioTrack
79 const size_t SIZE_STOP_CALLBACKS = SIZE_MAX;
Eric Laurentfb00fc72017-05-25 18:17:12 -070080
Phil Burke4d7bb42017-03-28 11:32:39 -070081 switch (opcode) {
82 case AAUDIO_CALLBACK_OPERATION_PROCESS_DATA: {
Phil Burk134f1972017-12-08 13:06:11 -080083 (void) checkForDisconnectRequest(true);
Phil Burk2d5ba532017-09-06 14:36:11 -070084
85 // Note that this code assumes an AudioTrack::Buffer is the same as
86 // AudioRecord::Buffer
87 // TODO define our own AudioBuffer and pass it from the subclasses.
88 AudioTrack::Buffer *audioBuffer = static_cast<AudioTrack::Buffer *>(info);
Phil Burk9e9a95b2018-01-18 12:14:15 -080089 if (getState() == AAUDIO_STREAM_STATE_DISCONNECTED) {
90 ALOGW("processCallbackCommon() data, stream disconnected");
91 audioBuffer->size = SIZE_STOP_CALLBACKS;
92 } else if (!mCallbackEnabled.load()) {
93 ALOGW("processCallbackCommon() stopping because callback disabled");
Phil Burk134f1972017-12-08 13:06:11 -080094 audioBuffer->size = SIZE_STOP_CALLBACKS;
Phil Burk2d5ba532017-09-06 14:36:11 -070095 } else {
96 if (audioBuffer->frameCount == 0) {
Phil Burk9e9a95b2018-01-18 12:14:15 -080097 ALOGW("processCallbackCommon() data, frameCount is zero");
Phil Burk2d5ba532017-09-06 14:36:11 -070098 return;
99 }
Phil Burke4d7bb42017-03-28 11:32:39 -0700100
Eric Laurentfb00fc72017-05-25 18:17:12 -0700101 // If the caller specified an exact size then use a block size adapter.
102 if (mBlockAdapter != nullptr) {
103 int32_t byteCount = audioBuffer->frameCount * getBytesPerFrame();
104 callbackResult = mBlockAdapter->processVariableBlock(
105 (uint8_t *) audioBuffer->raw, byteCount);
106 } else {
107 // Call using the AAudio callback interface.
Phil Burk7328a802017-08-30 09:29:48 -0700108 callbackResult = callDataCallbackFrames((uint8_t *)audioBuffer->raw,
109 audioBuffer->frameCount);
Eric Laurentfb00fc72017-05-25 18:17:12 -0700110 }
111 if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE) {
112 audioBuffer->size = audioBuffer->frameCount * getBytesPerFrame();
Phil Burk134f1972017-12-08 13:06:11 -0800113 } else { // STOP or invalid result
Phil Burk9e9a95b2018-01-18 12:14:15 -0800114 ALOGW("%s() callback requested stop, fake an error", __func__);
Phil Burk134f1972017-12-08 13:06:11 -0800115 audioBuffer->size = SIZE_STOP_CALLBACKS;
116 // Disable the callback just in case AudioFlinger keeps trying to call us.
117 mCallbackEnabled.store(false);
Eric Laurentfb00fc72017-05-25 18:17:12 -0700118 }
Phil Burk0befec62017-07-28 15:12:13 -0700119
Phil Burk2d5ba532017-09-06 14:36:11 -0700120 if (updateStateMachine() != AAUDIO_OK) {
121 forceDisconnect();
122 mCallbackEnabled.store(false);
Phil Burk0befec62017-07-28 15:12:13 -0700123 }
Phil Burke4d7bb42017-03-28 11:32:39 -0700124 }
125 }
Phil Burk2d5ba532017-09-06 14:36:11 -0700126 break;
Phil Burke4d7bb42017-03-28 11:32:39 -0700127
Phil Burk0befec62017-07-28 15:12:13 -0700128 // Stream got rerouted so we disconnect.
Phil Burk2d5ba532017-09-06 14:36:11 -0700129 case AAUDIO_CALLBACK_OPERATION_DISCONNECTED:
Eric Laurentfb00fc72017-05-25 18:17:12 -0700130 ALOGD("processCallbackCommon() stream disconnected");
Phil Burk2d5ba532017-09-06 14:36:11 -0700131 forceDisconnect();
Phil Burke4d7bb42017-03-28 11:32:39 -0700132 mCallbackEnabled.store(false);
Phil Burke4d7bb42017-03-28 11:32:39 -0700133 break;
134
135 default:
136 break;
137 }
138}
Phil Burk5204d312017-05-04 17:16:13 -0700139
Phil Burk134f1972017-12-08 13:06:11 -0800140aaudio_result_t AudioStreamLegacy::checkForDisconnectRequest(bool errorCallbackEnabled) {
Phil Burk2d5ba532017-09-06 14:36:11 -0700141 if (mRequestDisconnect.isRequested()) {
142 ALOGD("checkForDisconnectRequest() mRequestDisconnect acknowledged");
Phil Burk134f1972017-12-08 13:06:11 -0800143 forceDisconnect(errorCallbackEnabled);
Phil Burk2d5ba532017-09-06 14:36:11 -0700144 mRequestDisconnect.acknowledge();
145 mCallbackEnabled.store(false);
Phil Burk134f1972017-12-08 13:06:11 -0800146 return AAUDIO_ERROR_DISCONNECTED;
147 } else {
148 return AAUDIO_OK;
Phil Burk2d5ba532017-09-06 14:36:11 -0700149 }
150}
151
Phil Burk134f1972017-12-08 13:06:11 -0800152void AudioStreamLegacy::forceDisconnect(bool errorCallbackEnabled) {
Phil Burk2d5ba532017-09-06 14:36:11 -0700153 if (getState() != AAUDIO_STREAM_STATE_DISCONNECTED) {
154 setState(AAUDIO_STREAM_STATE_DISCONNECTED);
Phil Burk134f1972017-12-08 13:06:11 -0800155 if (errorCallbackEnabled) {
156 maybeCallErrorCallback(AAUDIO_ERROR_DISCONNECTED);
Phil Burk2d5ba532017-09-06 14:36:11 -0700157 }
158 }
159}
160
Phil Burk5204d312017-05-04 17:16:13 -0700161aaudio_result_t AudioStreamLegacy::getBestTimestamp(clockid_t clockId,
162 int64_t *framePosition,
163 int64_t *timeNanoseconds,
164 ExtendedTimestamp *extendedTimestamp) {
165 int timebase;
166 switch (clockId) {
167 case CLOCK_BOOTTIME:
168 timebase = ExtendedTimestamp::TIMEBASE_BOOTTIME;
169 break;
170 case CLOCK_MONOTONIC:
171 timebase = ExtendedTimestamp::TIMEBASE_MONOTONIC;
172 break;
173 default:
174 ALOGE("getTimestamp() - Unrecognized clock type %d", (int) clockId);
Phil Burk17fff382017-05-16 14:06:45 -0700175 return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
Phil Burk5204d312017-05-04 17:16:13 -0700176 break;
177 }
Phil Burk7328a802017-08-30 09:29:48 -0700178 ExtendedTimestamp::Location location = ExtendedTimestamp::Location::LOCATION_INVALID;
179 int64_t localPosition;
180 status_t status = extendedTimestamp->getBestTimestamp(&localPosition, timeNanoseconds,
181 timebase, &location);
182 // use MonotonicCounter to prevent retrograde motion.
183 mTimestampPosition.update32((int32_t)localPosition);
184 *framePosition = mTimestampPosition.get();
185
186// ALOGD("getBestTimestamp() fposition: server = %6lld, kernel = %6lld, location = %d",
187// (long long) extendedTimestamp->mPosition[ExtendedTimestamp::Location::LOCATION_SERVER],
188// (long long) extendedTimestamp->mPosition[ExtendedTimestamp::Location::LOCATION_KERNEL],
189// (int)location);
Phil Burkc75d97f2017-09-08 15:48:36 -0700190 if (status == WOULD_BLOCK) {
191 return AAUDIO_ERROR_INVALID_STATE;
192 } else {
193 return AAudioConvert_androidToAAudioResult(status);
194 }
Phil Burk5204d312017-05-04 17:16:13 -0700195}
Eric Laurentfb00fc72017-05-25 18:17:12 -0700196
197void AudioStreamLegacy::onAudioDeviceUpdate(audio_port_handle_t deviceId)
198{
199 ALOGD("onAudioDeviceUpdate() deviceId %d", (int)deviceId);
200 if (getDeviceId() != AAUDIO_UNSPECIFIED && getDeviceId() != deviceId &&
201 getState() != AAUDIO_STREAM_STATE_DISCONNECTED) {
Phil Burk2d5ba532017-09-06 14:36:11 -0700202 // Note that isDataCallbackActive() is affected by state so call it before DISCONNECTING.
203 // If we have a data callback and the stream is active, then ask the data callback
204 // to DISCONNECT and call the error callback.
205 if (isDataCallbackActive()) {
206 ALOGD("onAudioDeviceUpdate() request DISCONNECT in data callback due to device change");
207 // If the stream is stopped before the data callback has a chance to handle the
208 // request then the requestStop() and requestPause() methods will handle it after
209 // the callback has stopped.
210 mRequestDisconnect.request();
211 } else {
212 ALOGD("onAudioDeviceUpdate() DISCONNECT the stream now");
213 forceDisconnect();
Eric Laurentfb00fc72017-05-25 18:17:12 -0700214 }
215 }
216 setDeviceId(deviceId);
217}