blob: ee29177dfda73227063b2949bc7b39e7c8aaf9d2 [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()
Eric Laurentfb00fc72017-05-25 18:17:12 -070034 : AudioStream(), mDeviceCallback(new StreamDeviceCallback(this)) {
Phil Burke4d7bb42017-03-28 11:32:39 -070035}
36
37AudioStreamLegacy::~AudioStreamLegacy() {
38}
39
40// Called from AudioTrack.cpp or AudioRecord.cpp
41static void AudioStreamLegacy_callback(int event, void* userData, void *info) {
42 AudioStreamLegacy *streamLegacy = (AudioStreamLegacy *) userData;
43 streamLegacy->processCallback(event, info);
44}
45
46aaudio_legacy_callback_t AudioStreamLegacy::getLegacyCallback() {
47 return AudioStreamLegacy_callback;
48}
49
Phil Burk7328a802017-08-30 09:29:48 -070050int32_t AudioStreamLegacy::callDataCallbackFrames(uint8_t *buffer, int32_t numFrames) {
51 if (getDirection() == AAUDIO_DIRECTION_INPUT) {
52 // Increment before because we already got the data from the device.
53 incrementFramesRead(numFrames);
54 }
55
Phil Burke4d7bb42017-03-28 11:32:39 -070056 // Call using the AAudio callback interface.
57 AAudioStream_dataCallback appCallback = getDataCallbackProc();
Phil Burk7328a802017-08-30 09:29:48 -070058 aaudio_data_callback_result_t callbackResult = (*appCallback)(
Phil Burke4d7bb42017-03-28 11:32:39 -070059 (AAudioStream *) this,
60 getDataCallbackUserData(),
61 buffer,
Phil Burk7328a802017-08-30 09:29:48 -070062 numFrames);
63
64 if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE
65 && getDirection() == AAUDIO_DIRECTION_OUTPUT) {
66 // Increment after because we are going to write the data to the device.
67 incrementFramesWritten(numFrames);
68 }
69 return callbackResult;
70}
71
72// Implement FixedBlockProcessor
73int32_t AudioStreamLegacy::onProcessFixedBlock(uint8_t *buffer, int32_t numBytes) {
74 int32_t numFrames = numBytes / getBytesPerFrame();
75 return callDataCallbackFrames(buffer, numFrames);
Phil Burke4d7bb42017-03-28 11:32:39 -070076}
77
78void AudioStreamLegacy::processCallbackCommon(aaudio_callback_operation_t opcode, void *info) {
79 aaudio_data_callback_result_t callbackResult;
Eric Laurentfb00fc72017-05-25 18:17:12 -070080
81 if (!mCallbackEnabled.load()) {
82 return;
83 }
84
Phil Burke4d7bb42017-03-28 11:32:39 -070085 switch (opcode) {
86 case AAUDIO_CALLBACK_OPERATION_PROCESS_DATA: {
Eric Laurentfb00fc72017-05-25 18:17:12 -070087 if (getState() != AAUDIO_STREAM_STATE_DISCONNECTED) {
88 // Note that this code assumes an AudioTrack::Buffer is the same as
89 // AudioRecord::Buffer
90 // TODO define our own AudioBuffer and pass it from the subclasses.
91 AudioTrack::Buffer *audioBuffer = static_cast<AudioTrack::Buffer *>(info);
92 if (audioBuffer->frameCount == 0) return;
Phil Burke4d7bb42017-03-28 11:32:39 -070093
Eric Laurentfb00fc72017-05-25 18:17:12 -070094 // If the caller specified an exact size then use a block size adapter.
95 if (mBlockAdapter != nullptr) {
96 int32_t byteCount = audioBuffer->frameCount * getBytesPerFrame();
97 callbackResult = mBlockAdapter->processVariableBlock(
98 (uint8_t *) audioBuffer->raw, byteCount);
99 } else {
100 // Call using the AAudio callback interface.
Phil Burk7328a802017-08-30 09:29:48 -0700101 callbackResult = callDataCallbackFrames((uint8_t *)audioBuffer->raw,
102 audioBuffer->frameCount);
Eric Laurentfb00fc72017-05-25 18:17:12 -0700103 }
104 if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE) {
105 audioBuffer->size = audioBuffer->frameCount * getBytesPerFrame();
Eric Laurentfb00fc72017-05-25 18:17:12 -0700106 } else {
107 audioBuffer->size = 0;
108 }
Phil Burk0befec62017-07-28 15:12:13 -0700109
110 if (updateStateMachine() == AAUDIO_OK) {
111 break; // don't fall through
112 }
Phil Burke4d7bb42017-03-28 11:32:39 -0700113 }
114 }
Eric Laurentfb00fc72017-05-25 18:17:12 -0700115 /// FALL THROUGH
Phil Burke4d7bb42017-03-28 11:32:39 -0700116
Phil Burk0befec62017-07-28 15:12:13 -0700117 // Stream got rerouted so we disconnect.
Phil Burke4d7bb42017-03-28 11:32:39 -0700118 case AAUDIO_CALLBACK_OPERATION_DISCONNECTED: {
Eric Laurentfb00fc72017-05-25 18:17:12 -0700119 setState(AAUDIO_STREAM_STATE_DISCONNECTED);
120 ALOGD("processCallbackCommon() stream disconnected");
Phil Burke4d7bb42017-03-28 11:32:39 -0700121 if (getErrorCallbackProc() != nullptr) {
122 (*getErrorCallbackProc())(
123 (AAudioStream *) this,
124 getErrorCallbackUserData(),
Eric Laurentfb00fc72017-05-25 18:17:12 -0700125 AAUDIO_ERROR_DISCONNECTED
Phil Burke4d7bb42017-03-28 11:32:39 -0700126 );
127 }
128 mCallbackEnabled.store(false);
129 }
130 break;
131
132 default:
133 break;
134 }
135}
Phil Burk5204d312017-05-04 17:16:13 -0700136
137aaudio_result_t AudioStreamLegacy::getBestTimestamp(clockid_t clockId,
138 int64_t *framePosition,
139 int64_t *timeNanoseconds,
140 ExtendedTimestamp *extendedTimestamp) {
141 int timebase;
142 switch (clockId) {
143 case CLOCK_BOOTTIME:
144 timebase = ExtendedTimestamp::TIMEBASE_BOOTTIME;
145 break;
146 case CLOCK_MONOTONIC:
147 timebase = ExtendedTimestamp::TIMEBASE_MONOTONIC;
148 break;
149 default:
150 ALOGE("getTimestamp() - Unrecognized clock type %d", (int) clockId);
Phil Burk17fff382017-05-16 14:06:45 -0700151 return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
Phil Burk5204d312017-05-04 17:16:13 -0700152 break;
153 }
Phil Burk7328a802017-08-30 09:29:48 -0700154 ExtendedTimestamp::Location location = ExtendedTimestamp::Location::LOCATION_INVALID;
155 int64_t localPosition;
156 status_t status = extendedTimestamp->getBestTimestamp(&localPosition, timeNanoseconds,
157 timebase, &location);
158 // use MonotonicCounter to prevent retrograde motion.
159 mTimestampPosition.update32((int32_t)localPosition);
160 *framePosition = mTimestampPosition.get();
161
162// ALOGD("getBestTimestamp() fposition: server = %6lld, kernel = %6lld, location = %d",
163// (long long) extendedTimestamp->mPosition[ExtendedTimestamp::Location::LOCATION_SERVER],
164// (long long) extendedTimestamp->mPosition[ExtendedTimestamp::Location::LOCATION_KERNEL],
165// (int)location);
Phil Burk5204d312017-05-04 17:16:13 -0700166 return AAudioConvert_androidToAAudioResult(status);
167}
Eric Laurentfb00fc72017-05-25 18:17:12 -0700168
169void AudioStreamLegacy::onAudioDeviceUpdate(audio_port_handle_t deviceId)
170{
171 ALOGD("onAudioDeviceUpdate() deviceId %d", (int)deviceId);
172 if (getDeviceId() != AAUDIO_UNSPECIFIED && getDeviceId() != deviceId &&
173 getState() != AAUDIO_STREAM_STATE_DISCONNECTED) {
174 setState(AAUDIO_STREAM_STATE_DISCONNECTED);
175 // if we have a data callback and the stream is active, send the error callback from
176 // data callback thread when it sees the DISCONNECTED state
177 if (!isDataCallbackActive() && getErrorCallbackProc() != nullptr) {
178 (*getErrorCallbackProc())(
179 (AAudioStream *) this,
180 getErrorCallbackUserData(),
181 AAUDIO_ERROR_DISCONNECTED
182 );
183 }
184 }
185 setDeviceId(deviceId);
186}