AAudioServiceEndpointPlay.cpp revision 87c9f646a94259d7c321c3b3d5947fa1778f5ac2
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 "AAudioService" 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 37using namespace android; // TODO just import names needed 38using namespace aaudio; // TODO just import names needed 39 40#define BURSTS_PER_BUFFER_DEFAULT 2 41 42AAudioServiceEndpointPlay::AAudioServiceEndpointPlay(AAudioService &audioService) 43 : mStreamInternalPlay(audioService, true) { 44} 45 46AAudioServiceEndpointPlay::~AAudioServiceEndpointPlay() { 47} 48 49aaudio_result_t AAudioServiceEndpointPlay::open(int32_t deviceId) { 50 aaudio_result_t result = AAudioServiceEndpoint::open(deviceId); 51 if (result == AAUDIO_OK) { 52 mMixer.allocate(getStreamInternal()->getSamplesPerFrame(), 53 getStreamInternal()->getFramesPerBurst()); 54 55 int32_t burstsPerBuffer = AAudioProperty_getMixerBursts(); 56 if (burstsPerBuffer == 0) { 57 mLatencyTuningEnabled = true; 58 burstsPerBuffer = BURSTS_PER_BUFFER_DEFAULT; 59 } 60 ALOGD("AAudioServiceEndpoint(): burstsPerBuffer = %d", burstsPerBuffer); 61 int32_t desiredBufferSize = burstsPerBuffer * getStreamInternal()->getFramesPerBurst(); 62 getStreamInternal()->setBufferSize(desiredBufferSize); 63 } 64 return result; 65} 66 67// Mix data from each application stream and write result to the shared MMAP stream. 68void *AAudioServiceEndpointPlay::callbackLoop() { 69 ALOGD("AAudioServiceEndpointPlay(): callbackLoop() entering"); 70 int32_t underflowCount = 0; 71 72 aaudio_result_t result = getStreamInternal()->requestStart(); 73 74 int64_t timeoutNanos = getStreamInternal()->calculateReasonableTimeout(); 75 76 // result might be a frame count 77 while (mCallbackEnabled.load() && getStreamInternal()->isActive() && (result >= 0)) { 78 // Mix data from each active stream. 79 mMixer.clear(); 80 { // use lock guard 81 std::lock_guard <std::mutex> lock(mLockStreams); 82 for (AAudioServiceStreamShared *sharedStream : mRunningStreams) { 83 FifoBuffer *fifo = sharedStream->getDataFifoBuffer(); 84 float volume = 0.5; // TODO get from system 85 bool underflowed = mMixer.mix(fifo, volume); 86 underflowCount += underflowed ? 1 : 0; 87 // TODO log underflows in each stream 88 sharedStream->markTransferTime(AudioClock::getNanoseconds()); 89 } 90 } 91 92 // Write mixer output to stream using a blocking write. 93 result = getStreamInternal()->write(mMixer.getOutputBuffer(), 94 getFramesPerBurst(), timeoutNanos); 95 if (result == AAUDIO_ERROR_DISCONNECTED) { 96 disconnectRegisteredStreams(); 97 break; 98 } else if (result != getFramesPerBurst()) { 99 ALOGW("AAudioServiceEndpoint(): callbackLoop() wrote %d / %d", 100 result, getFramesPerBurst()); 101 break; 102 } 103 } 104 105 result = getStreamInternal()->requestStop(); 106 107 ALOGD("AAudioServiceEndpointPlay(): callbackLoop() exiting, %d underflows", underflowCount); 108 return NULL; // TODO review 109} 110