/*
* Copyright (C) 2005 Luca Veltri - University of Parma - Italy
*
* This source code 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 source code 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 source code; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author(s):
* Luca Veltri (luca.veltri@unipr.it)
*/
package local.media;
import org.zoolu.net.UdpPacket;
import org.zoolu.net.UdpSocket;
import org.zoolu.net.IpAddress;
import java.io.InputStream;
/** UdpStreamSender is a generic stream sender.
* It takes an InputStream and sends it through UDP.
*/
public class UdpStreamSender extends Thread
{
/** Whether debug mode */
private static final boolean DEBUG=true;
/** The InputStream */
InputStream input_stream=null;
/** The UdpSocket */
UdpSocket udp_socket=null;
/** Payload type */
int p_type;
/** Number of frame per second */
long frame_rate;
/** Number of bytes per frame */
int frame_size;
/** Whether the socket has been created here */
boolean socket_is_local=false;
/** Whether it works synchronously with a local clock, or it it acts as slave of the InputStream */
boolean do_sync=true;
/** Whether it is running */
boolean running=false;
/** Constructs a UdpStreamSender.
* @param input_stream the stream source
* @param do_sync whether time synchronization must be performed by the UdpStreamSender,
* or it is performed by the InputStream (e.g. the system audio input)
* @param frame_rate the frame rate, i.e. the number of frames that should be sent per second;
* it is used to calculate the nominal packet time and,in case of do_sync==true,
the next departure time
* @param frame_size the size of the payload
* @param dest_addr the destination address
* @param dest_port the destination port */
public UdpStreamSender(InputStream input_stream, boolean do_sync, long frame_rate, int frame_size, String dest_addr, int dest_port)
{ init(input_stream,do_sync,frame_rate,frame_size,null,dest_addr,dest_port);
}
/** Constructs a UdpStreamSender.
* @param input_stream the stream to be sent
* @param do_sync whether time synchronization must be performed by the UdpStreamSender,
* or it is performed by the InputStream (e.g. the system audio input)
* @param frame_rate the frame rate, i.e. the number of frames that should be sent per second;
* it is used to calculate the nominal packet time and,in case of do_sync==true,
the next departure time
* @param frame_size the size of the payload
* @param src_socket the socket used to send the UDP packet
* @param dest_addr the destination address
* @param dest_port the thestination port */
public UdpStreamSender(InputStream input_stream, boolean do_sync, long frame_rate, int frame_size, UdpSocket src_socket, String dest_addr, int dest_port)
{ init(input_stream,do_sync,frame_rate,frame_size,src_socket,dest_addr,dest_port);
}
/** Inits the UdpStreamSender */
private void init(InputStream input_stream, boolean do_sync, long frame_rate, int frame_size, UdpSocket src_socket, String dest_addr, int dest_port)
{
this.input_stream=input_stream;
this.frame_rate=frame_rate;
this.frame_size=frame_size;
this.do_sync=do_sync;
try
{ if (src_socket==null)
{ udp_socket=new UdpSocket();
socket_is_local=true;
}
else
{ udp_socket=src_socket;
socket_is_local=false;
}
}
catch (Exception e) { e.printStackTrace(); }
}
/** Whether is running */
public boolean isRunning()
{ return running;
}
/** Stops running */
public void halt()
{ running=false;
}
/** Runs it in a new Thread. */
public void run()
{
if (udp_socket==null || input_stream==null) return;
//else
byte[] buffer=new byte[frame_size];
UdpPacket udp_packet=new UdpPacket(buffer,0);
long time=0;
long start_time=System.currentTimeMillis();
long byte_rate=frame_rate*frame_size;
running=true;
if (DEBUG) println("Reading blocks of "+(buffer.length)+" bytes");
try
{ while (running)
{
//if (DEBUG) System.out.print("o");
int num=input_stream.read(buffer,12,buffer.length);
//if (DEBUG) System.out.print("*");
if (num>0)
{ udp_packet.setLength(num);
udp_socket.send(udp_packet);
// update rtp timestamp (in milliseconds)
time+=(num*1000)/byte_rate;
// wait fo next departure
if (do_sync)
{ long frame_time=start_time+time-System.currentTimeMillis();
// wait before next departure..
try { Thread.sleep(frame_time); } catch (Exception e) {}
}
}
else
if (num<0)
{ println("Error reading from InputStream");
running=false;
}
}
}
catch (Exception e) { running=false; e.printStackTrace(); }
//if (DEBUG) println("rtp time: "+time);
//if (DEBUG) println("real time: "+(System.currentTimeMillis()-start_time));
// close UdpSocket
if (socket_is_local && udp_socket!=null) udp_socket.close();
// free all
input_stream=null;
udp_socket=null;
if (DEBUG) println("udp sender terminated");
}
/** Debug output */
private static void println(String str)
{ System.out.println("UdpStreamSender: "+str);
}
}