/* ------------------ Client usage: java Client [Server hostname] [Server RTSP listening port] [Video file requested] ---------------------- */ import java.io.*; import java.net.*; import java.util.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.Timer; public class Client{ //GUI //---- JFrame f = new JFrame("Client"); JButton setupButton = new JButton("Setup"); JButton playButton = new JButton("Play"); JButton pauseButton = new JButton("Pause"); JButton tearButton = new JButton("Teardown"); JPanel mainPanel = new JPanel(); JPanel buttonPanel = new JPanel(); JLabel iconLabel = new JLabel(); ImageIcon icon; //RTP variables: //---------------- DatagramPacket rcvdp; //UDP packet received from the server DatagramSocket RTPsocket; //socket to be used to send and receive UDP packets static int RTP_RCV_PORT = 25000; //port where the client will receive the RTP packets Timer timer; //timer used to receive data from the UDP socket byte[] buf; //buffer used to store data received from the server //RTSP variables //---------------- //rtsp states final static int INIT = 0; final static int READY = 1; final static int PLAYING = 2; static int state; //RTSP state == INIT or READY or PLAYING Socket RTSPsocket; //socket used to send/receive RTSP messages //input and output stream filters static BufferedReader RTSPBufferedReader; static BufferedWriter RTSPBufferedWriter; static String VideoFileName; //video file to request to the server int RTSPSeqNb = 0; //Sequence number of RTSP messages within the session int RTSPid = 0; //ID of the RTSP session (given by the RTSP Server) final static String CRLF = "\r\n"; //Video constants: //------------------ static int MJPEG_TYPE = 26; //RTP payload type for MJPEG video //-------------------------- //Constructor //-------------------------- public Client() { //build GUI //-------------------------- //Frame f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); //Buttons buttonPanel.setLayout(new GridLayout(1,0)); buttonPanel.add(setupButton); buttonPanel.add(playButton); buttonPanel.add(pauseButton); buttonPanel.add(tearButton); setupButton.addActionListener(new setupButtonListener()); playButton.addActionListener(new playButtonListener()); pauseButton.addActionListener(new pauseButtonListener()); tearButton.addActionListener(new tearButtonListener()); //Image display label iconLabel.setIcon(null); //frame layout mainPanel.setLayout(null); mainPanel.add(iconLabel); mainPanel.add(buttonPanel); iconLabel.setBounds(0,0,380,280); buttonPanel.setBounds(0,280,380,50); f.getContentPane().add(mainPanel, BorderLayout.CENTER); f.setSize(new Dimension(390,370)); f.setVisible(true); //init timer //-------------------------- timer = new Timer(20, new timerListener()); timer.setInitialDelay(0); timer.setCoalesce(true); //allocate enough memory for the buffer used to receive data from the server buf = new byte[15000]; } //------------------------------------ //main //------------------------------------ public static void main(String argv[]) throws Exception { //Create a Client object Client theClient = new Client(); //get server RTSP port and IP address from the command line //------------------ int RTSP_server_port = Integer.parseInt(argv[1]); String ServerHost = argv[0]; InetAddress ServerIPAddr = InetAddress.getByName(ServerHost); //get video filename to request: VideoFileName = argv[2]; //Establish a TCP connection with the server to exchange RTSP messages //------------------ theClient.RTSPsocket = new Socket(ServerIPAddr, RTSP_server_port); //Set input and output stream filters: RTSPBufferedReader = new BufferedReader(new InputStreamReader(theClient.RTSPsocket.getInputStream()) ); RTSPBufferedWriter = new BufferedWriter(new OutputStreamWriter(theClient.RTSPsocket.getOutputStream()) ); //init RTSP state: state = INIT; } //------------------------------------ //Handler for buttons //------------------------------------ //............. //TO COMPLETE //............. //Handler for Setup button //----------------------- class setupButtonListener implements ActionListener{ public void actionPerformed(ActionEvent e){ //System.out.println("Setup Button pressed !"); if (state == INIT) { //Init non-blocking RTPsocket that will be used to receive data try{ //construct a new DatagramSocket to receive RTP packets from the server, on port RTP_RCV_PORT //RTPsocket = ... //set TimeOut value of the socket to 5msec. //.... } catch (SocketException se) { System.out.println("Socket exception: "+se); System.exit(0); } //init RTSP sequence number RTSPSeqNb = 1; //Send SETUP message to the server send_RTSP_request("SETUP"); //Wait for the response if (parse_server_response() != 200) System.out.println("Invalid Server Response"); else { //change RTSP state and print new state //state = .... //System.out.println("New RTSP state: ...."); } }//else if state != INIT then do nothing } } //Handler for Play button //----------------------- class playButtonListener implements ActionListener { public void actionPerformed(ActionEvent e){ //System.out.println("Play Button pressed !"); if (state == READY) { //increase RTSP sequence number //..... //Send PLAY message to the server send_RTSP_request("PLAY"); //Wait for the response if (parse_server_response() != 200) System.out.println("Invalid Server Response"); else { //change RTSP state and print out new state //..... // System.out.println("New RTSP state: ...") //start the timer timer.start(); } }//else if state != READY then do nothing } } //Handler for Pause button //----------------------- class pauseButtonListener implements ActionListener { public void actionPerformed(ActionEvent e){ //System.out.println("Pause Button pressed !"); if (state == PLAYING) { //increase RTSP sequence number //........ //Send PAUSE message to the server send_RTSP_request("PAUSE"); //Wait for the response if (parse_server_response() != 200) System.out.println("Invalid Server Response"); else { //change RTSP state and print out new state //........ //System.out.println("New RTSP state: ..."); //stop the timer timer.stop(); } } //else if state != PLAYING then do nothing } } //Handler for Teardown button //----------------------- class tearButtonListener implements ActionListener { public void actionPerformed(ActionEvent e){ //System.out.println("Teardown Button pressed !"); //increase RTSP sequence number // .......... //Send TEARDOWN message to the server send_RTSP_request("TEARDOWN"); //Wait for the response if (parse_server_response() != 200) System.out.println("Invalid Server Response"); else { //change RTSP state and print out new state //........ //System.out.println("New RTSP state: ..."); //stop the timer timer.stop(); //exit System.exit(0); } } } //------------------------------------ //Handler for timer //------------------------------------ class timerListener implements ActionListener { public void actionPerformed(ActionEvent e) { //Construct a DatagramPacket to receive data from the UDP socket rcvdp = new DatagramPacket(buf, buf.length); try{ //receive the DP from the socket: RTPsocket.receive(rcvdp); //create an RTPpacket object from the DP RTPpacket rtp_packet = new RTPpacket(rcvdp.getData(), rcvdp.getLength()); //print important header fields of the RTP packet received: System.out.println("Got RTP packet with SeqNum # "+rtp_packet.getsequencenumber()+" TimeStamp "+rtp_packet.gettimestamp()+" ms, of type "+rtp_packet.getpayloadtype()); //print header bitstream: rtp_packet.printheader(); //get the payload bitstream from the RTPpacket object int payload_length = rtp_packet.getpayload_length(); byte [] payload = new byte[payload_length]; rtp_packet.getpayload(payload); //get an Image object from the payload bitstream Toolkit toolkit = Toolkit.getDefaultToolkit(); Image image = toolkit.createImage(payload, 0, payload_length); //display the image as an ImageIcon object icon = new ImageIcon(image); iconLabel.setIcon(icon); } catch (InterruptedIOException iioe){ //System.out.println("Nothing to read"); } catch (IOException ioe) { System.out.println("Exception caught: "+ioe); } } } //------------------------------------ //Parse Server Response //------------------------------------ private int parse_server_response() { int reply_code = 0; try{ //parse status line and extract the reply_code: String StatusLine = RTSPBufferedReader.readLine(); //System.out.println("RTSP Client - Received from Server:"); System.out.println(StatusLine); StringTokenizer tokens = new StringTokenizer(StatusLine); tokens.nextToken(); //skip over the RTSP version reply_code = Integer.parseInt(tokens.nextToken()); //if reply code is OK get and print the 2 other lines if (reply_code == 200) { String SeqNumLine = RTSPBufferedReader.readLine(); System.out.println(SeqNumLine); String SessionLine = RTSPBufferedReader.readLine(); System.out.println(SessionLine); //if state == INIT gets the Session Id from the SessionLine tokens = new StringTokenizer(SessionLine); tokens.nextToken(); //skip over the Session: RTSPid = Integer.parseInt(tokens.nextToken()); } } catch(Exception ex) { System.out.println("Exception caught: "+ex); System.exit(0); } return(reply_code); } //------------------------------------ //Send RTSP Request //------------------------------------ //............. //TO COMPLETE //............. private void send_RTSP_request(String request_type) { try{ //Use the RTSPBufferedWriter to write to the RTSP socket //write the request line: //RTSPBufferedWriter.write(...); //write the CSeq line: //...... //check if request_type is equal to "SETUP" and in this case write the Transport: line advertising to the server the port used to receive the RTP packets RTP_RCV_PORT //if .... //otherwise, write the Session line from the RTSPid field //else .... RTSPBufferedWriter.flush(); } catch(Exception ex) { System.out.println("Exception caught: "+ex); System.exit(0); } } }//end of Class Client