• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 package org.drrickorang.loopback;
18 
19 
20 /**
21  * Non-blocking pipe where writer writes to the pipe using write() and read reads from the pipe
22  * using read(). Data in the pipe are stored in the short array "mBuffer".
23  * The write side of a pipe permits overruns; flow control is the caller's responsibility.
24  */
25 
26 public class PipeShort extends Pipe {
27     private int          mFront; // writer's current position
28     private int          mRear; // reader's current position
29     private final short  mBuffer[]; // store that data in the pipe
30     private volatile int mVolatileRear; // used to keep rear synchronized
31 
32 
33     /**
34      * IMPORTANT: Since a signed integer is used to store mRear and mFront, their values should not
35      * exceed 2^31 - 1, or else overflows happens and the positions of read and mFront becomes
36      * incorrect.
37      */
PipeShort(int maxSamples)38     public PipeShort(int maxSamples) {
39         super(maxSamples);
40         mBuffer = new short[mMaxValues];
41     }
42 
43 
44     /**
45      * offset must be >= 0.
46      * count is maximum number of bytes to copy, and must be >= 0.
47      * offset + count must be <= buffer.length.
48      * Return actual number of shorts copied, which will be >= 0.
49      */
write(short[] buffer, int offset, int count)50     public int write(short[] buffer, int offset, int count) {
51         // mask the upper bits to get the correct position in the pipe
52         int rear = mRear & (mMaxValues - 1);
53         int written = mMaxValues - rear;
54         if (written > count) {
55             written = count;
56         }
57 
58         System.arraycopy(buffer, offset, mBuffer, rear, written);
59         if (rear + written == mMaxValues) {
60             if ((count -= written) > rear) {
61                 count = rear;
62             }
63             if (count > 0) {
64                 System.arraycopy(buffer, offset + written, mBuffer, 0, count);
65                 written += count;
66             }
67         }
68 
69         mRear += written;
70         mVolatileRear = mRear;
71         return written;
72     }
73 
74 
75     @Override
read(short[] buffer, int offset, int count)76     public int read(short[] buffer, int offset, int count) {
77         int avail = availableToRead();
78         if (avail <= 0) {
79             return avail;
80         }
81 
82         // An overrun can occur from here on and be silently ignored,
83         // but it will be caught at next read()
84         if (count > avail) {
85             count = avail;
86         }
87 
88         // mask the upper bits to get the correct position in the pipe
89         int front = mFront & (mMaxValues - 1);
90         int read = mMaxValues - front;
91 
92         if (read > count) {
93             read = count;
94         }
95 
96         // In particular, an overrun during the System.arraycopy will result in reading corrupt data
97         System.arraycopy(mBuffer, front, buffer, offset, read);
98         // We could re-read the rear pointer here to detect the corruption, but why bother?
99         if (front + read == mMaxValues) {
100             if ((count -= read) > front) {
101                 count = front;
102             }
103 
104             if (count > 0) {
105                 System.arraycopy(mBuffer, 0, buffer, offset + read, count);
106                 read += count;
107             }
108         }
109 
110         mFront += read;
111         return read;
112     }
113 
114 
115 
116     @Override
availableToRead()117     public int availableToRead() {
118         int rear = mVolatileRear;
119         int avail = rear - mFront;
120         if (avail > mMaxValues) {
121             // Discard 1/16 of the most recent data in pipe to avoid another overrun immediately
122             int oldFront = mFront;
123             mFront = rear - mMaxValues + (mMaxValues >> 4);
124             mSamplesOverrun += mFront - oldFront;
125             ++mOverruns;
126             return OVERRUN;
127         }
128 
129         return avail;
130     }
131 
132 
133     @Override
flush()134     public void flush() {
135         mRear = mFront;
136         mVolatileRear = mFront;
137     }
138 
139 }
140