Home | History | Annotate | Download | only in loopback
      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      */
     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      */
     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
     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
    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
    134     public void flush() {
    135         mRear = mFront;
    136         mVolatileRear = mFront;
    137     }
    138 
    139 }
    140