fyhertz / libstreaming

A solution for streaming H.264, H.263, AMR, AAC using RTP on Android
Apache License 2.0
3.49k stars 1.08k forks source link

GoodbyeReport and END_OF_STREAM extension #217

Open dcerisano opened 8 years ago

dcerisano commented 8 years ago

Just posting a mod of SenderReport that handles the GoodbyeReport packet (type 203). Needed a way to stop clients from the server, and this seems to be the established method Tested with VLC and ff/avplay , and it seems to work ...

Not yet comfortable with RTSP, so not requesting a pull.

There is also the END_OF_STREAM Request extension that seems better suited to stopping clients, but not sure how many players have implemented it.

import java.io.IOException;
import java.io.OutputStream;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
/**
 * Implementation of Sender Report RTCP packets.
 */
public class GoodbyeReport {
    public  final int MTU = 1500;
    private  final int PACKET_LENGTH = 8;
private  MulticastSocket usock;
private  DatagramPacket upack;
private  int mTransport;
private  OutputStream mOutputStream = null;
private  byte[] mBuffer = new byte[MTU];
private  int mSSRC, mPort = -1;
public GoodbyeReport(int ssrc) throws IOException {
    super();
    GoodbyeReport.mSSRC = ssrc;
}

public GoodbyeReport() {
    mTransport = RtpSocket.TRANSPORT_UDP;
    //         0                   1                   2                   3
    //         0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    //        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //        |V=2|P|    SC   |   PT=BYE=203  |             length            |
    //        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //        |                           SSRC/CSRC                           |
    //        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+     
    mBuffer[0] = (byte) Integer.parseInt("10000000",2);

    /* Packet Type PT */
    mBuffer[1] = (byte) 203;

    /* Byte 2,3          ->  Length                          */
    setLong(PACKET_LENGTH, 2, 4);

    /* Byte 4,5,6,7      ->  SSRC                            */
    try {
        usock = new MulticastSocket();
    } catch (IOException e) {
        // Very unlikely to happen. Means that all UDP ports are already being used
        throw new RuntimeException(e.getMessage());
    }
    upack = new DatagramPacket(mBuffer, 1);
}

public void close() {
    usock.close();
}

public static void goodbye() throws IOException {
    send();
}

public void setSSRC(int ssrc) {
    GoodbyeReport.mSSRC = ssrc; 
    setLong(ssrc,4,8);
}

public void setDestination(InetAddress dest, int dport) {
    mTransport = RtpSocket.TRANSPORT_UDP;
    mPort = dport;
    upack.setPort(dport);
    upack.setAddress(dest);
}

/**
 * If a TCP is used as the transport protocol for the RTP session,
 * the output stream to which RTP packets will be written to must
 * be specified with this method.
 */ 
public void setOutputStream(OutputStream os) {
    mTransport = RtpSocket.TRANSPORT_UDP;
    mOutputStream = os;
}   

public int getPort() {
    return mPort;
}

public int getLocalPort() {
    return usock.getLocalPort();
}

public int getSSRC() {
    return mSSRC;
}

private void setLong(long n, int begin, int end) {
    for (end--; end >= begin; end--) {
        mBuffer[end] = (byte) (n % 256);
        n >>= 8;
    }
}   

private  void send() throws IOException {
        try {
            mOutputStream.write(mBuffer, 0, PACKET_LENGTH);
        } catch (Exception e) {}
  }
 }