blob: ee2504d3d5ff654d8af860933106de2213fb58d6 [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 Burk7328a802017-08-30 09:29:48 -070051int32_t AudioStreamLegacy::callDataCallbackFrames(uint8_t *buffer, int32_t numFrames) {
52 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.
58 AAudioStream_dataCallback appCallback = getDataCallbackProc();
Phil Burk7328a802017-08-30 09:29:48 -070059 aaudio_data_callback_result_t callbackResult = (*appCallback)(
Phil Burke4d7bb42017-03-28 11:32:39 -070060 (AAudioStream *) this,
61 getDataCallbackUserData(),
62 buffer,
Phil Burk7328a802017-08-30 09:29:48 -070063 numFrames);
64
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) {
75 int32_t numFrames = numBytes / getBytesPerFrame();
76 return 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;
Eric Laurentfb00fc72017-05-25 18:17:12 -070081
Phil Burke4d7bb42017-03-28 11:32:39 -070082 switch (opcode) {
83 case AAUDIO_CALLBACK_OPERATION_PROCESS_DATA: {
Phil Burk2d5ba532017-09-06 14:36:11 -070084 checkForDisconnectRequest();
85
86 // Note that this code assumes an AudioTrack::Buffer is the same as
87 // AudioRecord::Buffer
88 // TODO define our own AudioBuffer and pass it from the subclasses.
89 AudioTrack::Buffer *audioBuffer = static_cast<AudioTrack::Buffer *>(info);
90 if (getState() == AAUDIO_STREAM_STATE_DISCONNECTED || !mCallbackEnabled.load()) {
91 audioBuffer->size = 0; // silence the buffer
92 } else {
93 if (audioBuffer->frameCount == 0) {
94 return;
95 }
Phil Burke4d7bb42017-03-28 11:32:39 -070096
Eric Laurentfb00fc72017-05-25 18:17:12 -070097 // If the caller specified an exact size then use a block size adapter.
98 if (mBlockAdapter != nullptr) {
99 int32_t byteCount = audioBuffer->frameCount * getBytesPerFrame();
100 callbackResult = mBlockAdapter->processVariableBlock(
101 (uint8_t *) audioBuffer->raw, byteCount);
102 } else {
103 // Call using the AAudio callback interface.
Phil Burk7328a802017-08-30 09:29:48 -0700104 callbackResult = callDataCallbackFrames((uint8_t *)audioBuffer->raw,
105 audioBuffer->frameCount);
Eric Laurentfb00fc72017-05-25 18:17:12 -0700106 }
107 if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE) {
108 audioBuffer->size = audioBuffer->frameCount * getBytesPerFrame();
Eric Laurentfb00fc72017-05-25 18:17:12 -0700109 } else {
110 audioBuffer->size = 0;
111 }
Phil Burk0befec62017-07-28 15:12:13 -0700112
Phil Burk2d5ba532017-09-06 14:36:11 -0700113 if (updateStateMachine() != AAUDIO_OK) {
114 forceDisconnect();
115 mCallbackEnabled.store(false);
Phil Burk0befec62017-07-28 15:12:13 -0700116 }
Phil Burke4d7bb42017-03-28 11:32:39 -0700117 }
118 }
Phil Burk2d5ba532017-09-06 14:36:11 -0700119 break;
Phil Burke4d7bb42017-03-28 11:32:39 -0700120
Phil Burk0befec62017-07-28 15:12:13 -0700121 // Stream got rerouted so we disconnect.
Phil Burk2d5ba532017-09-06 14:36:11 -0700122 case AAUDIO_CALLBACK_OPERATION_DISCONNECTED:
Eric Laurentfb00fc72017-05-25 18:17:12 -0700123 ALOGD("processCallbackCommon() stream disconnected");
Phil Burk2d5ba532017-09-06 14:36:11 -0700124 forceDisconnect();
Phil Burke4d7bb42017-03-28 11:32:39 -0700125 mCallbackEnabled.store(false);
Phil Burke4d7bb42017-03-28 11:32:39 -0700126 break;
127
128 default:
129 break;
130 }
131}
Phil Burk5204d312017-05-04 17:16:13 -0700132
Phil Burk2d5ba532017-09-06 14:36:11 -0700133
134
135void AudioStreamLegacy::checkForDisconnectRequest() {
136 if (mRequestDisconnect.isRequested()) {
137 ALOGD("checkForDisconnectRequest() mRequestDisconnect acknowledged");
138 forceDisconnect();
139 mRequestDisconnect.acknowledge();
140 mCallbackEnabled.store(false);
141 }
142}
143
144void AudioStreamLegacy::forceDisconnect() {
145 if (getState() != AAUDIO_STREAM_STATE_DISCONNECTED) {
146 setState(AAUDIO_STREAM_STATE_DISCONNECTED);
147 if (getErrorCallbackProc() != nullptr) {
148 (*getErrorCallbackProc())(
149 (AAudioStream *) this,
150 getErrorCallbackUserData(),
151 AAUDIO_ERROR_DISCONNECTED
152 );
153 }
154 }
155}
156
Phil Burk5204d312017-05-04 17:16:13 -0700157aaudio_result_t AudioStreamLegacy::getBestTimestamp(clockid_t clockId,
158 int64_t *framePosition,
159 int64_t *timeNanoseconds,
160 ExtendedTimestamp *extendedTimestamp) {
161 int timebase;
162 switch (clockId) {
163 case CLOCK_BOOTTIME:
164 timebase = ExtendedTimestamp::TIMEBASE_BOOTTIME;
165 break;
166 case CLOCK_MONOTONIC:
167 timebase = ExtendedTimestamp::TIMEBASE_MONOTONIC;
168 break;
169 default:
170 ALOGE("getTimestamp() - Unrecognized clock type %d", (int) clockId);
Phil Burk17fff382017-05-16 14:06:45 -0700171 return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
Phil Burk5204d312017-05-04 17:16:13 -0700172 break;
173 }
Phil Burk7328a802017-08-30 09:29:48 -0700174 ExtendedTimestamp::Location location = ExtendedTimestamp::Location::LOCATION_INVALID;
175 int64_t localPosition;
176 status_t status = extendedTimestamp->getBestTimestamp(&localPosition, timeNanoseconds,
177 timebase, &location);
178 // use MonotonicCounter to prevent retrograde motion.
179 mTimestampPosition.update32((int32_t)localPosition);
180 *framePosition = mTimestampPosition.get();
181
182// ALOGD("getBestTimestamp() fposition: server = %6lld, kernel = %6lld, location = %d",
183// (long long) extendedTimestamp->mPosition[ExtendedTimestamp::Location::LOCATION_SERVER],
184// (long long) extendedTimestamp->mPosition[ExtendedTimestamp::Location::LOCATION_KERNEL],
185// (int)location);
Phil Burkc75d97f2017-09-08 15:48:36 -0700186 if (status == WOULD_BLOCK) {
187 return AAUDIO_ERROR_INVALID_STATE;
188 } else {
189 return AAudioConvert_androidToAAudioResult(status);
190 }
Phil Burk5204d312017-05-04 17:16:13 -0700191}
Eric Laurentfb00fc72017-05-25 18:17:12 -0700192
193void AudioStreamLegacy::onAudioDeviceUpdate(audio_port_handle_t deviceId)
194{
195 ALOGD("onAudioDeviceUpdate() deviceId %d", (int)deviceId);
196 if (getDeviceId() != AAUDIO_UNSPECIFIED && getDeviceId() != deviceId &&
197 getState() != AAUDIO_STREAM_STATE_DISCONNECTED) {
Phil Burk2d5ba532017-09-06 14:36:11 -0700198 // Note that isDataCallbackActive() is affected by state so call it before DISCONNECTING.
199 // If we have a data callback and the stream is active, then ask the data callback
200 // to DISCONNECT and call the error callback.
201 if (isDataCallbackActive()) {
202 ALOGD("onAudioDeviceUpdate() request DISCONNECT in data callback due to device change");
203 // If the stream is stopped before the data callback has a chance to handle the
204 // request then the requestStop() and requestPause() methods will handle it after
205 // the callback has stopped.
206 mRequestDisconnect.request();
207 } else {
208 ALOGD("onAudioDeviceUpdate() DISCONNECT the stream now");
209 forceDisconnect();
Eric Laurentfb00fc72017-05-25 18:17:12 -0700210 }
211 }
212 setDeviceId(deviceId);
213}