1 /* 2 * Copyright (C) 2015 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 package com.android.cts.verifier.audio.wavelib; 18 19 // Non-blocking pipe supports a single writer and single reader. 20 // The write side of a pipe permits overruns; flow control is the caller's responsibility. 21 22 public class PipeShort { 23 private int mFront; 24 private int mRear; 25 private short mBuffer[]; 26 private volatile int mVolatileRear; // written by write(), read by read() 27 private int mMaxValues; 28 private int mBytesOverrun; 29 private int mOverruns; 30 public static final int OVERRUN = -2; 31 32 // maxBytes will be rounded up to a power of 2, and all slots are available. Must be >= 2. PipeShort(int maxValues)33 public PipeShort(int maxValues) 34 { 35 mMaxValues = roundup(maxValues); 36 mBuffer = new short[mMaxValues]; 37 } 38 39 // buffer must != null. 40 // offset must be >= 0. 41 // count is maximum number of bytes to copy, and must be >= 0. 42 // offset + count must be <= buffer.length. 43 // Returns actual number of bytes copied >= 0. write(short[] buffer, int offset, int count)44 public int write(short[] buffer, int offset, int count) 45 { 46 int rear = mRear & (mMaxValues - 1); 47 int written = mMaxValues - rear; 48 if (written > count) { 49 written = count; 50 } 51 System.arraycopy(buffer, offset, mBuffer, rear, written); 52 if (rear + written == mMaxValues) { 53 if ((count -= written) > rear) { 54 count = rear; 55 } 56 if (count > 0) { 57 System.arraycopy(buffer, offset + written, mBuffer, 0, count); 58 written += count; 59 } 60 } 61 mRear += written; 62 mVolatileRear = mRear; 63 return written; 64 } 65 availableToRead()66 public int availableToRead() 67 { 68 int rear = mVolatileRear; 69 int avail = rear - mFront; 70 if (avail > mMaxValues) { 71 // Discard 1/16 of the most recent data in pipe to avoid another overrun immediately 72 int oldFront = mFront; 73 mFront = rear - mMaxValues + (mMaxValues >> 4); 74 mBytesOverrun += mFront - oldFront; 75 ++mOverruns; 76 return OVERRUN; 77 } 78 return avail; 79 } 80 81 // buffer must != null. 82 // offset must be >= 0. 83 // count is maximum number of bytes to copy, and must be >= 0. 84 // offset + count must be <= buffer.length. 85 // Returns actual number of bytes copied >= 0. read(short[] buffer, int offset, int count)86 public int read(short[] buffer, int offset, int count) 87 { 88 int avail = availableToRead(); 89 if (avail <= 0) { 90 return avail; 91 } 92 // An overrun can occur from here on and be silently ignored, 93 // but it will be caught at next read() 94 if (count > avail) { 95 count = avail; 96 } 97 int front = mFront & (mMaxValues - 1); 98 int red = mMaxValues - front; 99 if (red > count) { 100 red = count; 101 } 102 // In particular, an overrun during the System.arraycopy will result in reading corrupt data 103 System.arraycopy(mBuffer, front, buffer, offset, red); 104 // We could re-read the rear pointer here to detect the corruption, but why bother? 105 if (front + red == mMaxValues) { 106 if ((count -= red) > front) { 107 count = front; 108 } 109 if (count > 0) { 110 System.arraycopy(mBuffer, 0, buffer, offset + red, count); 111 red += count; 112 } 113 } 114 mFront += red; 115 return red; 116 } 117 flush()118 public void flush() 119 { 120 mRear = mFront; 121 mVolatileRear = mFront; 122 } 123 124 // Round up to the next highest power of 2 roundup(int v)125 private static int roundup(int v) 126 { 127 // Integer.numberOfLeadingZeros() returns 32 for zero input 128 if (v == 0) { 129 v = 1; 130 } 131 int lz = Integer.numberOfLeadingZeros(v); 132 int rounded = 0x80000000 >>> lz; 133 // 0x800000001 and higher are actually rounded _down_ to prevent overflow 134 if (v > rounded && lz > 0) { 135 rounded <<= 1; 136 } 137 return rounded; 138 } 139 140 } 141