Package p2pradio.sources

Source Code of p2pradio.sources.BroadcastBuffer

/*
* P2P-Radio - Peer to peer streaming system
* Project homepage: http://p2p-radio.sourceforge.net/
* Copyright (C) 2003-2004 Michael Kaufmann <hallo@michael-kaufmann.ch>
*
* ---------------------------------------------------------------------------
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
* ---------------------------------------------------------------------------
*/
package p2pradio.sources;

import p2pradio.*;
import p2pradio.packets.MetadataPacket;
import p2pradio.packets.HeaderPacket;
import p2pradio.packets.DataPacket;
import p2pradio.packets.PacketFactory;
import p2pradio.logging.Logger;


/**
* Sources use BroadcastBuffer objects to broadcast data.
* <P>
* The broadcast buffer automatically adds sequence numbers and time stamps
* to the packets and sends Metadata periodically
*
* @author Michael Kaufmann
*/
public class BroadcastBuffer extends Thread
{
  private Buffer buffer;
  private int port;
  private Metadata metadata = new Metadata();
 
  // Informationen f�r die Strompakete
  private long startTime;
  private boolean startTimeIsValid = false;
  private long nextSeqNr = 1;
 
  private long lastSendTime;
  private boolean lastSendTimeIsValid = false
 
  // Messung der Durchschnittsgeschwindigkeit
  private long lastSpeedMeasurementTime;
  private boolean lastSpeedMeasurementTimeIsValid = false;
  private long bytesSinceLastSpeedMeasurement = 0;
  private int speedMeasurementPeriod = 1000;
  private int averageBytesPerSec = 0;
 
  public static final int MAX_SPEED_MEASUREMENT_PERIOD = 32000;
 
  public static final int MAX_NODATA_INTERVAL = 1000;
  public static final byte[] NULL_BYTE = new byte[0];
 
  private YellowPages yp;
 
   
  /**
   * Creates a new Broadcast Buffer.
   *
   * @param buffer The buffer to be filled
   */ 
  public BroadcastBuffer(Buffer buffer, int port)
  {
    this(buffer, port, Messages.getString("BroadcastBuffer.THREAD_NAME")); //$NON-NLS-1$
  }
 
  /**
   * Creates a new Broadcast Buffer.
   *
   * @param buffer The buffer to be filled
   * @param threadName The thread name of this Broadcast Buffer
   */ 
  public BroadcastBuffer(Buffer buffer, int port, String threadName)
  {
    super(threadName);
    this.buffer = buffer;
    this.port = port;
    setDaemon(true);
   
    sendMetadata();
    setHeader(NULL_BYTE);
  }
 
  /**
   * Starts this Broadcast Buffer. It will periodically add Metadata packets.
   */
  public void run()
  { 
    Logger.finer("BroadcastBuffer", "BroadcastBuffer.THREAD_RUNNING"); //$NON-NLS-1$ //$NON-NLS-2$
     
    try
    {
      long now = System.currentTimeMillis();
      long waitTime = MAX_NODATA_INTERVAL;
           
      while(true)
      {
        try
        {
          synchronized(this)
          {
            if (waitTime > 0)
            {
              wait(waitTime);
            }
          }
        }
        catch (InterruptedException e)
        {   
        }
         
        now = System.currentTimeMillis();
       
        if (lastSendTimeIsValid)
        {
          if (now - lastSendTime >= MAX_NODATA_INTERVAL)
          {
            // Es wurden keine Daten gesendet
            sendNullData();
           
            waitTime = MAX_NODATA_INTERVAL;
          }
          else
          {
            waitTime = MAX_NODATA_INTERVAL - (now - lastSendTime);
          }
        }
        else
        {
          // Es wurden noch keine Daten gesendet
          sendNullData();
         
          waitTime = MAX_NODATA_INTERVAL;
        }
      }
    }
    catch (Exception e)
    {
      Logger.severe("BroadcastBuffer", "INTERNAL_ERROR", e); //$NON-NLS-1$ //$NON-NLS-2$
    }
  }

  public void setHeader(byte[] header)
  {
    setHeader(header, 0, header.length);
  }
 
  public void setHeader(byte[] header, int headerLength)
  {
    setHeader(header, 0, headerLength);
  }
 
  public void setHeader(byte[] header, int headerOffset, int headerLength)
  {
    if (header == null)
    {
      throw new NullPointerException();
    }
    else if ((headerOffset < 0) || (headerOffset > header.length) || (headerLength < 0) || ((headerOffset + headerLength) > header.length) || ((headerOffset + headerLength) < 0))
    {
      throw new IndexOutOfBoundsException();
    }
   
    // Maximale Paketgr�sse
    int maxHeaderSize = PacketFactory.TCP_MAX_MESSAGE_SIZE - HeaderPacket.getMaxLength();
   
    if (headerLength > maxHeaderSize)
    {
      throw new IllegalArgumentException(Messages.getString("BroadcastBuffer.HEADER_IS_TOO_LONG")); //$NON-NLS-1$
    }
   
    buffer.put(new HeaderPacket(getNextSeqNr(), getTimestamp(), header, headerOffset, headerLength));
  }


  /**
   * That's the same as <code>sendData(data, 0, data.length)</code>
   *
   * @see #sendData(byte[],int,int)
   */
  public void sendData(byte[] data)
  {
    sendData(data, 0, data.length);
  }

  /**
   * That's the same as <code>sendData(data, 0, dataLength)</code>
   *
   * @see #sendData(byte[],int,int)
   */
  public void sendData(byte[] data, int dataLength)
  {
    sendData(data, 0, dataLength);
  }
 
  /**
   * Puts <code>data</code> in the buffer, but only starting at
   * <code>dataOffset</code> and with length <code>dataLength</code>.
   * <P>
   * If the data is too big to be put in a single {@link DataPacket},
   * the data is distributed to multiple packets.
   *
   * @see #sendData(byte[])
   * @see #sendData(byte[],int)
   */
  public void sendData(byte[] data, int dataOffset, int dataLength)
  {
    if (data == null)
    {
      throw new NullPointerException();
    }
    else if ((dataOffset < 0) || (dataOffset > data.length) || (dataLength < 0) || ((dataOffset + dataLength) > data.length) || ((dataOffset + dataLength) < 0))
    {
      throw new IndexOutOfBoundsException();
    }
    else if (dataLength == 0)
    {
      return;
    }
   
    // Maximale Paketgr�sse
    int maxDataSize = PacketFactory.TCP_MAX_MESSAGE_SIZE - DataPacket.getMaxLength();
   
    if (dataLength > maxDataSize)
    {
      // Die Daten m�ssen auf mehrere Pakete aufgeteilt werden
     
      synchronized(buffer)
      {
        for (int i=0; i < dataLength / maxDataSize; i++)
        {
          buffer.put(new DataPacket(getNextSeqNr(), getTimestamp(), buffer.getNewestHeaderPacket().getSeqNr(), buffer.getNewestMetadataPacket().getSeqNr(), data, dataOffset + i * maxDataSize, maxDataSize));
        }
     
        buffer.put(new DataPacket(getNextSeqNr(), getTimestamp(), buffer.getNewestHeaderPacket().getSeqNr(), buffer.getNewestMetadataPacket().getSeqNr(), data, dataOffset + dataLength - (dataLength % maxDataSize), dataLength % maxDataSize));
      }
    }
    else
    {
      // Nur ein Paket ist n�tig
      buffer.put(new DataPacket(getNextSeqNr(), getTimestamp(), buffer.getNewestHeaderPacket().getSeqNr(), buffer.getNewestMetadataPacket().getSeqNr(), data, dataOffset, dataLength));
    }
   
    long now = System.currentTimeMillis();
   
    lastSendTime = now;
    lastSendTimeIsValid = true;
   
   
    // Messung der Durchschnittsgeschwindigkeit
   
    bytesSinceLastSpeedMeasurement += dataLength;
   
    if (lastSpeedMeasurementTimeIsValid)
    {
      if (now - lastSpeedMeasurementTime >= speedMeasurementPeriod)
      {
        averageBytesPerSec = Math.round((float)bytesSinceLastSpeedMeasurement / ((float)(now - lastSpeedMeasurementTime) / 1000.0f));
        metadata.setAverageByterate(averageBytesPerSec);
       
        // Ist zwar ein bisschen doof, die ganzen Metadaten nochmals
        // zu schicken, nur wegen der Geschwindigkeitsmessung...
        sendMetadata();
       
        if (speedMeasurementPeriod < MAX_SPEED_MEASUREMENT_PERIOD)
        {
          speedMeasurementPeriod *= 2;
        }
       
        lastSpeedMeasurementTime = now;
        bytesSinceLastSpeedMeasurement = 0;
      }
    }
    else
    {
      lastSpeedMeasurementTime = now;
      lastSpeedMeasurementTimeIsValid = true;
    }
  }

  /**
   * Sets the current metadata.
   */
  public void setMetadata(Metadata metadata)
  {
    if (!metadata.equals(this.metadata))
    {
      // Sonst geht die Byterate verloren
      metadata.setAverageByterate(averageBytesPerSec);
     
      // Metadaten klonen und nur die Kopie behalten (sonst sind
      // die Metadaten automatisch immer auf dem neusten Stand, weil
      // die Referenzen auf dasselbe Objekt zeigen)
      this.metadata = (Metadata)metadata.clone();
         
      // Metadaten sofort senden
      sendMetadata();
    }
   
    // Jetzt, wo wir die Metadaten haben, k�nnen wir das
    // Yellow Pages-System informieren 
    if (yp == null)
    {
      yp = new YellowPages(this, port);
      yp.start();
    }
  }

  /**
   * Puts <code>metadata</code> in the buffer.
   */
  protected void sendMetadata()
  {
    // Da diese Klasse auch manchmal die Metadaten eigenh�ndig
    // �ndert (Geschwindigkeitsmessung), m�ssen die Metadaten
    // nochmals geklont werden
    buffer.put(new MetadataPacket(getNextSeqNr(), getTimestamp(), (Metadata)metadata.clone()));
       
    lastSendTime = System.currentTimeMillis();
    lastSendTimeIsValid = true;
  }
 
  private void sendNullData()
  {
    sendData(NULL_BYTE);
  }
 
  private synchronized long getTimestamp()
  {
    if (startTimeIsValid)
    {
      return System.currentTimeMillis() - startTime;
    }
    else
    {
      startTime = System.currentTimeMillis();
      startTimeIsValid = true;
   
      return System.currentTimeMillis() - startTime;
    }
  }
 
  private synchronized long getNextSeqNr()
  {
    return nextSeqNr++;
  }
 
  // Required by YellowPages
  public Metadata getMetadata()
  {
    return metadata;
  }
 
  public void removeFromYP()
  {
    if (yp != null)
    {
      yp.shutdown();
    }
  }
}

TOP

Related Classes of p2pradio.sources.BroadcastBuffer

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.