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 <aaudio/AAudio.h> 25 26 #include "core/AudioStream.h" 27 #include "legacy/AudioStreamLegacy.h" 28 29 using namespace android; 30 using namespace aaudio; 31 32 AudioStreamLegacy::AudioStreamLegacy() 33 : AudioStream(), mDeviceCallback(new StreamDeviceCallback(this)) { 34 } 35 36 AudioStreamLegacy::~AudioStreamLegacy() { 37 } 38 39 // Called from AudioTrack.cpp or AudioRecord.cpp 40 static void AudioStreamLegacy_callback(int event, void* userData, void *info) { 41 AudioStreamLegacy *streamLegacy = (AudioStreamLegacy *) userData; 42 streamLegacy->processCallback(event, info); 43 } 44 45 aaudio_legacy_callback_t AudioStreamLegacy::getLegacyCallback() { 46 return AudioStreamLegacy_callback; 47 } 48 49 // Implement FixedBlockProcessor 50 int32_t AudioStreamLegacy::onProcessFixedBlock(uint8_t *buffer, int32_t numBytes) { 51 int32_t frameCount = numBytes / getBytesPerFrame(); 52 // Call using the AAudio callback interface. 53 AAudioStream_dataCallback appCallback = getDataCallbackProc(); 54 return (*appCallback)( 55 (AAudioStream *) this, 56 getDataCallbackUserData(), 57 buffer, 58 frameCount); 59 } 60 61 void AudioStreamLegacy::processCallbackCommon(aaudio_callback_operation_t opcode, void *info) { 62 aaudio_data_callback_result_t callbackResult; 63 64 if (!mCallbackEnabled.load()) { 65 return; 66 } 67 68 switch (opcode) { 69 case AAUDIO_CALLBACK_OPERATION_PROCESS_DATA: { 70 if (getState() != AAUDIO_STREAM_STATE_DISCONNECTED) { 71 // Note that this code assumes an AudioTrack::Buffer is the same as 72 // AudioRecord::Buffer 73 // TODO define our own AudioBuffer and pass it from the subclasses. 74 AudioTrack::Buffer *audioBuffer = static_cast<AudioTrack::Buffer *>(info); 75 if (audioBuffer->frameCount == 0) return; 76 77 // If the caller specified an exact size then use a block size adapter. 78 if (mBlockAdapter != nullptr) { 79 int32_t byteCount = audioBuffer->frameCount * getBytesPerFrame(); 80 callbackResult = mBlockAdapter->processVariableBlock( 81 (uint8_t *) audioBuffer->raw, byteCount); 82 } else { 83 // Call using the AAudio callback interface. 84 callbackResult = (*getDataCallbackProc())( 85 (AAudioStream *) this, 86 getDataCallbackUserData(), 87 audioBuffer->raw, 88 audioBuffer->frameCount 89 ); 90 } 91 if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE) { 92 audioBuffer->size = audioBuffer->frameCount * getBytesPerFrame(); 93 incrementClientFrameCounter(audioBuffer->frameCount); 94 } else { 95 audioBuffer->size = 0; 96 } 97 break; 98 } 99 } 100 /// FALL THROUGH 101 102 // Stream got rerouted so we disconnect. 103 case AAUDIO_CALLBACK_OPERATION_DISCONNECTED: { 104 setState(AAUDIO_STREAM_STATE_DISCONNECTED); 105 ALOGD("processCallbackCommon() stream disconnected"); 106 if (getErrorCallbackProc() != nullptr) { 107 (*getErrorCallbackProc())( 108 (AAudioStream *) this, 109 getErrorCallbackUserData(), 110 AAUDIO_ERROR_DISCONNECTED 111 ); 112 } 113 mCallbackEnabled.store(false); 114 } 115 break; 116 117 default: 118 break; 119 } 120 } 121 122 aaudio_result_t AudioStreamLegacy::getBestTimestamp(clockid_t clockId, 123 int64_t *framePosition, 124 int64_t *timeNanoseconds, 125 ExtendedTimestamp *extendedTimestamp) { 126 int timebase; 127 switch (clockId) { 128 case CLOCK_BOOTTIME: 129 timebase = ExtendedTimestamp::TIMEBASE_BOOTTIME; 130 break; 131 case CLOCK_MONOTONIC: 132 timebase = ExtendedTimestamp::TIMEBASE_MONOTONIC; 133 break; 134 default: 135 ALOGE("getTimestamp() - Unrecognized clock type %d", (int) clockId); 136 return AAUDIO_ERROR_ILLEGAL_ARGUMENT; 137 break; 138 } 139 status_t status = extendedTimestamp->getBestTimestamp(framePosition, timeNanoseconds, timebase); 140 return AAudioConvert_androidToAAudioResult(status); 141 } 142 143 void AudioStreamLegacy::onAudioDeviceUpdate(audio_port_handle_t deviceId) 144 { 145 ALOGD("onAudioDeviceUpdate() deviceId %d", (int)deviceId); 146 if (getDeviceId() != AAUDIO_UNSPECIFIED && getDeviceId() != deviceId && 147 getState() != AAUDIO_STREAM_STATE_DISCONNECTED) { 148 setState(AAUDIO_STREAM_STATE_DISCONNECTED); 149 // if we have a data callback and the stream is active, send the error callback from 150 // data callback thread when it sees the DISCONNECTED state 151 if (!isDataCallbackActive() && getErrorCallbackProc() != nullptr) { 152 (*getErrorCallbackProc())( 153 (AAudioStream *) this, 154 getErrorCallbackUserData(), 155 AAUDIO_ERROR_DISCONNECTED 156 ); 157 } 158 } 159 setDeviceId(deviceId); 160 } 161