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