1/* 2 * Copyright (C) 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 "AAudioServiceEndpointPlay" 18//#define LOG_NDEBUG 0 19#include <utils/Log.h> 20 21#include <assert.h> 22#include <map> 23#include <mutex> 24#include <utils/Singleton.h> 25 26#include "AAudioEndpointManager.h" 27#include "AAudioServiceEndpoint.h" 28#include <algorithm> 29#include <mutex> 30#include <vector> 31 32#include "core/AudioStreamBuilder.h" 33#include "AAudioServiceEndpoint.h" 34#include "AAudioServiceStreamShared.h" 35#include "AAudioServiceEndpointPlay.h" 36#include "AAudioServiceEndpointShared.h" 37#include "AAudioServiceStreamBase.h" 38 39using namespace android; // TODO just import names needed 40using namespace aaudio; // TODO just import names needed 41 42#define BURSTS_PER_BUFFER_DEFAULT 2 43 44AAudioServiceEndpointPlay::AAudioServiceEndpointPlay(AAudioService &audioService) 45 : mStreamInternalPlay(audioService, true) { 46 ALOGD("%s(%p) created", __func__, this); 47 mStreamInternal = &mStreamInternalPlay; 48} 49 50AAudioServiceEndpointPlay::~AAudioServiceEndpointPlay() { 51 ALOGD("%s(%p) destroyed", __func__, this); 52} 53 54aaudio_result_t AAudioServiceEndpointPlay::open(const aaudio::AAudioStreamRequest &request) { 55 aaudio_result_t result = AAudioServiceEndpointShared::open(request); 56 if (result == AAUDIO_OK) { 57 mMixer.allocate(getStreamInternal()->getSamplesPerFrame(), 58 getStreamInternal()->getFramesPerBurst()); 59 60 int32_t burstsPerBuffer = AAudioProperty_getMixerBursts(); 61 if (burstsPerBuffer == 0) { 62 mLatencyTuningEnabled = true; 63 burstsPerBuffer = BURSTS_PER_BUFFER_DEFAULT; 64 } 65 int32_t desiredBufferSize = burstsPerBuffer * getStreamInternal()->getFramesPerBurst(); 66 getStreamInternal()->setBufferSize(desiredBufferSize); 67 } 68 return result; 69} 70 71// Mix data from each application stream and write result to the shared MMAP stream. 72void *AAudioServiceEndpointPlay::callbackLoop() { 73 ALOGD("%s() entering >>>>>>>>>>>>>>> MIXER", __func__); 74 aaudio_result_t result = AAUDIO_OK; 75 int64_t timeoutNanos = getStreamInternal()->calculateReasonableTimeout(); 76 77 // result might be a frame count 78 while (mCallbackEnabled.load() && getStreamInternal()->isActive() && (result >= 0)) { 79 // Mix data from each active stream. 80 mMixer.clear(); 81 82 { // brackets are for lock_guard 83 int index = 0; 84 int64_t mmapFramesWritten = getStreamInternal()->getFramesWritten(); 85 86 std::lock_guard <std::mutex> lock(mLockStreams); 87 for (const auto clientStream : mRegisteredStreams) { 88 int64_t clientFramesRead = 0; 89 bool allowUnderflow = true; 90 91 aaudio_stream_state_t state = clientStream->getState(); 92 if (state == AAUDIO_STREAM_STATE_STOPPING) { 93 allowUnderflow = false; // just read what is already in the FIFO 94 } else if (state != AAUDIO_STREAM_STATE_STARTED) { 95 continue; // this stream is not running so skip it. 96 } 97 98 sp<AAudioServiceStreamShared> streamShared = 99 static_cast<AAudioServiceStreamShared *>(clientStream.get()); 100 101 { 102 // Lock the AudioFifo to protect against close. 103 std::lock_guard <std::mutex> lock(streamShared->getAudioDataQueueLock()); 104 105 FifoBuffer *fifo = streamShared->getAudioDataFifoBuffer_l(); 106 if (fifo != nullptr) { 107 108 // Determine offset between framePosition in client's stream 109 // vs the underlying MMAP stream. 110 clientFramesRead = fifo->getReadCounter(); 111 // These two indices refer to the same frame. 112 int64_t positionOffset = mmapFramesWritten - clientFramesRead; 113 streamShared->setTimestampPositionOffset(positionOffset); 114 115 int32_t framesMixed = mMixer.mix(index, fifo, allowUnderflow); 116 117 if (streamShared->isFlowing()) { 118 // Consider it an underflow if we got less than a burst 119 // after the data started flowing. 120 bool underflowed = allowUnderflow 121 && framesMixed < mMixer.getFramesPerBurst(); 122 if (underflowed) { 123 streamShared->incrementXRunCount(); 124 } 125 } else if (framesMixed > 0) { 126 // Mark beginning of data flow after a start. 127 streamShared->setFlowing(true); 128 } 129 clientFramesRead = fifo->getReadCounter(); 130 } 131 } 132 133 if (clientFramesRead > 0) { 134 // This timestamp represents the completion of data being read out of the 135 // client buffer. It is sent to the client and used in the timing model 136 // to decide when the client has room to write more data. 137 Timestamp timestamp(clientFramesRead, AudioClock::getNanoseconds()); 138 streamShared->markTransferTime(timestamp); 139 } 140 141 index++; // just used for labelling tracks in systrace 142 } 143 } 144 145 // Write mixer output to stream using a blocking write. 146 result = getStreamInternal()->write(mMixer.getOutputBuffer(), 147 getFramesPerBurst(), timeoutNanos); 148 if (result == AAUDIO_ERROR_DISCONNECTED) { 149 AAudioServiceEndpointShared::disconnectRegisteredStreams(); 150 break; 151 } else if (result != getFramesPerBurst()) { 152 ALOGW("callbackLoop() wrote %d / %d", 153 result, getFramesPerBurst()); 154 break; 155 } 156 } 157 158 ALOGD("%s() exiting, enabled = %d, state = %d, result = %d <<<<<<<<<<<<< MIXER", 159 __func__, mCallbackEnabled.load(), getStreamInternal()->getState(), result); 160 return NULL; // TODO review 161} 162