< prev index next >

src/java.desktop/share/classes/com/sun/media/sound/SoftMixingSourceDataLine.java

Print this page




   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */

  25 package com.sun.media.sound;
  26 
  27 import java.io.IOException;
  28 import java.io.InputStream;
  29 import java.util.Arrays;
  30 
  31 import javax.sound.sampled.AudioFormat;
  32 import javax.sound.sampled.AudioInputStream;
  33 import javax.sound.sampled.AudioSystem;
  34 import javax.sound.sampled.DataLine;
  35 import javax.sound.sampled.LineEvent;
  36 import javax.sound.sampled.LineUnavailableException;
  37 import javax.sound.sampled.SourceDataLine;
  38 
  39 /**
  40  * SourceDataLine implementation for the SoftMixingMixer.
  41  *
  42  * @author Karl Helgason
  43  */
  44 public final class SoftMixingSourceDataLine extends SoftMixingDataLine


  59     private byte[] cycling_buffer;
  60 
  61     private int cycling_read_pos = 0;
  62 
  63     private int cycling_write_pos = 0;
  64 
  65     private int cycling_avail = 0;
  66 
  67     private long cycling_framepos = 0;
  68 
  69     private AudioFloatInputStream afis;
  70 
  71     private static class NonBlockingFloatInputStream extends
  72             AudioFloatInputStream {
  73         AudioFloatInputStream ais;
  74 
  75         NonBlockingFloatInputStream(AudioFloatInputStream ais) {
  76             this.ais = ais;
  77         }
  78 

  79         public int available() throws IOException {
  80             return ais.available();
  81         }
  82 

  83         public void close() throws IOException {
  84             ais.close();
  85         }
  86 

  87         public AudioFormat getFormat() {
  88             return ais.getFormat();
  89         }
  90 

  91         public long getFrameLength() {
  92             return ais.getFrameLength();
  93         }
  94 

  95         public void mark(int readlimit) {
  96             ais.mark(readlimit);
  97         }
  98 

  99         public boolean markSupported() {
 100             return ais.markSupported();
 101         }
 102 

 103         public int read(float[] b, int off, int len) throws IOException {
 104             int avail = available();
 105             if (len > avail) {
 106                 int ret = ais.read(b, off, avail);
 107                 Arrays.fill(b, off + ret, off + len, 0);
 108                 return len;
 109             }
 110             return ais.read(b, off, len);
 111         }
 112 

 113         public void reset() throws IOException {
 114             ais.reset();
 115         }
 116 

 117         public long skip(long len) throws IOException {
 118             return ais.skip(len);
 119         }
 120 
 121     }
 122 
 123     SoftMixingSourceDataLine(SoftMixingMixer mixer, DataLine.Info info) {
 124         super(mixer, info);
 125     }
 126 

 127     public int write(byte[] b, int off, int len) {
 128         if (!isOpen())
 129             return 0;
 130         if (len % framesize != 0)
 131             throw new IllegalArgumentException(
 132                     "Number of bytes does not represent an integral number of sample frames.");
 133         if (off < 0) {
 134             throw new ArrayIndexOutOfBoundsException(off);
 135         }
 136         if ((long)off + (long)len > (long)b.length) {
 137             throw new ArrayIndexOutOfBoundsException(b.length);
 138         }
 139 
 140         byte[] buff = cycling_buffer;
 141         int buff_len = cycling_buffer.length;
 142 
 143         int l = 0;
 144         while (l != len) {
 145             int avail;
 146             synchronized (cycling_buffer) {


 185     // FloatControl.Type.PAN
 186     // FloatControl.Type.MASTER_GAIN
 187     // FloatControl.Type.BALANCE
 188 
 189     private boolean _active = false;
 190 
 191     private AudioFormat outputformat;
 192 
 193     private int out_nrofchannels;
 194 
 195     private int in_nrofchannels;
 196 
 197     private float _rightgain;
 198 
 199     private float _leftgain;
 200 
 201     private float _eff1gain;
 202 
 203     private float _eff2gain;
 204 

 205     protected void processControlLogic() {
 206         _active = active;
 207         _rightgain = rightgain;
 208         _leftgain = leftgain;
 209         _eff1gain = eff1gain;
 210         _eff2gain = eff2gain;
 211     }
 212 

 213     protected void processAudioLogic(SoftAudioBuffer[] buffers) {
 214         if (_active) {
 215             float[] left = buffers[SoftMixingMainMixer.CHANNEL_LEFT].array();
 216             float[] right = buffers[SoftMixingMainMixer.CHANNEL_RIGHT].array();
 217             int bufferlen = buffers[SoftMixingMainMixer.CHANNEL_LEFT].getSize();
 218 
 219             int readlen = bufferlen * in_nrofchannels;
 220             if (readbuffer == null || readbuffer.length < readlen) {
 221                 readbuffer = new float[readlen];
 222             }
 223             int ret = 0;
 224             try {
 225                 ret = afis.read(readbuffer);
 226                 if (ret != in_nrofchannels)
 227                     Arrays.fill(readbuffer, ret, readlen, 0);
 228             } catch (IOException e) {
 229             }
 230 
 231             int in_c = in_nrofchannels;
 232             for (int i = 0, ix = 0; i < bufferlen; i++, ix += in_c) {


 257                     }
 258                 }
 259             }
 260 
 261             if (_eff2gain > 0.0001) {
 262                 float[] eff2 = buffers[SoftMixingMainMixer.CHANNEL_EFFECT2]
 263                         .array();
 264                 for (int i = 0, ix = 0; i < bufferlen; i++, ix += in_c) {
 265                     eff2[i] += readbuffer[ix] * _eff2gain;
 266                 }
 267                 if (in_nrofchannels == 2) {
 268                     for (int i = 0, ix = 1; i < bufferlen; i++, ix += in_c) {
 269                         eff2[i] += readbuffer[ix] * _eff2gain;
 270                     }
 271                 }
 272             }
 273 
 274         }
 275     }
 276 

 277     public void open() throws LineUnavailableException {
 278         open(format);
 279     }
 280 

 281     public void open(AudioFormat format) throws LineUnavailableException {
 282         if (bufferSize == -1)
 283             bufferSize = ((int) (format.getFrameRate() / 2))
 284                     * format.getFrameSize();
 285         open(format, bufferSize);
 286     }
 287 

 288     public void open(AudioFormat format, int bufferSize)
 289             throws LineUnavailableException {
 290 
 291         LineEvent event = null;
 292 
 293         if (bufferSize < format.getFrameSize() * 32)
 294             bufferSize = format.getFrameSize() * 32;
 295 
 296         synchronized (control_mutex) {
 297 
 298             if (!isOpen()) {
 299                 if (!mixer.isOpen()) {
 300                     mixer.open();
 301                     mixer.implicitOpen = true;
 302                 }
 303 
 304                 event = new LineEvent(this, LineEvent.Type.OPEN, 0);
 305 
 306                 this.bufferSize = bufferSize - bufferSize
 307                         % format.getFrameSize();
 308                 this.format = format;
 309                 this.framesize = format.getFrameSize();
 310                 this.outputformat = mixer.getFormat();
 311                 out_nrofchannels = outputformat.getChannels();
 312                 in_nrofchannels = format.getChannels();
 313 
 314                 open = true;
 315 
 316                 mixer.getMainMixer().openLine(this);
 317 
 318                 cycling_buffer = new byte[framesize * bufferSize];
 319                 cycling_read_pos = 0;
 320                 cycling_write_pos = 0;
 321                 cycling_avail = 0;
 322                 cycling_framepos = 0;
 323 
 324                 InputStream cycling_inputstream = new InputStream() {
 325 

 326                     public int read() throws IOException {
 327                         byte[] b = new byte[1];
 328                         int ret = read(b);
 329                         if (ret < 0)
 330                             return ret;
 331                         return b[0] & 0xFF;
 332                     }
 333 

 334                     public int available() throws IOException {
 335                         synchronized (cycling_buffer) {
 336                             return cycling_avail;
 337                         }
 338                     }
 339 

 340                     public int read(byte[] b, int off, int len)
 341                             throws IOException {
 342 
 343                         synchronized (cycling_buffer) {
 344                             if (len > cycling_avail)
 345                                 len = cycling_avail;
 346                             int pos = cycling_read_pos;
 347                             byte[] buff = cycling_buffer;
 348                             int buff_len = buff.length;
 349                             for (int i = 0; i < len; i++) {
 350                                 b[off++] = buff[pos];
 351                                 pos++;
 352                                 if (pos == buff_len)
 353                                     pos = 0;
 354                             }
 355                             cycling_read_pos = pos;
 356                             cycling_avail -= len;
 357                             cycling_framepos += len / framesize;
 358                         }
 359                         return len;


 370                 if (Math.abs(format.getSampleRate()
 371                         - outputformat.getSampleRate()) > 0.000001)
 372                     afis = new AudioFloatInputStreamResampler(afis,
 373                             outputformat);
 374 
 375             } else {
 376                 if (!format.matches(getFormat())) {
 377                     throw new IllegalStateException(
 378                             "Line is already open with format " + getFormat()
 379                                     + " and bufferSize " + getBufferSize());
 380                 }
 381             }
 382 
 383         }
 384 
 385         if (event != null)
 386             sendEvent(event);
 387 
 388     }
 389 

 390     public int available() {
 391         synchronized (cycling_buffer) {
 392             return cycling_buffer.length - cycling_avail;
 393         }
 394     }
 395 

 396     public void drain() {
 397         while (true) {
 398             int avail;
 399             synchronized (cycling_buffer) {
 400                 avail = cycling_avail;
 401             }
 402             if (avail != 0)
 403                 return;
 404             try {
 405                 Thread.sleep(1);
 406             } catch (InterruptedException e) {
 407                 return;
 408             }
 409         }
 410     }
 411 

 412     public void flush() {
 413         synchronized (cycling_buffer) {
 414             cycling_read_pos = 0;
 415             cycling_write_pos = 0;
 416             cycling_avail = 0;
 417         }
 418     }
 419 

 420     public int getBufferSize() {
 421         synchronized (control_mutex) {
 422             return bufferSize;
 423         }
 424     }
 425 

 426     public AudioFormat getFormat() {
 427         synchronized (control_mutex) {
 428             return format;
 429         }
 430     }
 431 

 432     public int getFramePosition() {
 433         return (int) getLongFramePosition();
 434     }
 435 

 436     public float getLevel() {
 437         return AudioSystem.NOT_SPECIFIED;
 438     }
 439 

 440     public long getLongFramePosition() {
 441         synchronized (cycling_buffer) {
 442             return cycling_framepos;
 443         }
 444     }
 445 

 446     public long getMicrosecondPosition() {
 447         return (long) (getLongFramePosition() * (1000000.0 / (double) getFormat()
 448                 .getSampleRate()));
 449     }
 450 

 451     public boolean isActive() {
 452         synchronized (control_mutex) {
 453             return active;
 454         }
 455     }
 456 

 457     public boolean isRunning() {
 458         synchronized (control_mutex) {
 459             return active;
 460         }
 461     }
 462 

 463     public void start() {
 464 
 465         LineEvent event = null;
 466 
 467         synchronized (control_mutex) {
 468             if (isOpen()) {
 469                 if (active)
 470                     return;
 471                 active = true;
 472                 event = new LineEvent(this, LineEvent.Type.START,
 473                         getLongFramePosition());
 474             }
 475         }
 476 
 477         if (event != null)
 478             sendEvent(event);
 479     }
 480 

 481     public void stop() {
 482         LineEvent event = null;
 483 
 484         synchronized (control_mutex) {
 485             if (isOpen()) {
 486                 if (!active)
 487                     return;
 488                 active = false;
 489                 event = new LineEvent(this, LineEvent.Type.STOP,
 490                         getLongFramePosition());
 491             }
 492         }
 493 
 494         if (event != null)
 495             sendEvent(event);
 496     }
 497 

 498     public void close() {
 499 
 500         LineEvent event = null;
 501 
 502         synchronized (control_mutex) {
 503             if (!isOpen())
 504                 return;
 505             stop();
 506 
 507             event = new LineEvent(this, LineEvent.Type.CLOSE,
 508                     getLongFramePosition());
 509 
 510             open = false;
 511             mixer.getMainMixer().closeLine(this);
 512         }
 513 
 514         if (event != null)
 515             sendEvent(event);
 516 
 517     }
 518 

 519     public boolean isOpen() {
 520         synchronized (control_mutex) {
 521             return open;
 522         }
 523     }
 524 
 525 }


   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.media.sound;
  27 
  28 import java.io.IOException;
  29 import java.io.InputStream;
  30 import java.util.Arrays;
  31 
  32 import javax.sound.sampled.AudioFormat;
  33 import javax.sound.sampled.AudioInputStream;
  34 import javax.sound.sampled.AudioSystem;
  35 import javax.sound.sampled.DataLine;
  36 import javax.sound.sampled.LineEvent;
  37 import javax.sound.sampled.LineUnavailableException;
  38 import javax.sound.sampled.SourceDataLine;
  39 
  40 /**
  41  * SourceDataLine implementation for the SoftMixingMixer.
  42  *
  43  * @author Karl Helgason
  44  */
  45 public final class SoftMixingSourceDataLine extends SoftMixingDataLine


  60     private byte[] cycling_buffer;
  61 
  62     private int cycling_read_pos = 0;
  63 
  64     private int cycling_write_pos = 0;
  65 
  66     private int cycling_avail = 0;
  67 
  68     private long cycling_framepos = 0;
  69 
  70     private AudioFloatInputStream afis;
  71 
  72     private static class NonBlockingFloatInputStream extends
  73             AudioFloatInputStream {
  74         AudioFloatInputStream ais;
  75 
  76         NonBlockingFloatInputStream(AudioFloatInputStream ais) {
  77             this.ais = ais;
  78         }
  79 
  80         @Override
  81         public int available() throws IOException {
  82             return ais.available();
  83         }
  84 
  85         @Override
  86         public void close() throws IOException {
  87             ais.close();
  88         }
  89 
  90         @Override
  91         public AudioFormat getFormat() {
  92             return ais.getFormat();
  93         }
  94 
  95         @Override
  96         public long getFrameLength() {
  97             return ais.getFrameLength();
  98         }
  99 
 100         @Override
 101         public void mark(int readlimit) {
 102             ais.mark(readlimit);
 103         }
 104 
 105         @Override
 106         public boolean markSupported() {
 107             return ais.markSupported();
 108         }
 109 
 110         @Override
 111         public int read(float[] b, int off, int len) throws IOException {
 112             int avail = available();
 113             if (len > avail) {
 114                 int ret = ais.read(b, off, avail);
 115                 Arrays.fill(b, off + ret, off + len, 0);
 116                 return len;
 117             }
 118             return ais.read(b, off, len);
 119         }
 120 
 121         @Override
 122         public void reset() throws IOException {
 123             ais.reset();
 124         }
 125 
 126         @Override
 127         public long skip(long len) throws IOException {
 128             return ais.skip(len);
 129         }
 130 
 131     }
 132 
 133     SoftMixingSourceDataLine(SoftMixingMixer mixer, DataLine.Info info) {
 134         super(mixer, info);
 135     }
 136 
 137     @Override
 138     public int write(byte[] b, int off, int len) {
 139         if (!isOpen())
 140             return 0;
 141         if (len % framesize != 0)
 142             throw new IllegalArgumentException(
 143                     "Number of bytes does not represent an integral number of sample frames.");
 144         if (off < 0) {
 145             throw new ArrayIndexOutOfBoundsException(off);
 146         }
 147         if ((long)off + (long)len > (long)b.length) {
 148             throw new ArrayIndexOutOfBoundsException(b.length);
 149         }
 150 
 151         byte[] buff = cycling_buffer;
 152         int buff_len = cycling_buffer.length;
 153 
 154         int l = 0;
 155         while (l != len) {
 156             int avail;
 157             synchronized (cycling_buffer) {


 196     // FloatControl.Type.PAN
 197     // FloatControl.Type.MASTER_GAIN
 198     // FloatControl.Type.BALANCE
 199 
 200     private boolean _active = false;
 201 
 202     private AudioFormat outputformat;
 203 
 204     private int out_nrofchannels;
 205 
 206     private int in_nrofchannels;
 207 
 208     private float _rightgain;
 209 
 210     private float _leftgain;
 211 
 212     private float _eff1gain;
 213 
 214     private float _eff2gain;
 215 
 216     @Override
 217     protected void processControlLogic() {
 218         _active = active;
 219         _rightgain = rightgain;
 220         _leftgain = leftgain;
 221         _eff1gain = eff1gain;
 222         _eff2gain = eff2gain;
 223     }
 224 
 225     @Override
 226     protected void processAudioLogic(SoftAudioBuffer[] buffers) {
 227         if (_active) {
 228             float[] left = buffers[SoftMixingMainMixer.CHANNEL_LEFT].array();
 229             float[] right = buffers[SoftMixingMainMixer.CHANNEL_RIGHT].array();
 230             int bufferlen = buffers[SoftMixingMainMixer.CHANNEL_LEFT].getSize();
 231 
 232             int readlen = bufferlen * in_nrofchannels;
 233             if (readbuffer == null || readbuffer.length < readlen) {
 234                 readbuffer = new float[readlen];
 235             }
 236             int ret = 0;
 237             try {
 238                 ret = afis.read(readbuffer);
 239                 if (ret != in_nrofchannels)
 240                     Arrays.fill(readbuffer, ret, readlen, 0);
 241             } catch (IOException e) {
 242             }
 243 
 244             int in_c = in_nrofchannels;
 245             for (int i = 0, ix = 0; i < bufferlen; i++, ix += in_c) {


 270                     }
 271                 }
 272             }
 273 
 274             if (_eff2gain > 0.0001) {
 275                 float[] eff2 = buffers[SoftMixingMainMixer.CHANNEL_EFFECT2]
 276                         .array();
 277                 for (int i = 0, ix = 0; i < bufferlen; i++, ix += in_c) {
 278                     eff2[i] += readbuffer[ix] * _eff2gain;
 279                 }
 280                 if (in_nrofchannels == 2) {
 281                     for (int i = 0, ix = 1; i < bufferlen; i++, ix += in_c) {
 282                         eff2[i] += readbuffer[ix] * _eff2gain;
 283                     }
 284                 }
 285             }
 286 
 287         }
 288     }
 289 
 290     @Override
 291     public void open() throws LineUnavailableException {
 292         open(format);
 293     }
 294 
 295     @Override
 296     public void open(AudioFormat format) throws LineUnavailableException {
 297         if (bufferSize == -1)
 298             bufferSize = ((int) (format.getFrameRate() / 2))
 299                     * format.getFrameSize();
 300         open(format, bufferSize);
 301     }
 302 
 303     @Override
 304     public void open(AudioFormat format, int bufferSize)
 305             throws LineUnavailableException {
 306 
 307         LineEvent event = null;
 308 
 309         if (bufferSize < format.getFrameSize() * 32)
 310             bufferSize = format.getFrameSize() * 32;
 311 
 312         synchronized (control_mutex) {
 313 
 314             if (!isOpen()) {
 315                 if (!mixer.isOpen()) {
 316                     mixer.open();
 317                     mixer.implicitOpen = true;
 318                 }
 319 
 320                 event = new LineEvent(this, LineEvent.Type.OPEN, 0);
 321 
 322                 this.bufferSize = bufferSize - bufferSize
 323                         % format.getFrameSize();
 324                 this.format = format;
 325                 this.framesize = format.getFrameSize();
 326                 this.outputformat = mixer.getFormat();
 327                 out_nrofchannels = outputformat.getChannels();
 328                 in_nrofchannels = format.getChannels();
 329 
 330                 open = true;
 331 
 332                 mixer.getMainMixer().openLine(this);
 333 
 334                 cycling_buffer = new byte[framesize * bufferSize];
 335                 cycling_read_pos = 0;
 336                 cycling_write_pos = 0;
 337                 cycling_avail = 0;
 338                 cycling_framepos = 0;
 339 
 340                 InputStream cycling_inputstream = new InputStream() {
 341 
 342                     @Override
 343                     public int read() throws IOException {
 344                         byte[] b = new byte[1];
 345                         int ret = read(b);
 346                         if (ret < 0)
 347                             return ret;
 348                         return b[0] & 0xFF;
 349                     }
 350 
 351                     @Override
 352                     public int available() throws IOException {
 353                         synchronized (cycling_buffer) {
 354                             return cycling_avail;
 355                         }
 356                     }
 357 
 358                     @Override
 359                     public int read(byte[] b, int off, int len)
 360                             throws IOException {
 361 
 362                         synchronized (cycling_buffer) {
 363                             if (len > cycling_avail)
 364                                 len = cycling_avail;
 365                             int pos = cycling_read_pos;
 366                             byte[] buff = cycling_buffer;
 367                             int buff_len = buff.length;
 368                             for (int i = 0; i < len; i++) {
 369                                 b[off++] = buff[pos];
 370                                 pos++;
 371                                 if (pos == buff_len)
 372                                     pos = 0;
 373                             }
 374                             cycling_read_pos = pos;
 375                             cycling_avail -= len;
 376                             cycling_framepos += len / framesize;
 377                         }
 378                         return len;


 389                 if (Math.abs(format.getSampleRate()
 390                         - outputformat.getSampleRate()) > 0.000001)
 391                     afis = new AudioFloatInputStreamResampler(afis,
 392                             outputformat);
 393 
 394             } else {
 395                 if (!format.matches(getFormat())) {
 396                     throw new IllegalStateException(
 397                             "Line is already open with format " + getFormat()
 398                                     + " and bufferSize " + getBufferSize());
 399                 }
 400             }
 401 
 402         }
 403 
 404         if (event != null)
 405             sendEvent(event);
 406 
 407     }
 408 
 409     @Override
 410     public int available() {
 411         synchronized (cycling_buffer) {
 412             return cycling_buffer.length - cycling_avail;
 413         }
 414     }
 415 
 416     @Override
 417     public void drain() {
 418         while (true) {
 419             int avail;
 420             synchronized (cycling_buffer) {
 421                 avail = cycling_avail;
 422             }
 423             if (avail != 0)
 424                 return;
 425             try {
 426                 Thread.sleep(1);
 427             } catch (InterruptedException e) {
 428                 return;
 429             }
 430         }
 431     }
 432 
 433     @Override
 434     public void flush() {
 435         synchronized (cycling_buffer) {
 436             cycling_read_pos = 0;
 437             cycling_write_pos = 0;
 438             cycling_avail = 0;
 439         }
 440     }
 441 
 442     @Override
 443     public int getBufferSize() {
 444         synchronized (control_mutex) {
 445             return bufferSize;
 446         }
 447     }
 448 
 449     @Override
 450     public AudioFormat getFormat() {
 451         synchronized (control_mutex) {
 452             return format;
 453         }
 454     }
 455 
 456     @Override
 457     public int getFramePosition() {
 458         return (int) getLongFramePosition();
 459     }
 460 
 461     @Override
 462     public float getLevel() {
 463         return AudioSystem.NOT_SPECIFIED;
 464     }
 465 
 466     @Override
 467     public long getLongFramePosition() {
 468         synchronized (cycling_buffer) {
 469             return cycling_framepos;
 470         }
 471     }
 472 
 473     @Override
 474     public long getMicrosecondPosition() {
 475         return (long) (getLongFramePosition() * (1000000.0 / (double) getFormat()
 476                 .getSampleRate()));
 477     }
 478 
 479     @Override
 480     public boolean isActive() {
 481         synchronized (control_mutex) {
 482             return active;
 483         }
 484     }
 485 
 486     @Override
 487     public boolean isRunning() {
 488         synchronized (control_mutex) {
 489             return active;
 490         }
 491     }
 492 
 493     @Override
 494     public void start() {
 495 
 496         LineEvent event = null;
 497 
 498         synchronized (control_mutex) {
 499             if (isOpen()) {
 500                 if (active)
 501                     return;
 502                 active = true;
 503                 event = new LineEvent(this, LineEvent.Type.START,
 504                         getLongFramePosition());
 505             }
 506         }
 507 
 508         if (event != null)
 509             sendEvent(event);
 510     }
 511 
 512     @Override
 513     public void stop() {
 514         LineEvent event = null;
 515 
 516         synchronized (control_mutex) {
 517             if (isOpen()) {
 518                 if (!active)
 519                     return;
 520                 active = false;
 521                 event = new LineEvent(this, LineEvent.Type.STOP,
 522                         getLongFramePosition());
 523             }
 524         }
 525 
 526         if (event != null)
 527             sendEvent(event);
 528     }
 529 
 530     @Override
 531     public void close() {
 532 
 533         LineEvent event = null;
 534 
 535         synchronized (control_mutex) {
 536             if (!isOpen())
 537                 return;
 538             stop();
 539 
 540             event = new LineEvent(this, LineEvent.Type.CLOSE,
 541                     getLongFramePosition());
 542 
 543             open = false;
 544             mixer.getMainMixer().closeLine(this);
 545         }
 546 
 547         if (event != null)
 548             sendEvent(event);
 549 
 550     }
 551 
 552     @Override
 553     public boolean isOpen() {
 554         synchronized (control_mutex) {
 555             return open;
 556         }
 557     }

 558 }
< prev index next >