/*
 * JBoss, the OpenSource J2EE webOS
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */

package org.jboss.media.engine.audio;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;

import javax.media.Codec;
import javax.media.DataSink;
import javax.media.Manager;
import javax.media.MediaLocator;
import javax.media.NoDataSinkException;
import javax.media.NoProcessorException;
import javax.media.NotConfiguredError;
import javax.media.Processor;
import javax.media.UnsupportedPlugInException;
import javax.media.control.FormatControl;
import javax.media.control.TrackControl;
import javax.media.format.AudioFormat;
import javax.media.protocol.DataSource;

import jmapps.util.StateHelper;

import org.jboss.media.engine.MediaPluginGraph;
import org.jboss.media.engine.MediaPublisher;
import org.jboss.media.engine.MediaPublisherMBean;

/**
 * @version <tt>$Revision: 1.3 $</tt>
 * @author <a href="mailto:spyridon_samothrakis@yahoo.com">Spyridon Samothrakis</a>
 * 
 * @jmx.mbean extends="org.jboss.media.engine.MediaPublisherMBean"
 */
public class RtpAudioMediaPublisher
   extends MediaPublisher
   implements MediaPublisherMBean, RtpAudioMediaPublisherMBean
{

   private int m_bitRate;
   private int m_resolution;
   private String m_encoding;
   private int m_channels;

   protected Processor m_processor;
   protected DataSink m_rtpTransmitter;

   protected AudioGenericPluginSupport m_plugin;

   public RtpAudioMediaPublisher()
   {
      m_plugin = new AudioGenericPluginSupport();
   }

   // Accessors :) 
   ///////////////////////////////////////////////////////////////////////////////
   /**
    * Returns the bitRate.
    * @return int
    * @jmx:managed-attribute
    */
   public int getBitRate()
   {
      return m_bitRate;
   }

   /**
    * Returns the encoding.
    * @return String
    * @jmx:managed-attribute
    */
   public String getEncoding()
   {
      return m_encoding;
   }

   /**
    * Sets the bitRate.
    * @param bitRate The bitRate to set
    * @jmx:managed-attribute
    */
   public void setBitRate(int bitRate)
   {
      m_bitRate = bitRate;
   }

   /**
    * Sets the encoding.
    * @param encoding The encoding to set
    * @jmx:managed-attribute
    */
   public void setEncoding(String encoding)
   {
      m_encoding = encoding;
   }

   /**
    * Returns the resolution.
    * @return int
    * @jmx:managed-attribute
    */
   public int getResolution()
   {
      return m_resolution;
   }

   /**
    * Sets the resolution.
    * @param resolution The resolution to set
    * @jmx:managed-attribute
    */
   public void setResolution(int resolution)
   {
      m_resolution = resolution;
   }

   /**
    * @return
    * @jmx:managed-attribute
    */
   public int getChannels()
   {
      return m_channels;
   }

   /**
    * @param string
    * @jmx:managed-attribute
    */
   public void setChannels(int channels)
   {
      m_channels = channels;
   }

   public void publish()
      throws
         NoProcessorException,
         MalformedURLException,
         IOException,
         NoDataSinkException
   {
      // Give me a processor
      // For the moment just crush and burn . No exception handling
      File file = new File(getFileName());
      m_processor = Manager.createProcessor(new MediaLocator(file.toURL()));
      StateHelper stateHelper;
      stateHelper = new StateHelper(m_processor);

      if (!stateHelper.configure(10000))
      {
         log.error("Failed to configure the processor.");
      }
      //wait until configured and get ready to fight

      configurePluginGraph();

      // At this point, we have determined where we can send out
      // ulaw data or not.
      // realize the processor
      boolean encodingOk = checkForEncoding(m_encoding);
      if (encodingOk)
      {
         // block until realized.
         if (!stateHelper.realize(10000))
         {
            log.error("Failed to realize the processor.");
         }

         // get the output datasource of the processor and exit
         // if we fail
         DataSource ds = null;

         ds = m_processor.getDataOutput();

         String url = "rtp://" + getHost() + ":" + getPort() + getContext();
         MediaLocator m = new MediaLocator(url);
         m_rtpTransmitter = Manager.createDataSink(ds, m);
         log.debug(m_rtpTransmitter);
         m_rtpTransmitter.open();
         m_rtpTransmitter.start();

         ds.start();
         m_processor.start();
      }

      log.info("Transmission of " + getFileName() + " " + "started");
   }

   public void stop()
   {
      if (m_processor != null)
      {
         m_processor.stop();
         m_processor.close();
         m_processor = null;
         m_rtpTransmitter.close();
         m_rtpTransmitter = null;
      }

      log.info("Transmission of " + getFileName() + " " + "stopped");
   }

   // Helper functions

   private boolean checkForEncoding(String encoding)
   {
      TrackControl track[] = m_processor.getTrackControls();
      boolean encodingOk = false;
      // Go through the tracks and try to program one of them to
      // output ulaw data.
      for (int i = 0; i < track.length; i++)
      {
         if (!encodingOk && track[i] instanceof FormatControl)
         {
            if (((FormatControl) track[i])
               .setFormat(
                  new AudioFormat(
                     getEncoding(),
                     getResolution(),
                     getBitRate(),
                     getChannels()))
               == null)
            {
               track[i].setEnabled(false);
            }
            else
            {
               encodingOk = true;
            }
         }
         else
         {
            // we could not set this track to correct encoding, so disable it
            track[i].setEnabled(false);
         }
      }

      return encodingOk;
   }

   /* (non-Javadoc)
    * @see org.jboss.media.engine.MediaPublisher#addPluginGraph(org.jboss.media.engine.MediaPluginGraph)
    */
   public void addPluginGraph(MediaPluginGraph pg)
   {
      m_plugin.setPluginGraph(pg);
   }

   private void configurePluginGraph()
   {

      if (m_plugin == null)
         return;
      //    add the plugins
      TrackControl tc[] = m_processor.getTrackControls();

      if (tc == null)
      {
         log.error("Failed to obtain track controls from the processor.");
      }
      else
      {
         TrackControl audioTrack = null;
         for (int i = 0; i < tc.length; i++)
         {
            if (tc[i].getFormat() instanceof AudioFormat)
            {
               audioTrack = tc[i];
               break;
            }
         }
         try
         {
            audioTrack.setCodecChain(new Codec[] { m_plugin });
         }
         catch (UnsupportedPlugInException e)
         {
            log.error("The processor does not support effects.");
         }
         catch (NotConfiguredError e)
         {
            log.error("Processor not configured", e);
         }
      }
   }

}