/*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* 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 version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.mmedia.rtsp;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.ByteArrayOutputStream;
import com.sun.j2me.log.Logging;
import com.sun.j2me.log.LogChannels;
/**
* RtspConnectionBase is a portable base for RtspConnection platform-specific
* classes that represent a TCP/IP connection to an RTSP Server.
*/
public abstract class RtspConnectionBase extends Thread implements Runnable {
/**
* Flag inidicating whether the connection to
* the RTSP Server is alive.
*/
protected boolean connectionIsAlive = false;
protected InputStream is = null;
protected OutputStream os = null;
protected RtspDS ds = null;
/** Platform-specific implementations override this method
* to create 'is' and 'os' objects
*/
protected abstract void openStreams(RtspUrl url) throws IOException;
protected void closeStreams() {
if (null != is) {
try {
is.close();
} catch (IOException e) {
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION, LogChannels.LC_MMAPI,
"IOException in RtspConnection.closeStreams(): " + e.getMessage());
}
}
is = null;
}
if (null != os) {
try {
os.close();
} catch (IOException e) {
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION, LogChannels.LC_MMAPI,
"IOException in RtspConnection.closeStreams(): " + e.getMessage());
}
}
os = null;
}
}
/** Creates a new RTSP connection.
*
* @param url RTSP URL object
* @exception IOException Throws and IOException if a connection
* to the RTSP server cannot be established.
*/
public RtspConnectionBase(RtspDS ds) throws IOException {
try {
openStreams(ds.getUrl());
} catch (IOException e) {
throw e;
}
if (null == is) throw new IOException("InputStream creation failed");
if (null == os) throw new IOException("OutputStream creation failed");
connectionIsAlive = true;
this.ds = ds;
start();
}
/**
* Sends a message to the RTSP server.
*
* @param message A byte array containing an RTSP message.
* @return Returns true, if the message was sent
* successfully, otherwise false.
*/
public boolean sendData(byte[] message) {
try {
os.write(message);
os.flush();
return true;
} catch (IOException e) {
return false;
}
}
/**
* The main processing loop for incoming RTSP messages.
*/
public void run() {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int ch0 = 0;
int ch1 = 0;
int ch2 = 0;
int ch3 = 0;
while (connectionIsAlive) {
try {
ch3 = ch2;
ch2 = ch1;
ch1 = ch0;
ch0 = is.read();
if (-1 != ch0) {
baos.write(ch0);
if ('\r' == ch1 && '\n' == ch0 &&
'\r' == ch3 && '\n' == ch2) {
// message header is completely received
String header = new String(baos.toByteArray());
int content_length = getContentLength(header);
for (int i = 0; i < content_length; i++) {
ch0 = is.read();
if (-1 != ch0) {
baos.write(ch0);
} else {
connectionIsAlive = false;
break;
}
}
// whole message is completely received
ds.processIncomingMessage(baos.toByteArray());
baos.reset();
}
} else {
connectionIsAlive = false;
}
} catch (Exception e) {
connectionIsAlive = false;
}
}
}
/**
* Gets the content length of an RTSP message.
*
* @param msg_header The RTSP message header.
* @return Returns the content length in bytes.
*/
private static int getContentLength(String msg_header) {
int length;
int start = msg_header.indexOf("Content-length");
if (start == -1) {
// fix for QTSS:
start = msg_header.indexOf("Content-Length");
}
if (start == -1) {
length = 0;
} else {
start = msg_header.indexOf(':', start) + 2;
int end = msg_header.indexOf('\r', start);
String length_str = msg_header.substring(start, end);
length = Integer.parseInt(length_str);
}
return length;
}
/**
* Closes the RTSP connection.
*/
public void close() {
connectionIsAlive = false;
closeStreams();
}
/**
* Indicates whether the connection to the RTSP server
* is alive.
*
* @return Returns true, if the connection is alive, false otherwise.
*/
public boolean connectionIsAlive() {
return connectionIsAlive;
}
}