Aplicação Java - TCC

Olá, estou tentando desenvolver uma aplicação pra reproduzir músicas sem compressão (PCM) de um servidor.
O servidor lê uma pasta contendo as músicas e envia todos os arquivos pelo socket.
A questão é que até consigo reproduzir os dados de áudio da primeira música vindos direto do fluxo (classe InputStream), mas
quando o player começa a executar a segunda música a aplicação me retorna o seguinte erro:

[quote]D:\ESTUDOS\FACULDADE\TCC\TESTE DO PROTOCOLO\Protocolo Multimídia\test>java Player 192.168.0.139 39000
Trying to connect to 192.168.0.139 39000
Made server connection.
java.io.IOException: mark/reset not supported
at java.io.InputStream.reset(InputStream.java:334)
at java.io.FilterInputStream.reset(FilterInputStream.java:200)
at com.sun.media.sound.WaveFileReader.getFMT(WaveFileReader.java:258)
at com.sun.media.sound.WaveFileReader.getAudioInputStream(WaveFileReader.java:160)
at javax.sound.sampled.AudioSystem.getAudioInputStream(AudioSystem.java:1094)
at Player.player(Player.java:35)
at Player.main(Player.java:29)

D:\ESTUDOS\FACULDADE\TCC\TESTE DO PROTOCOLO\Protocolo Multimídia\test>[/quote]

Aqui estão as partes do problema, o método de Server readMusic(), que lê os arquivos da pasta e envia os bytes pelo socket,

[code]// Le os arquivos do diretorio e trata os dados para o fluxo de saida,
// como quantidade de arquivos(o), nome e conteudo.
public void readMusic(Socket clientConn)
{
try
{
OutputStream os = clientConn.getOutputStream();

      // Lista os arquivos do diretorio
      File qntFile = new File(dir);
      String files[] = qntFile.list();
      int qnt_files = files.length;
      
      // Trata os dados para o fluxo de saida.
      System.out.println("Sending File...");
      for (int cur_file = 0; cur_file < qnt_files; cur_file++)
      {
          String fileStr = dir + files[cur_file];
          
          // Envia o conteudo do arquivo.
          byte b[] = new byte[1024];
          InputStream in = new FileInputStream(new File(fileStr));
          int numRead=0;

          BufferedInputStream stream = new BufferedInputStream(in);
          if(cur_file > 0)
              if(stream.markSupported() != true)
                  stream.mark(0);
          
          while ( ( numRead = stream.read(b, 0, b.length)) > 0) {
              os.write(b, 0, numRead);
          }
          os.flush();
      }
  }
  catch(Exception e)
  {
      e.printStackTrace();
      listen();  // volta a verificar a porta se algum erro acontecer
  }
  System.exit(1);

} // Fim do metodo readMusic().[/code]

e o método player() de Player

[code]public static void player(InputStream in) {
try {
while(in != null){
AudioInputStream stream = AudioSystem.getAudioInputStream(in);

            // codificacao ALAW e ULAW precisam ser convertidas
            // para PCM_SIGNED antes de serem reproduzidas.
            AudioFormat format = stream.getFormat();
            if (format.getEncoding() != AudioFormat.Encoding.PCM_SIGNED) {
                format = new AudioFormat(
                    AudioFormat.Encoding.PCM_SIGNED,
                    format.getSampleRate(),
                    format.getSampleSizeInBits()*2,
                    format.getChannels(),
                    format.getFrameSize()*2,
                    format.getFrameRate(),
                    true);
                stream = AudioSystem.getAudioInputStream(format, stream);
            }

            // Cria o canal de comunicacao com o driver de som
            SourceDataLine.Info info = new DataLine.Info(
                SourceDataLine.class, stream.getFormat(),
                ((int)stream.getFrameLength()*format.getFrameSize()));
            SourceDataLine line = (SourceDataLine) AudioSystem.getLine(info);
            line.open(stream.getFormat());
            line.start();

            // Le e reproduz continuamente os pedacos do arquivos de audio.
            int numRead = 0;
            byte[] buf = new byte[line.getBufferSize()];
            while ((numRead = stream.read(buf, 0, buf.length)) >= 0) {
                int offset = 0;
                while (offset < numRead) {
                    offset += line.write(buf, offset, numRead-offset);
                }
            }
            line.drain();
            line.stop();
        }
    }
    catch (IOException e) {
            e.printStackTrace();
        }
    catch (LineUnavailableException e) {
        e.printStackTrace();
    }
    catch (UnsupportedAudioFileException e) {
        e.printStackTrace();
    }
} // Fim do metodo player().[/code]

Se alguém puder ajudar. Por favor, é para o famigerado trabalho de conclusão de curso.

Hernane Orlando




isto é meio simples para um tcc não acha?

O TCC não é só isso… eu pesquisei um bocado de protocolos multimídia, onde eles são usados e onde não são, e porque. Rádio Web.
Isso ai é só pra fechar o trabalho mostrando a simplicidade de se criar um protocolo. E é justamente na simplicidade que eu estou apanhando.

if(stream.markSupported() != true) stream.mark(0);

Olhe o que diz seu if:

“Se o mark não é suportado, use o mark”. Não é a toa que dá erro. Use assim:

if(stream.markSupported()) stream.mark(0);

É ViniGodoy, continua não dando certo.

Mas o que eu tinha entendido é que o método markSuported verifica o suporte, se não tiver ele retorna false, dai o método mark implementaria esse suporte. Mas pelo visto também não é isso.

Não. O método markSupported() indica se esse stream suporta ou não marcações. Se ele suportar, você pode usar os comandos mark() e reset() e similares.

Se não era ali, veja se no seu código você não chama reset() em algum lugar. Se chamar, ponha num if desses também.

O método reset não é usado na aplicação. O engraçado é o seguinte: a pasta contém dois arquivos .wav. Quanto inverto a ordem das músicas, ele toca sem problema a primeira música. Não existe problema quanto a formato dos arquivos. Qualquer uma das duas músicas é reproduzida se entrar primeiro no fluxo.

E na página http://java.sun.com/j2se/1.5.0/docs/api/java/io/InputStream.html#mark(int) diz que o método mark em inputstream não faz nada ("The mark method of InputStream does nothing. "), por isso tentei bufferedinputstream. Então de qual que é desse método mark().

Uma classe deve implementar explicitamente o método mark. Como é o caso do FileInputStream.
O mark faz uma marcação num ponto do stream, para que você possa voltar naquele ponto mais tarde. Entretanto, alguns streams, como os sockets, não suportam esse tipo de marcação, pois são dados são excluídos assim que são lidos.

Na verdade, dê uma lida na documentação do getAudioInputStream.in(InputStream):

Obtains an audio input stream from the provided input stream. The stream must point to valid audio file data. The implementation of this method may require multiple parsers to examine the stream to determine whether they support it. These parsers must be able to mark the stream, read enough data to determine whether they support the stream, and, if not, reset the stream’s read pointer to its original position. If the input stream does not support these operation, this method may fail with an IOException.

É o que está acontecendo com você, não é? Faz sentido. Como você passou só um InputStream para o método, ele terá que fazer uma leitura do cabeçalho para descobrir que tipo de audio você possui. E isso pode exigir que ele “vá e volte” pelo arquivo.

Faça a conversão de ALAW e ULAW para PCM no computador do servidor, já que o FileInputStream suporta markings. Ou grave os arquivos lá diretamente em PCM. Então, você pode ler os dados diretamente do InputStream no cliente, e reproduzi-los no DataLine sem criar um AudioInputStream. Ou, mesmo que crie, você pode usar um dos construtores onde você especifica diretamente o formato, evitando a necessidade dos markings.

Veja, o problema não está no seu protocolo, e nem na transferência.