MonoPipe.cpp revision 6d8aabe8a3be1ac0789d00b82c3ca8b81381f5ab
1/* 2 * Copyright (C) 2012 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 "MonoPipe" 18//#define LOG_NDEBUG 0 19 20#include <cutils/atomic.h> 21#include <cutils/compiler.h> 22#include <utils/Log.h> 23#include "MonoPipe.h" 24#include "roundup.h" 25 26namespace android { 27 28MonoPipe::MonoPipe(size_t maxFrames, NBAIO_Format format, bool writeCanBlock) : 29 NBAIO_Sink(format), 30 mMaxFrames(roundup(maxFrames)), 31 mBuffer(malloc(mMaxFrames * Format_frameSize(format))), 32 mFront(0), 33 mRear(0), 34 mWriteCanBlock(writeCanBlock) 35{ 36} 37 38MonoPipe::~MonoPipe() 39{ 40 free(mBuffer); 41} 42 43ssize_t MonoPipe::availableToWrite() const 44{ 45 if (CC_UNLIKELY(!mNegotiated)) { 46 return NEGOTIATE; 47 } 48 ssize_t ret = mMaxFrames - (mRear - android_atomic_acquire_load(&mFront)); 49 ALOG_ASSERT((0 <= ret) && (ret <= mMaxFrames)); 50 return ret; 51} 52 53ssize_t MonoPipe::write(const void *buffer, size_t count) 54{ 55 if (CC_UNLIKELY(!mNegotiated)) { 56 return NEGOTIATE; 57 } 58 size_t totalFramesWritten = 0; 59 while (count > 0) { 60 size_t avail = availableToWrite(); 61 size_t written = avail; 62 if (CC_LIKELY(written > count)) { 63 written = count; 64 } 65 size_t rear = mRear & (mMaxFrames - 1); 66 size_t part1 = mMaxFrames - rear; 67 if (part1 > written) { 68 part1 = written; 69 } 70 if (CC_LIKELY(part1 > 0)) { 71 memcpy((char *) mBuffer + (rear << mBitShift), buffer, part1 << mBitShift); 72 if (CC_UNLIKELY(rear + part1 == mMaxFrames)) { 73 size_t part2 = written - part1; 74 if (CC_LIKELY(part2 > 0)) { 75 memcpy(mBuffer, (char *) buffer + (part1 << mBitShift), part2 << mBitShift); 76 } 77 } 78 android_atomic_release_store(written + mRear, &mRear); 79 totalFramesWritten += written; 80 } 81 if (!mWriteCanBlock) { 82 break; 83 } 84 count -= written; 85 buffer = (char *) buffer + (written << mBitShift); 86 // Simulate blocking I/O by sleeping at different rates, depending on a throttle. 87 // The throttle tries to keep the pipe about 5/8 full on average, with a slight jitter. 88 uint64_t ns; 89 enum { 90 THROTTLE_VERY_FAST, // pipe is (nearly) empty, fill quickly 91 THROTTLE_FAST, // pipe is normal, fill at slightly faster rate 92 THROTTLE_NOMINAL, // pipe is normal, fill at nominal rate 93 THROTTLE_SLOW, // pipe is normal, fill at slightly slower rate 94 THROTTLE_VERY_SLOW, // pipe is (nearly) full, fill slowly 95 } throttle; 96 avail -= written; 97 // FIXME cache these values to avoid re-computation 98 if (avail >= (mMaxFrames * 3) / 4) { 99 throttle = THROTTLE_VERY_FAST; 100 } else if (avail >= mMaxFrames / 2) { 101 throttle = THROTTLE_FAST; 102 } else if (avail >= (mMaxFrames * 3) / 8) { 103 throttle = THROTTLE_NOMINAL; 104 } else if (avail >= mMaxFrames / 4) { 105 throttle = THROTTLE_SLOW; 106 } else { 107 throttle = THROTTLE_VERY_SLOW; 108 } 109 if (written > 0) { 110 // FIXME cache these values also 111 switch (throttle) { 112 case THROTTLE_VERY_FAST: 113 default: 114 ns = written * ( 500000000 / Format_sampleRate(mFormat)); 115 break; 116 case THROTTLE_FAST: 117 ns = written * ( 750000000 / Format_sampleRate(mFormat)); 118 break; 119 case THROTTLE_NOMINAL: 120 ns = written * (1000000000 / Format_sampleRate(mFormat)); 121 break; 122 case THROTTLE_SLOW: 123 ns = written * (1100000000 / Format_sampleRate(mFormat)); 124 break; 125 case THROTTLE_VERY_SLOW: 126 ns = written * (1250000000 / Format_sampleRate(mFormat)); 127 break; 128 } 129 } else { 130 ns = mMaxFrames * (250000000 / Format_sampleRate(mFormat)); 131 } 132 if (ns > 999999999) { 133 ns = 999999999; 134 } 135 struct timespec sleep; 136 sleep.tv_sec = 0; 137 sleep.tv_nsec = ns; 138 nanosleep(&sleep, NULL); 139 } 140 mFramesWritten += totalFramesWritten; 141 return totalFramesWritten; 142} 143 144} // namespace android 145