2015-10-13 7 views
3

Я пытаюсь использовать Java Sound (с MP3SPI и VorbisSPI) для чтения аудиоданных из файлов WAV, MP3 и OGG, хранения их в байтовый массив, в чтобы играть его позже оттуда. Для того, чтобы сделать это, я использую такой код:Как буферизовать и воспроизводить звуковые данные из файлов OGG с помощью Java Sound

public Sound loadSound(File file){ 
    AudioInputStream baseStream = AudioSystem.getAudioInputStream(file); 
    AudioFormat baseFormat = baseStream.getFormat(); 
    AudioFormat decodedFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 
        baseFormat.getSampleRate(), 
        16, 
        baseFormat.getChannels(), 
        baseFormat.getChannels() * 2, 
        baseFormat.getSampleRate(), 
        false); 
    AudioInputStream decodedStream = AudioSystem.getAudioInputStream(decodedFormat, baseStream); 
    // Buffer audio data from audio stream 
    ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); 
    byte[] buffer = new byte[4096]; 
       int nBytesRead = 0; 
       while (nBytesRead != -1) { 
        nBytesRead = decodedStream.read(buffer, 0, buffer.length); 
        // Write read bytes to out stream 
        byteOut.write(buffer); 
       } 
    // close streams and cleanup 
    byte[] samples = byteOut.toByteArray(); 

    return new Sound(samples,decodedFormat); 
} 

Звук класса в основном (байт [] образцы, формат AudioFormat) пара. Готово, я стараюсь читать и играть в байтовый массив следующим образом:

public void play(Sound sound) { 
    InputStream source = new ByteArrayInputStream(sound.getSamples()); 
    AudioFormat format = sound.getFormat(); 
    // use a short, 100ms (1/10th sec) buffer for real-time changes to the sound stream 
    int bufferSize = format.getFrameSize() 
      * Math.round(format.getSampleRate()/10); 
    byte[] buffer = new byte[bufferSize]; 

    // create a line to play to 
    SourceDataLine line; 
    try { 
     DataLine.Info info 
       = new DataLine.Info(SourceDataLine.class, format); 
     line = (SourceDataLine) AudioSystem.getLine(info); 
     line.open(format, bufferSize); 
    } catch (LineUnavailableException ex) { 
     ex.printStackTrace(); 
     return; 
    } 

    // start the line 
    line.start(); 

    // copy data to the line 
    try { 
     int numBytesRead = 0; 
     while (numBytesRead != -1) { 
      numBytesRead 
        = source.read(buffer, 0, buffer.length); 
      if (numBytesRead != -1) { 
       line.write(buffer, 0, numBytesRead); 
      } 
     } 
    } catch (IOException ex) { 
     ex.printStackTrace(); 
    } catch (ArrayIndexOutOfBoundsException ex2) { 

    } 

    // wait until all data is played, then close the line 
    line.drain(); 
    line.close(); 

} 

Это все работает отлично WAV и MP3, но воспроизведение OGG искажается и несколько замедлились, так как если формат был неправ. Мне бы хотелось, чтобы кто-то мог указать, почему это происходит.

Примечание: Я как бы решил проблему, загрузив весь аудиофайл в виде байтового массива с помощью FileInputStream, а затем воспроизведя его с помощью AudioInputStream над ByteArrayInputStream на массиве. Тем не менее, массив байтов содержит кодированные данные вместо декодированного: на практике это не имеет большого значения для меня, но я не знаю, почему предыдущий подход не работал для OGG. Спасибо всем, кто попытается ответить.

+1

Возможно, это не связано, но вы должны использовать 'nBytesRead' в вызове' byteOut.write'. Возможно, что чтение вернет менее 4096 байт, и в этом случае вы будете писать мусор в поток вывода. Это почти гарантировано произойдет в последнем буфере. – jaket

+0

Это похоже на трюк! Спасибо @jaket :) – EPresident

+0

Прохладный, я напишу это как ответ, который вы можете принять. – jaket

ответ

2

Вопрос находится в loadSound, где возвращаемое значение nBytesRead не используется в следующем вызове write. Функция read не требуется для возврата полного количества запрошенных байтов. Фактически, это могло бы сделать декодер проще реализовать, если он может сломать вещи по своим естественным границам. Вероятно, это то, что делает декодер ogg. Кроме того, если возвращаемое значение не используется, то самый прочитанный вызов вряд ли вернет требуемый размер.

  byte[] buffer = new byte[4096]; 
      int nBytesRead = 0; 
      while (nBytesRead != -1) { 
       nBytesRead = decodedStream.read(buffer, 0, buffer.length); 
       // Write read bytes to out stream 
       byteOut.write(buffer, 0, nBytesRead); 
       //     ^^^^^^^^^^^^^ 
      } 

 Смежные вопросы

  • Нет связанных вопросов^_^