Package net.sf.fmj.media.multiplexer.audio

Source Code of net.sf.fmj.media.multiplexer.audio.AUMux

package net.sf.fmj.media.multiplexer.audio;

import java.io.IOException;
import java.io.OutputStream;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.media.Buffer;
import javax.media.Format;
import javax.media.ResourceUnavailableException;
import javax.media.format.AudioFormat;
import javax.media.protocol.FileTypeDescriptor;
import javax.media.protocol.Seekable;
import javax.media.protocol.DataSource;
import javax.media.protocol.PushSourceStream;

import net.sf.fmj.media.codec.JavaSoundCodec;
import net.sf.fmj.media.multiplexer.AbstractInputStreamMux;
import net.sf.fmj.media.renderer.audio.JavaSoundUtils;
import net.sf.fmj.utility.LoggerSingleton;
import net.sf.fmj.media.multiplexer.InputStreamPushDataSource;
import net.sf.fmj.media.multiplexer.InputStreamPushSourceStream;

/**
* AU Mux that doesn't use javasound.
* @author Ken Larson
*
*/
public class AUMux extends AbstractInputStreamMux
{
  private static final Logger logger = LoggerSingleton.logger;

  public AUMux()
  {
    super(new FileTypeDescriptor(FileTypeDescriptor.BASIC_AUDIO));
  }

  @Override
  public Format[] getSupportedInputFormats()
  {
    return new Format[] {
        new AudioFormat(AudioFormat.LINEAR, -1, 8, -1, -1, AudioFormat.SIGNED),
        new AudioFormat(AudioFormat.LINEAR, -1, 16, -1, AudioFormat.BIG_ENDIAN, AudioFormat.SIGNED),
        new AudioFormat(AudioFormat.LINEAR, -1, 24, -1, AudioFormat.BIG_ENDIAN, AudioFormat.SIGNED),
        new AudioFormat(AudioFormat.LINEAR, -1, 32, -1, AudioFormat.BIG_ENDIAN, AudioFormat.SIGNED),
        new AudioFormat(AudioFormat.ULAW), // TODO: narrow down
        new AudioFormat(AudioFormat.ALAW) // TODO: narrow down
        };
  }
 
  @Override
  public Format setInputFormat(Format format, int trackID)
  {
    logger.finer("setInputFormat " + format + " " + trackID);
   
    boolean match = false;
    for (Format supported : getSupportedInputFormats())
    {
      if (format.matches(supported))
      {  match = true;
        break;
      }
    }
    if (!match)
    {
      logger.warning("Input format does not match any supported input format: " + format);
      return null;
    }
    if (inputFormats != null// TODO: should we save this somewhere and apply once inputFormats is not null?
      inputFormats[trackID] = format;
   
    return format;
  }

 
  private void outputHeader(OutputStream os) throws IOException
  {
    byte[] header = JavaSoundCodec.createAuHeader(JavaSoundUtils.convertFormat((AudioFormat) inputFormats[0]))// TODO: no length
    if (header == null)
      throw new IOException("Unable to create AU header");
   
    os.write(header);
    }
 
  private void outputTrailer(OutputStream os) throws IOException
  {
      // mgodehardt: updating data length field, some java versions cannot handle length of -1 in au file
      // ( microsoft mediaplayer is not playing au files with length -1 )
     
      // should we throw a IOException if length could not be written ?
        DataSource ds = getDataOutput();
        if ( ds instanceof InputStreamPushDataSource )
        {
            InputStreamPushDataSource pds = (InputStreamPushDataSource)ds;
            PushSourceStream pss = pds.getStreams()[0];
           
            if ( pss instanceof InputStreamPushSourceStream )
            {
                InputStreamPushSourceStream ispss = (InputStreamPushSourceStream)pss;
                if ( ((Seekable)ispss.getTransferHandler()) instanceof Seekable )
                {
                    ((Seekable)ispss.getTransferHandler()).seek(8);
                   
                    writeInt(os, bytesWritten);

                    if (getDataOutputNoInit() != null)
                    {
                      getDataOutputNoInit().notifyDataAvailable(0)// only 1 track
                    }
                }
            }
        }
    }
 
  private boolean headerWritten = false;
  private boolean trailerWritten = false;
 
  // when stream is closed, data length is written to the header ( otherwise some programs will not play the au file )
  private long    bytesWritten;

  public void open() throws ResourceUnavailableException
  {
        super.open();
   
    if (!headerWritten)
    {  try
      {
        outputHeader(getOutputStream());
      } catch (IOException e)
      {
        logger.log(Level.WARNING, "" + e, e);
        throw new ResourceUnavailableException("" + e);
      }
      headerWritten = true;
    }
  }
 
  @Override
  public void close()
  {
    if (!trailerWritten)
    {
        try
      {
                outputTrailer(getOutputStream());
      } catch (IOException e)
      {
        logger.log(Level.WARNING, "" + e, e);
        throw new RuntimeException(e);
      }
      trailerWritten = true;
    }
   
    super.close();
  }

  @Override
  protected void doProcess(Buffer buffer, int trackID, OutputStream os) throws IOException
  {
    if (!headerWritten)
    {  outputHeader(os);
      headerWritten = true;
    }
    if (buffer.isEOM())
    { 
      if (!trailerWritten)
      {  outputTrailer(os);
        trailerWritten = true;
      }
      os.close();
      return;    // TODO: what if there is data in buffer?
    }
   
    if (buffer.isDiscard())
      return;
     
    os.write((byte[]) buffer.getData(), buffer.getOffset(), buffer.getLength());
        bytesWritten += buffer.getLength();
    }
}
TOP

Related Classes of net.sf.fmj.media.multiplexer.audio.AUMux

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.