1 /* 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 23 #include <aaudio/AAudio.h> 24 #include <audio_utils/primitives.h> 25 #include <media/AudioTrack.h> 26 #include <media/AudioTimestamp.h> 27 #include <utils/String16.h> 28 29 #include "core/AudioStream.h" 30 #include "legacy/AudioStreamLegacy.h" 31 32 using namespace android; 33 using namespace aaudio; 34 35 AudioStreamLegacy::AudioStreamLegacy() 36 : AudioStream() 37 , mDeviceCallback(new StreamDeviceCallback(this)) { 38 } 39 40 AudioStreamLegacy::~AudioStreamLegacy() { 41 } 42 43 // Called from AudioTrack.cpp or AudioRecord.cpp 44 static void AudioStreamLegacy_callback(int event, void* userData, void *info) { 45 AudioStreamLegacy *streamLegacy = (AudioStreamLegacy *) userData; 46 streamLegacy->processCallback(event, info); 47 } 48 49 aaudio_legacy_callback_t AudioStreamLegacy::getLegacyCallback() { 50 return AudioStreamLegacy_callback; 51 } 52 53 aaudio_data_callback_result_t AudioStreamLegacy::callDataCallbackFrames(uint8_t *buffer, 54 int32_t numFrames) { 55 void *finalAudioData = buffer; 56 if (getDirection() == AAUDIO_DIRECTION_INPUT) { 57 // Increment before because we already got the data from the device. 58 incrementFramesRead(numFrames); 59 finalAudioData = (void *) maybeConvertDeviceData(buffer, numFrames); 60 } 61 62 // Call using the AAudio callback interface. 63 aaudio_data_callback_result_t callbackResult = maybeCallDataCallback(finalAudioData, 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 74 int32_t AudioStreamLegacy::onProcessFixedBlock(uint8_t *buffer, int32_t numBytes) { 75 int32_t numFrames = numBytes / getBytesPerDeviceFrame(); 76 return (int32_t) callDataCallbackFrames(buffer, numFrames); 77 } 78 79 void AudioStreamLegacy::processCallbackCommon(aaudio_callback_operation_t opcode, void *info) { 80 aaudio_data_callback_result_t callbackResult; 81 // This illegal size can be used to tell AudioFlinger to stop calling us. 82 // This takes advantage of AudioFlinger killing the stream. 83 // TODO add to API in AudioRecord and AudioTrack 84 const size_t SIZE_STOP_CALLBACKS = SIZE_MAX; 85 86 switch (opcode) { 87 case AAUDIO_CALLBACK_OPERATION_PROCESS_DATA: { 88 (void) checkForDisconnectRequest(true); 89 90 // Note that this code assumes an AudioTrack::Buffer is the same as 91 // AudioRecord::Buffer 92 // TODO define our own AudioBuffer and pass it from the subclasses. 93 AudioTrack::Buffer *audioBuffer = static_cast<AudioTrack::Buffer *>(info); 94 if (getState() == AAUDIO_STREAM_STATE_DISCONNECTED) { 95 ALOGW("processCallbackCommon() data, stream disconnected"); 96 audioBuffer->size = SIZE_STOP_CALLBACKS; 97 } else if (!mCallbackEnabled.load()) { 98 ALOGW("processCallbackCommon() stopping because callback disabled"); 99 audioBuffer->size = SIZE_STOP_CALLBACKS; 100 } else { 101 if (audioBuffer->frameCount == 0) { 102 ALOGW("processCallbackCommon() data, frameCount is zero"); 103 return; 104 } 105 106 // If the caller specified an exact size then use a block size adapter. 107 if (mBlockAdapter != nullptr) { 108 int32_t byteCount = audioBuffer->frameCount * getBytesPerDeviceFrame(); 109 callbackResult = mBlockAdapter->processVariableBlock( 110 (uint8_t *) audioBuffer->raw, byteCount); 111 } else { 112 // Call using the AAudio callback interface. 113 callbackResult = callDataCallbackFrames((uint8_t *)audioBuffer->raw, 114 audioBuffer->frameCount); 115 } 116 if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE) { 117 audioBuffer->size = audioBuffer->frameCount * getBytesPerDeviceFrame(); 118 } else { // STOP or invalid result 119 ALOGW("%s() callback requested stop, fake an error", __func__); 120 audioBuffer->size = SIZE_STOP_CALLBACKS; 121 // Disable the callback just in case AudioFlinger keeps trying to call us. 122 mCallbackEnabled.store(false); 123 } 124 125 if (updateStateMachine() != AAUDIO_OK) { 126 forceDisconnect(); 127 mCallbackEnabled.store(false); 128 } 129 } 130 } 131 break; 132 133 // Stream got rerouted so we disconnect. 134 case AAUDIO_CALLBACK_OPERATION_DISCONNECTED: 135 ALOGD("processCallbackCommon() stream disconnected"); 136 forceDisconnect(); 137 mCallbackEnabled.store(false); 138 break; 139 140 default: 141 break; 142 } 143 } 144 145 aaudio_result_t AudioStreamLegacy::checkForDisconnectRequest(bool errorCallbackEnabled) { 146 if (mRequestDisconnect.isRequested()) { 147 ALOGD("checkForDisconnectRequest() mRequestDisconnect acknowledged"); 148 forceDisconnect(errorCallbackEnabled); 149 mRequestDisconnect.acknowledge(); 150 mCallbackEnabled.store(false); 151 return AAUDIO_ERROR_DISCONNECTED; 152 } else { 153 return AAUDIO_OK; 154 } 155 } 156 157 void AudioStreamLegacy::forceDisconnect(bool errorCallbackEnabled) { 158 if (getState() != AAUDIO_STREAM_STATE_DISCONNECTED) { 159 setState(AAUDIO_STREAM_STATE_DISCONNECTED); 160 if (errorCallbackEnabled) { 161 maybeCallErrorCallback(AAUDIO_ERROR_DISCONNECTED); 162 } 163 } 164 } 165 166 aaudio_result_t AudioStreamLegacy::getBestTimestamp(clockid_t clockId, 167 int64_t *framePosition, 168 int64_t *timeNanoseconds, 169 ExtendedTimestamp *extendedTimestamp) { 170 int timebase; 171 switch (clockId) { 172 case CLOCK_BOOTTIME: 173 timebase = ExtendedTimestamp::TIMEBASE_BOOTTIME; 174 break; 175 case CLOCK_MONOTONIC: 176 timebase = ExtendedTimestamp::TIMEBASE_MONOTONIC; 177 break; 178 default: 179 ALOGE("getTimestamp() - Unrecognized clock type %d", (int) clockId); 180 return AAUDIO_ERROR_ILLEGAL_ARGUMENT; 181 break; 182 } 183 ExtendedTimestamp::Location location = ExtendedTimestamp::Location::LOCATION_INVALID; 184 int64_t localPosition; 185 status_t status = extendedTimestamp->getBestTimestamp(&localPosition, timeNanoseconds, 186 timebase, &location); 187 if (status == OK) { 188 // use MonotonicCounter to prevent retrograde motion. 189 mTimestampPosition.update32((int32_t) localPosition); 190 *framePosition = mTimestampPosition.get(); 191 } 192 193 // ALOGD("getBestTimestamp() fposition: server = %6lld, kernel = %6lld, location = %d", 194 // (long long) extendedTimestamp->mPosition[ExtendedTimestamp::Location::LOCATION_SERVER], 195 // (long long) extendedTimestamp->mPosition[ExtendedTimestamp::Location::LOCATION_KERNEL], 196 // (int)location); 197 return AAudioConvert_androidToAAudioResult(status); 198 } 199 200 void AudioStreamLegacy::onAudioDeviceUpdate(audio_port_handle_t deviceId) 201 { 202 ALOGD("onAudioDeviceUpdate() deviceId %d", (int)deviceId); 203 if (getDeviceId() != AAUDIO_UNSPECIFIED && getDeviceId() != deviceId && 204 getState() != AAUDIO_STREAM_STATE_DISCONNECTED) { 205 // Note that isDataCallbackActive() is affected by state so call it before DISCONNECTING. 206 // If we have a data callback and the stream is active, then ask the data callback 207 // to DISCONNECT and call the error callback. 208 if (isDataCallbackActive()) { 209 ALOGD("onAudioDeviceUpdate() request DISCONNECT in data callback due to device change"); 210 // If the stream is stopped before the data callback has a chance to handle the 211 // request then the requestStop() and requestPause() methods will handle it after 212 // the callback has stopped. 213 mRequestDisconnect.request(); 214 } else { 215 ALOGD("onAudioDeviceUpdate() DISCONNECT the stream now"); 216 forceDisconnect(); 217 } 218 } 219 setDeviceId(deviceId); 220 } 221