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 #include <utils/String16.h> 23 #include <media/AudioTrack.h> 24 #include <media/AudioTimestamp.h> 25 #include <aaudio/AAudio.h> 26 27 #include "core/AudioStream.h" 28 #include "legacy/AudioStreamLegacy.h" 29 30 using namespace android; 31 using namespace aaudio; 32 33 AudioStreamLegacy::AudioStreamLegacy() 34 : AudioStream() 35 , mDeviceCallback(new StreamDeviceCallback(this)) { 36 } 37 38 AudioStreamLegacy::~AudioStreamLegacy() { 39 } 40 41 // Called from AudioTrack.cpp or AudioRecord.cpp 42 static void AudioStreamLegacy_callback(int event, void* userData, void *info) { 43 AudioStreamLegacy *streamLegacy = (AudioStreamLegacy *) userData; 44 streamLegacy->processCallback(event, info); 45 } 46 47 aaudio_legacy_callback_t AudioStreamLegacy::getLegacyCallback() { 48 return AudioStreamLegacy_callback; 49 } 50 51 int32_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 57 // Call using the AAudio callback interface. 58 AAudioStream_dataCallback appCallback = getDataCallbackProc(); 59 aaudio_data_callback_result_t callbackResult = (*appCallback)( 60 (AAudioStream *) this, 61 getDataCallbackUserData(), 62 buffer, 63 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 / getBytesPerFrame(); 76 return callDataCallbackFrames(buffer, numFrames); 77 } 78 79 void AudioStreamLegacy::processCallbackCommon(aaudio_callback_operation_t opcode, void *info) { 80 aaudio_data_callback_result_t callbackResult; 81 82 switch (opcode) { 83 case AAUDIO_CALLBACK_OPERATION_PROCESS_DATA: { 84 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 } 96 97 // 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. 104 callbackResult = callDataCallbackFrames((uint8_t *)audioBuffer->raw, 105 audioBuffer->frameCount); 106 } 107 if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE) { 108 audioBuffer->size = audioBuffer->frameCount * getBytesPerFrame(); 109 } else { 110 audioBuffer->size = 0; 111 } 112 113 if (updateStateMachine() != AAUDIO_OK) { 114 forceDisconnect(); 115 mCallbackEnabled.store(false); 116 } 117 } 118 } 119 break; 120 121 // Stream got rerouted so we disconnect. 122 case AAUDIO_CALLBACK_OPERATION_DISCONNECTED: 123 ALOGD("processCallbackCommon() stream disconnected"); 124 forceDisconnect(); 125 mCallbackEnabled.store(false); 126 break; 127 128 default: 129 break; 130 } 131 } 132 133 134 135 void AudioStreamLegacy::checkForDisconnectRequest() { 136 if (mRequestDisconnect.isRequested()) { 137 ALOGD("checkForDisconnectRequest() mRequestDisconnect acknowledged"); 138 forceDisconnect(); 139 mRequestDisconnect.acknowledge(); 140 mCallbackEnabled.store(false); 141 } 142 } 143 144 void 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 157 aaudio_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); 171 return AAUDIO_ERROR_ILLEGAL_ARGUMENT; 172 break; 173 } 174 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); 186 if (status == WOULD_BLOCK) { 187 return AAUDIO_ERROR_INVALID_STATE; 188 } else { 189 return AAudioConvert_androidToAAudioResult(status); 190 } 191 } 192 193 void 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) { 198 // 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(); 210 } 211 } 212 setDeviceId(deviceId); 213 } 214