blob: c5dfb7c7a93ce0a070b2c6ff117ba284e09e63d2 [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);
89 if (getState() == AAUDIO_STREAM_STATE_DISCONNECTED || !mCallbackEnabled.load()) {
Phil Burk134f1972017-12-08 13:06:11 -080090 audioBuffer->size = SIZE_STOP_CALLBACKS;
Phil Burk2d5ba532017-09-06 14:36:11 -070091 } else {
92 if (audioBuffer->frameCount == 0) {
93 return;
94 }
Phil Burke4d7bb42017-03-28 11:32:39 -070095
Eric Laurentfb00fc72017-05-25 18:17:12 -070096 // If the caller specified an exact size then use a block size adapter.
97 if (mBlockAdapter != nullptr) {
98 int32_t byteCount = audioBuffer->frameCount * getBytesPerFrame();
99 callbackResult = mBlockAdapter->processVariableBlock(
100 (uint8_t *) audioBuffer->raw, byteCount);
101 } else {
102 // Call using the AAudio callback interface.
Phil Burk7328a802017-08-30 09:29:48 -0700103 callbackResult = callDataCallbackFrames((uint8_t *)audioBuffer->raw,
104 audioBuffer->frameCount);
Eric Laurentfb00fc72017-05-25 18:17:12 -0700105 }
106 if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE) {
107 audioBuffer->size = audioBuffer->frameCount * getBytesPerFrame();
Phil Burk134f1972017-12-08 13:06:11 -0800108 } else { // STOP or invalid result
109 ALOGW("%s() stop stream by faking an error", __func__);
110 audioBuffer->size = SIZE_STOP_CALLBACKS;
111 // Disable the callback just in case AudioFlinger keeps trying to call us.
112 mCallbackEnabled.store(false);
Eric Laurentfb00fc72017-05-25 18:17:12 -0700113 }
Phil Burk0befec62017-07-28 15:12:13 -0700114
Phil Burk2d5ba532017-09-06 14:36:11 -0700115 if (updateStateMachine() != AAUDIO_OK) {
116 forceDisconnect();
117 mCallbackEnabled.store(false);
Phil Burk0befec62017-07-28 15:12:13 -0700118 }
Phil Burke4d7bb42017-03-28 11:32:39 -0700119 }
120 }
Phil Burk2d5ba532017-09-06 14:36:11 -0700121 break;
Phil Burke4d7bb42017-03-28 11:32:39 -0700122
Phil Burk0befec62017-07-28 15:12:13 -0700123 // Stream got rerouted so we disconnect.
Phil Burk2d5ba532017-09-06 14:36:11 -0700124 case AAUDIO_CALLBACK_OPERATION_DISCONNECTED:
Eric Laurentfb00fc72017-05-25 18:17:12 -0700125 ALOGD("processCallbackCommon() stream disconnected");
Phil Burk2d5ba532017-09-06 14:36:11 -0700126 forceDisconnect();
Phil Burke4d7bb42017-03-28 11:32:39 -0700127 mCallbackEnabled.store(false);
Phil Burke4d7bb42017-03-28 11:32:39 -0700128 break;
129
130 default:
131 break;
132 }
133}
Phil Burk5204d312017-05-04 17:16:13 -0700134
Phil Burk134f1972017-12-08 13:06:11 -0800135aaudio_result_t AudioStreamLegacy::checkForDisconnectRequest(bool errorCallbackEnabled) {
Phil Burk2d5ba532017-09-06 14:36:11 -0700136 if (mRequestDisconnect.isRequested()) {
137 ALOGD("checkForDisconnectRequest() mRequestDisconnect acknowledged");
Phil Burk134f1972017-12-08 13:06:11 -0800138 forceDisconnect(errorCallbackEnabled);
Phil Burk2d5ba532017-09-06 14:36:11 -0700139 mRequestDisconnect.acknowledge();
140 mCallbackEnabled.store(false);
Phil Burk134f1972017-12-08 13:06:11 -0800141 return AAUDIO_ERROR_DISCONNECTED;
142 } else {
143 return AAUDIO_OK;
Phil Burk2d5ba532017-09-06 14:36:11 -0700144 }
145}
146
Phil Burk134f1972017-12-08 13:06:11 -0800147void AudioStreamLegacy::forceDisconnect(bool errorCallbackEnabled) {
Phil Burk2d5ba532017-09-06 14:36:11 -0700148 if (getState() != AAUDIO_STREAM_STATE_DISCONNECTED) {
149 setState(AAUDIO_STREAM_STATE_DISCONNECTED);
Phil Burk134f1972017-12-08 13:06:11 -0800150 if (errorCallbackEnabled) {
151 maybeCallErrorCallback(AAUDIO_ERROR_DISCONNECTED);
Phil Burk2d5ba532017-09-06 14:36:11 -0700152 }
153 }
154}
155
Phil Burk5204d312017-05-04 17:16:13 -0700156aaudio_result_t AudioStreamLegacy::getBestTimestamp(clockid_t clockId,
157 int64_t *framePosition,
158 int64_t *timeNanoseconds,
159 ExtendedTimestamp *extendedTimestamp) {
160 int timebase;
161 switch (clockId) {
162 case CLOCK_BOOTTIME:
163 timebase = ExtendedTimestamp::TIMEBASE_BOOTTIME;
164 break;
165 case CLOCK_MONOTONIC:
166 timebase = ExtendedTimestamp::TIMEBASE_MONOTONIC;
167 break;
168 default:
169 ALOGE("getTimestamp() - Unrecognized clock type %d", (int) clockId);
Phil Burk17fff382017-05-16 14:06:45 -0700170 return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
Phil Burk5204d312017-05-04 17:16:13 -0700171 break;
172 }
Phil Burk7328a802017-08-30 09:29:48 -0700173 ExtendedTimestamp::Location location = ExtendedTimestamp::Location::LOCATION_INVALID;
174 int64_t localPosition;
175 status_t status = extendedTimestamp->getBestTimestamp(&localPosition, timeNanoseconds,
176 timebase, &location);
177 // use MonotonicCounter to prevent retrograde motion.
178 mTimestampPosition.update32((int32_t)localPosition);
179 *framePosition = mTimestampPosition.get();
180
181// ALOGD("getBestTimestamp() fposition: server = %6lld, kernel = %6lld, location = %d",
182// (long long) extendedTimestamp->mPosition[ExtendedTimestamp::Location::LOCATION_SERVER],
183// (long long) extendedTimestamp->mPosition[ExtendedTimestamp::Location::LOCATION_KERNEL],
184// (int)location);
Phil Burkc75d97f2017-09-08 15:48:36 -0700185 if (status == WOULD_BLOCK) {
186 return AAUDIO_ERROR_INVALID_STATE;
187 } else {
188 return AAudioConvert_androidToAAudioResult(status);
189 }
Phil Burk5204d312017-05-04 17:16:13 -0700190}
Eric Laurentfb00fc72017-05-25 18:17:12 -0700191
192void AudioStreamLegacy::onAudioDeviceUpdate(audio_port_handle_t deviceId)
193{
194 ALOGD("onAudioDeviceUpdate() deviceId %d", (int)deviceId);
195 if (getDeviceId() != AAUDIO_UNSPECIFIED && getDeviceId() != deviceId &&
196 getState() != AAUDIO_STREAM_STATE_DISCONNECTED) {
Phil Burk2d5ba532017-09-06 14:36:11 -0700197 // Note that isDataCallbackActive() is affected by state so call it before DISCONNECTING.
198 // If we have a data callback and the stream is active, then ask the data callback
199 // to DISCONNECT and call the error callback.
200 if (isDataCallbackActive()) {
201 ALOGD("onAudioDeviceUpdate() request DISCONNECT in data callback due to device change");
202 // If the stream is stopped before the data callback has a chance to handle the
203 // request then the requestStop() and requestPause() methods will handle it after
204 // the callback has stopped.
205 mRequestDisconnect.request();
206 } else {
207 ALOGD("onAudioDeviceUpdate() DISCONNECT the stream now");
208 forceDisconnect();
Eric Laurentfb00fc72017-05-25 18:17:12 -0700209 }
210 }
211 setDeviceId(deviceId);
212}