View Javadoc
1   /*
2    * Copyright (c) 2002-2014, Mairie de Paris
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met:
8    *
9    *  1. Redistributions of source code must retain the above copyright notice
10   *     and the following disclaimer.
11   *
12   *  2. Redistributions in binary form must reproduce the above copyright notice
13   *     and the following disclaimer in the documentation and/or other materials
14   *     provided with the distribution.
15   *
16   *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
17   *     contributors may be used to endorse or promote products derived from
18   *     this software without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   * POSSIBILITY OF SUCH DAMAGE.
31   *
32   * License 1.0
33   */
34  package fr.paris.lutece.plugins.captcha.modules.jcaptcha.service.sound.filter;
35  
36  import java.io.FilterInputStream;
37  import java.io.IOException;
38  
39  import javax.sound.sampled.AudioInputStream;
40  
41  
42  /**
43   * The FilteredSoundStream class is a FilterInputStream that applies a
44   * SoundFilter to the underlying input stream.
45   *
46   * @see SoundFilter
47   */
48  public class FilteredSoundStream extends FilterInputStream
49  {
50      private static final int REMAINING_SIZE_UNKNOWN = -1;
51      private SoundFilter _soundFilter;
52      private int _remainingSize;
53      private int _sampleSizeInBits;
54  
55      /**
56       * Creates a new FilteredSoundStream object with the specified InputStream
57       * and SoundFilter.
58       *
59       * @param in the file sound stream
60       * @param soundFilter the sound filter
61       */
62      public FilteredSoundStream( AudioInputStream in, SoundFilter soundFilter )
63      {
64          super( in );
65          _soundFilter = soundFilter;
66          _remainingSize = REMAINING_SIZE_UNKNOWN;
67          _sampleSizeInBits = in.getFormat(  ).getSampleSizeInBits(  );
68      }
69  
70      /**
71       * Overrides the FilterInputStream method to apply this filter whenever
72       * bytes are read
73       *
74       * @param samples the samples
75       * @param offset the offset
76       * @param length the length of sample
77       * @return the byte read
78       * @throws IOException the IOException
79       */
80      public int read( byte[] samples, int offset, int length )
81          throws IOException
82      {
83          int nLengthReturn = length;
84  
85          // read and filter the sound samples in the stream
86          int bytesRead = super.read( samples, offset, nLengthReturn );
87  
88          if ( bytesRead > 0 )
89          {
90              _soundFilter.filter( samples, offset, bytesRead, _sampleSizeInBits );
91  
92              return bytesRead;
93          }
94  
95          // if there are no remaining bytes in the sound stream,
96          // check if the filter has any remaining bytes ("echoes").
97          if ( _remainingSize == REMAINING_SIZE_UNKNOWN )
98          {
99              _remainingSize = _soundFilter.getRemainingSize(  );
100             // round down to nearest multiple of 4
101             // (typical frame size)
102             _remainingSize = _remainingSize / 4 * 4;
103         }
104 
105         if ( _remainingSize > 0 )
106         {
107             nLengthReturn = Math.min( nLengthReturn, _remainingSize );
108 
109             // clear the buffer
110             for ( int i = offset; i < ( offset + nLengthReturn ); i++ )
111             {
112                 samples[i] = 0;
113             }
114 
115             // filter the remaining bytes
116             _soundFilter.filter( samples, offset, nLengthReturn, _sampleSizeInBits );
117             _remainingSize -= nLengthReturn;
118 
119             return nLengthReturn;
120         }
121         else
122         {
123             // end of stream
124             return -1;
125         }
126     }
127 }