RTSPConnection.java
上传用户:gmxazy
上传日期:2022-06-06
资源大小:70k
文件大小:7k
源码类别:

J2ME

开发平台:

Java

  1. import java.io.*;
  2. import java.util.*;
  3. import javax.microedition.io.*;
  4. /**
  5.  * Handles a single RTSP client.
  6.  */
  7. public class RTSPConnection implements Runnable {
  8. /**
  9.  * Connection to the client.
  10.  */
  11. private SocketConnection client;
  12. /**
  13.  * IP address/domain name of the server.
  14.  */
  15. private String serverAddr;
  16. /**
  17.  * IP address/domain name of the client.
  18.  */
  19. private String clientAddr;
  20. /**
  21.  * Output stream to the client.
  22.  */
  23. private OutputStream send;
  24. /**
  25.  * Input stream from the client.
  26.  */
  27. private InputStream recv;
  28. /**
  29.  * String buffer where lines of text are built up.
  30.  */
  31. private StringBuffer buf = new StringBuffer(256);
  32. /**
  33.  * Last sequence number (from the client request).
  34.  */
  35. private int cseq = 0;
  36. /**
  37.  * Port the server will be broadcasting from.
  38.  */
  39. private int audioPort = 0;
  40. /** 
  41.  * Port the client is listening on (taken from the Transport header in
  42.  * the client request).
  43.  */
  44. private int clientPort = 0;
  45. /**
  46.  * Creates a new instance to handle a client.
  47.  */
  48. public RTSPConnection(SocketConnection client) throws IOException {
  49. this.client = client;
  50. serverAddr  = client.getLocalAddress();
  51. clientAddr  = client.getAddress();
  52. send = client.openOutputStream();
  53. recv = client.openInputStream();
  54. new Thread(this).start();
  55. }
  56. /**
  57.  * Reads the next line of text from <code>recv</code>, up to and
  58.  * including the newline char. If there are no bytes to be read a <code>
  59.  * null</code> is returned instead.
  60.  *
  61.  * @returns the next line or <code>null</code>
  62.  */
  63. public String readLine() throws IOException {
  64. buf.setLength(0);
  65. while (true) {
  66. int val = recv.read();
  67. if (val == -1) {
  68. break;
  69. }
  70. if (val == 'r') {
  71. continue;
  72. }
  73. buf.append((char) val);
  74. if (val == 'n') {
  75. break;
  76. }
  77. }
  78. if (buf.length() == 0) {
  79. return null;
  80. } else {
  81. return buf.toString();
  82. }
  83. }
  84. /**
  85.  * Writes a line of ASCII text to <code>send</code> terminated with CRLF.
  86.  */
  87. public void writeLine(String line) throws IOException {
  88. for (int n = 0; n < line.length(); n++) {
  89. send.write(line.charAt(n));
  90. }
  91. send.write('r');
  92. send.write('n');
  93. }
  94. /**
  95.  * Writes a line of ASCII text to <code>send</code> terminated with CRLF.
  96.  */
  97. public void writeLine(StringBuffer line) throws IOException {
  98. for (int n = 0; n < line.length(); n++) {
  99. send.write(line.charAt(n));
  100. }
  101. send.write('r');
  102. send.write('n');
  103. }
  104. /**
  105.  * Appends text to the buffer terminated with CFLF.
  106.  */
  107. public void appendBuf(String line) {
  108. buf.append(line);
  109. buf.append('r');
  110. buf.append('n');
  111. }
  112. /**
  113.  * Writes a static SDP to <code>send</code>.
  114.  */
  115. public void writeSDP() throws IOException {
  116. buf.setLength(0);
  117. appendBuf("v=0");
  118. appendBuf("o=- 0 0 IN IP4 " + serverAddr);
  119. appendBuf("s=AudioStream");
  120. appendBuf("i=<No author>");
  121. appendBuf("t=0 0");
  122. appendBuf("a=tool:RTSP Demo");
  123. appendBuf("a=type:broadcast");
  124. appendBuf("a=control:*");
  125. appendBuf("a=range:npt=now-");
  126. appendBuf("m=audio 0 RTP/AVP 96");
  127. appendBuf("c=IN IP4 0.0.0.0");
  128. appendBuf("a=rtpmap:96 L8/22050/1"); // this is the audio type: 8-bit PCM, 22k, mono
  129. appendBuf("a=ptime:40");
  130. appendBuf("a=control:track1");
  131. //appendBuf("a=AvgBitRate:integer;22350");
  132. //appendBuf("a=AvgPacketSize:integer;894");
  133. //appendBuf("a=MaxBitRate:integer;22350");
  134. //appendBuf("a=MaxPacketSize:integer;894");
  135. writeLine("Content-Type: application/sdp");
  136. writeLine("Content-Length: " + (buf.length() + 4));
  137. writeLine("");
  138. writeLine(buf);
  139. }
  140. /**
  141.  * Sends the common 200 response to the client along with a sequence
  142.  * number.
  143.  */
  144. public void writeOK() throws IOException {
  145. writeLine("RTSP/1.0 200 OK");
  146. writeLine("CSeq: " + cseq);
  147. }
  148. /**
  149.  * Handles the connection with a single client.
  150.  */
  151. public void run() {
  152. AudioStream stream = null;
  153. try {
  154. loop: while (true) {
  155. String line = readLine();
  156. dprint(line);
  157. if (line == null) {
  158. break;
  159. }
  160. parseIncoming();
  161. switch (getCommand(line)) {
  162. case COMMAND_OPTIONS:
  163. writeOK();
  164. writeLine("Public: OPTIONS, DESCRIBE, SETUP, PLAY, PAUSE, TEARDOWN");
  165. break;
  166. case COMMAND_DESCRIBE:
  167. writeOK();
  168. writeLine("Content-Base: rtsp://" + serverAddr + ":8554/stream.wav/");
  169. writeSDP();
  170. break;
  171. case COMMAND_SETUP:
  172. if (stream == null) {
  173. stream = new AudioStream(-1);
  174. audioPort = stream.getPort();
  175. }
  176. writeOK();
  177. writeLine("Session: 1-0");
  178. writeLine("Transport: RTP/AVP;unicast;client_port=" + clientPort + "-" + (clientPort + 1)
  179. + ";server_port=" + audioPort + "-" + (audioPort + 1));
  180. break;
  181. case COMMAND_PLAY:
  182. writeOK();
  183. writeLine("Session: 1-0");
  184. writeLine("RTP-Info: url=rtsp://" + serverAddr + ":8554/stream.wav/track1;seq=0;");
  185. stream.play(clientAddr, clientPort);
  186. break;
  187. case COMMAND_PAUSE:
  188. writeOK();
  189. writeLine("Session: 1-0");
  190. stream.pause();
  191. break;
  192. case COMMAND_TEARDOWN:
  193. break loop;
  194. default:
  195. continue;
  196. }
  197. writeLine("");
  198. send.flush();
  199. }
  200. } catch (IOException e) {
  201. dprint(e);
  202. }
  203. dprint("Closing connectionn");
  204. stream.stop();
  205. try {
  206. send.close();
  207. recv.close();
  208. client.close();
  209. } catch (IOException e) {
  210. dprint(e);
  211. }
  212. }
  213. /**
  214.  * Reads the remainder of the client request and stores any interesting
  215.  * data (namely the sequence number and client port for now).
  216.  */
  217. private void parseIncoming() throws IOException {
  218. boolean hasCseq = false;
  219. while (true) {
  220. String line = readLine();
  221. dprint(line);
  222. if (line == null || line.equals("n")) {
  223. break;
  224. }
  225. if (line.indexOf("CSeq: ") == 0) {
  226. cseq = Integer.parseInt(line.substring(line.indexOf(':') + 1).trim());
  227. }
  228. if (line.indexOf("Transport: ") == 0) {
  229. int beg = line.indexOf("client_port=") + 12;
  230. if (beg < 0) {
  231. break;
  232. }
  233. int end = line.indexOf("-", beg);
  234. if (end < 0) {
  235. break;
  236. }
  237. clientPort = Integer.parseInt(line.substring(beg, end).trim());
  238. }
  239. }
  240. }
  241. public void dprint(Object obj) {
  242. System.out.print(obj);
  243. }
  244. /**
  245.  * List of RTSP commands supported.
  246.  */
  247. private static final Vector COMMANDS = new Vector(5);
  248. static {
  249. COMMANDS.addElement("OPTIONS ");
  250. COMMANDS.addElement("DESCRIBE ");
  251. COMMANDS.addElement("SETUP ");
  252. COMMANDS.addElement("PLAY ");
  253. COMMANDS.addElement("PAUSE ");
  254. COMMANDS.addElement("TEARDOWN ");
  255. }
  256. /*
  257.  * Command indices.
  258.  */
  259. private static final int COMMAND_OPTIONS  = 0;
  260. private static final int COMMAND_DESCRIBE = 1;
  261. private static final int COMMAND_SETUP    = 2;
  262. private static final int COMMAND_PLAY     = 3;
  263. private static final int COMMAND_PAUSE    = 4;
  264. private static final int COMMAND_TEARDOWN = 5;
  265. /**
  266.  * Returns a command index for a given string, or -1 if no match.
  267.  */
  268. private static int getCommand(String line) {
  269. for (int n = COMMANDS.size() - 1; n >= 0; n--) {
  270. if (line.indexOf((String) COMMANDS.elementAt(n)) == 0) {
  271. return n;
  272. }
  273. }
  274. return -1;
  275. }
  276. }