Java AudioInputStream如何支持负数字节跳过

时间:2018-08-19 18:52:03

标签: java audio skip audioinputstream

我正在尝试使用AudioInputStream跳过负数的字节  skip(long bytes)方法。

问题正在尝试(假设有少量字节...):

int skipped = audioInputStream.skip(-bytes);

总是返回0,如答案Java AudioInputStream skip with negative number of bytes always returns 0所述

我需要创建一个实现,该实现还支持负数的字节或类似向后的内容。


Here is the full code的github库。

我要做的是每次用户跳过音频时都重新创建线路  当我当然可以做得更好的时候,这会非常慢... ...向前还是向后。现在它仅支持转发...

/**                                                                                                                   
 * Skip bytes in the File input stream. It will skip N frames matching to bytes, so it will never skip given bytes len
 *                                                                                                                    
 * @param bytes                                                                                                       
 *            the bytes                                                                                               
 * @return value bigger than 0 for File and value = 0 for URL and InputStream                                         
 * @throws StreamPlayerException                                                                                      
 *             the stream player exception                                                                            
 */                                                                                                                   
public long seek(long bytes) throws StreamPlayerException {                                                           
    long totalSkipped = 0;                                                                                            

    //If it is File                                                                                                   
    if (dataSource instanceof File) {                                                                                 

        //Check if the requested bytes are more than totalBytes of Audio                                              
        long bytesLength = getTotalBytes();                                                                           
        System.out.println("Bytes: " + bytes + " BytesLength: " + bytesLength);                                       
        if ( ( bytesLength <= 0 ) || ( bytes >= bytesLength )) {                                                      
            generateEvent(Status.EOM, getEncodedStreamPosition(), null);                                              
            return totalSkipped;                                                                                      
        }                                                                                                             

        logger.info(() -> "Bytes to skip : " + bytes);                                                                
        Status previousStatus = status;                                                                               
        status = Status.SEEKING;                                                                                      

        try {                                                                                                         
            synchronized (audioLock) {                                                                                
                generateEvent(Status.SEEKING, AudioSystem.NOT_SPECIFIED, null);                                       
                initAudioInputStream();                                                                               
                if (audioInputStream != null) {                                                                       

                    long skipped;                                                                                     
                    // Loop until bytes are really skipped.                                                           
                    while (totalSkipped < ( bytes )) { //totalSkipped < (bytes-SKIP_INACCURACY_SIZE)))                
                        //System.out.println("Running");                                                              
                        skipped = audioInputStream.skip(bytes - totalSkipped);                                        
                        if (skipped == 0)                                                                             
                            break;                                                                                    
                        totalSkipped += skipped;                                                                      
                        logger.info("Skipped : " + totalSkipped + "/" + bytes);                                       
                        if (totalSkipped == -1)                                                                       
                            throw new StreamPlayerException(StreamPlayerException.PlayerException.SKIP_NOT_SUPPORTED);

                        logger.info("Skeeping:" + totalSkipped);                                                      
                    }                                                                                                 
                }                                                                                                     
            }                                                                                                         
            generateEvent(Status.SEEKED, getEncodedStreamPosition(), null);                                           
            status = Status.OPENED;                                                                                   
            if (previousStatus == Status.PLAYING)                                                                     
                play();                                                                                               
            else if (previousStatus == Status.PAUSED) {                                                               
                play();                                                                                               
                pause();                                                                                              
            }                                                                                                         

        } catch (IOException ex) {                                                                                    
            logger.log(Level.WARNING, ex.getMessage(), ex);                                                           
        }                                                                                                             
    }                                                                                                                 
    return totalSkipped;                                                                                              
}                                                                                                                     

2 个答案:

答案 0 :(得分:2)

您可以创建自己的缓冲区,它可以是ByteArrayOutputStream,但这是个a肿的事情-几分钟后总是让我内存不足-或拥有自己的Vector或其他ArrayList。

我尝试了一个10分钟的.wav文件,该文件运行良好-可以播放并将字节添加到缓冲区。

例如

Vector v=new Vector();
byte[] data=new byte[basicU];
while(true) {
  k=audioInputStream.read(data, 0, data.length);
  v.add(data);
  if(k<0) break;
  tot+=k;
}

-

这是我用于播放带有搜索文件的方法。我有一个用于生成寻道信号的线程。当我们进行多次搜索时,问题就变得复杂了。我使用变量K来检查是否需要向缓冲区添加数据。我不使用跳过,而是正常阅读;只是不要在线播放。

public void play() {
  boolean seekingBack=false;
  int i, j, k=0, seekPos=0, basicU=1024;
  AudioFormat targetFormat=null;
  int tot=0;
        new Thread() {
          public void run() {
            while(true) {
              numBytes=(Math.random()>0.5?1:-1)*500000;
              try { Thread.sleep(5000); } catch (Exception e) {} 
              seekSignal=true;
            }
          }}.start();
      try {
      File fileIn=new File("........");
        AudioInputStream audioInputStream=AudioSystem.getAudioInputStream(fileIn);
        targetFormat=audioInputStream.getFormat();
        DataLine.Info dinfo=new DataLine.Info(SourceDataLine.class, targetFormat);
        SourceDataLine line=null;
        line=(SourceDataLine)AudioSystem.getLine(dinfo);
        if(line==null) return;
        line.open(targetFormat);
        line.start();
        Vector v=new Vector();
        byte[] data=new byte[basicU];
        int K=0;
        while(true) {
          if(seekingBack) { // seeking backwards
            K=seekPos;
            k=data.length;
            for(j=0; j<data.length; j++)
              if(seekPos+j<v.size()) data[j]=((Byte)v.get(seekPos+j)).byteValue();
              else { k=j; break; }
            line.write(data, 0, k);
            seekPos+=k;
            K+=k;
            if(seekPos>v.size()-1) seekingBack=false;
          }
          else { // normal playing
            k=audioInputStream.read(data, 0, data.length);
            if(k<0) break;
            line.write(data, 0, k);
            if(K>=v.size()) for(j=0; j<k; j++) v.add(data[j]);
            K+=k;
          }
          if(seekSignal) { // received a seek signal
            if(seekingBack) { // we are on a previous back seek - reading from the buffer
            if(numBytes<0) {
              seekPos+=numBytes;
              if(seekPos<0) seekPos=0;
            }
            else { // depending on where the seek will go (in the buffer or actual audio stream)
              if(numBytes+seekPos<v.size())
                seekPos+=numBytes;
              else { // actual stream
                int rem=numBytes-(v.size()-seekPos);
                K=v.size();
                while(rem>0) {
                  k=audioInputStream.read(data, 0, data.length);
                  if(k<0) break;
                  if(K>=v.size()) for(j=0; j<k; j++) v.add(data[j]);
                  rem-=k;
                  K+=k;
                }
              }
            }
            }
            else { // we are not processing a previous back seek
            if(numBytes>=0) { // forward
                while(numBytes>0) {
                  k=audioInputStream.read(data, 0, data.length);
                  if(k<0) break;
                  if(K>=v.size()) for(j=0; j<k; j++) v.add(data[j]);
                  numBytes-=k;
                  K+=k;
                }
            }
            else { // backward
              seekingBack=true; seekPos=v.size()+numBytes; if(seekPos<0) seekPos=0; }
            }
            seekSignal=false;
          }
        }
        line.stop();
        line.close();
      }
      catch(Exception ex) { ex.printStackTrace(); System.out.println("audio problem "+ex); }
}

答案 1 :(得分:0)

使用您自己的缓冲区来保存历史记录的滚动窗口。我将构建一个帮助程序类,通过分配List<byte[]>来管理历史记录,例如以8192字节为块。然后,您需要一些简单的溢出机制来抛出最旧的块,并结合一些指针操作来跟踪您实际在流中的位置。祝你好运!