SamsungRemoteSession.java
Go to the documentation of this file.
00001 package org.rosmultimedia.player.samsung.driver;
00002 
00003 import java.io.BufferedWriter;
00004 import java.io.IOException;
00005 import java.io.InputStream;
00006 import java.io.InputStreamReader;
00007 import java.io.OutputStreamWriter;
00008 import java.io.Reader;
00009 import java.io.StringWriter;
00010 import java.io.Writer;
00011 import java.net.InetAddress;
00012 import java.net.InetSocketAddress;
00013 import java.net.Socket;
00014 import java.net.SocketException;
00015 import java.net.UnknownHostException;
00016 import java.util.Arrays;
00017 import java.util.concurrent.TimeoutException;
00018 
00019 import org.apache.commons.codec.binary.Base64;
00020 import org.rosmultimedia.player.samsung.SamsungCommand;
00021 import org.rosmultimedia.player.samsung.SamsungTvNode;
00022 
00030 public class SamsungRemoteSession {
00031 
00032         public static final String REMOTE               = "Alfred";     // REMOTE name
00033         public static final String APP          = "ros.samsung.tv";             // iphone..iapp.samsung
00034         private static final String TV  = "LE32C650";   // iphone.LE32C650.iapp.samsung
00035 
00036         private static final char[] ALLOWED_BYTES = new char[] {0x64, 0x00, 0x01, 0x00};
00037         private static final char[] DENIED_BYTES = new char[] {0x64, 0x00, 0x00, 0x00};
00038         private static final char[] TIMEOUT_BYTES = new char[] {0x65, 0x00};
00039 
00040         public static final String ALLOWED = "ALLOWED";
00041         public static final String DENIED = "DENIED";
00042         public static final String TIMEOUT = "TIMEOUT";
00043 
00044         private transient String applicationName;
00045         private transient String uniqueId;
00046         private transient String host;
00047         private transient int port;
00048 
00049         private transient Socket socket;
00050 
00051         private transient InputStreamReader reader;
00052 
00053         private transient BufferedWriter writer;
00054 
00055         private transient SamsungTvNode node;
00056 
00057         public SamsungRemoteSession(SamsungTvNode samsungTvNode) {
00058 
00059         }
00060 
00061         private SamsungRemoteSession(
00062                         final SamsungTvNode samsungTvNode,
00063                         final String applicationName,
00064                         final String uniqueId,
00065                         final String host,
00066                         final int port) {
00067                 this.applicationName = applicationName;
00068                 this.uniqueId = uniqueId;
00069 
00070                 if (this.uniqueId == null) {
00071                         this.uniqueId = "";
00072                 }
00073 
00074                 this.host = host;
00075                 this.port = port;
00076 
00077                 this.node = samsungTvNode;
00078         }
00079 
00080         public static SamsungRemoteSession create(
00081                         final SamsungTvNode samsungTvNode,
00082                         final String applicationName,
00083                         final String uniqueId,
00084                         final String host,
00085                         final int port)
00086                                         throws IOException, Exception, TimeoutException {
00087 
00088                 SamsungRemoteSession session = new SamsungRemoteSession(
00089                                 samsungTvNode,
00090                                 applicationName,
00091                                 uniqueId,
00092                                 host,
00093                                 port);
00094 
00095                 final String result = session.initialize();
00096                 if (!result.equals(ALLOWED)) {
00097                         if (result.equals(DENIED)) {
00098                                 throw new Exception("Connection Denied!"); //ConnectionDenied
00099                         } else
00100 
00101                         if (result.equals(TIMEOUT)) {
00102                                 throw new TimeoutException();
00103                         }
00104                 }
00105 
00106                 // for now we just assume to be connected
00107                 return session;
00108         }
00109 
00110         private String initialize() throws UnknownHostException, IOException {
00111                 this.node.logD("Creating socket for host " + host + " on port " + port);
00112 
00113                 this.socket = new Socket();
00114                 this.socket.connect(new InetSocketAddress(host, port), 5000);
00115 
00116                 this.node.logD("Socket successfully created and connected");
00117                 final InetAddress localAddress = this.socket.getLocalAddress();
00118                 this.node.logD("Local address is " + localAddress.getHostAddress());
00119 
00120                 this.node.logD("Sending registration message");
00121                 this.writer = new BufferedWriter(
00122                                 new OutputStreamWriter(this.socket.getOutputStream()));
00123 
00124                 this.writer.append((char)0x00);
00125                 writeText(writer, APP);
00126                 writeText(writer, getRegistrationPayload(localAddress.getHostAddress()));
00127                 this.writer.flush();
00128 
00129                 final InputStream inputStream = socket.getInputStream();
00130                 reader = new InputStreamReader(inputStream);
00131                 final String result = readRegistrationReply(reader);
00132                 //sendPart2();
00133 
00134                 int dataSize;
00135                 while ((dataSize = inputStream.available()) > 0) {
00136                         inputStream.skip(dataSize);
00137                 }
00138 
00139                 return result;
00140         }
00141 
00142         @SuppressWarnings("unused")
00143         private void sendPart2() throws IOException {
00144                 this.writer.append((char) 0x00);
00145                 writeText(writer, TV);
00146                 writeText(writer, new String(new char[] { 0xc8, 0x00 }));
00147         }
00148 
00149         private void checkConnection() throws UnknownHostException, IOException {
00150                 if (socket.isClosed() || !socket.isConnected()) {
00151                         this.node.logI("Connection closed, trying to reconnect...");
00152 
00153                         try {
00154                                 this.socket.close();
00155                         } catch (IOException e) {
00156                                 // Ignore any exception
00157                         }
00158 
00159                         this.initialize();
00160                         this.node.logI("Reconnected to server");
00161                 }
00162         }
00163 
00164         public void destroy() {
00165                 try {
00166                         socket.close();
00167                 } catch (IOException e) {
00168                         // Ignore exception
00169                 }
00170         }
00171 
00172         private String readRegistrationReply(Reader reader) throws IOException {
00173                 String result;
00174                 this.node.logD("Reading registration reply");
00175                 reader.read(); // Unknown byte 0x02
00176                 final String text1 = readText(reader); // Read
00177                                                                                         // "unknown.livingroom.iapp.samsung"
00178                                                                                         // for new RC and "iapp.samsung" for
00179                                                                                         // already registered RC
00180                 this.node.logD("Received ID: " + text1);
00181                 final char[] resultSeq = readCharArray(reader); // Read result sequence
00182                 if (Arrays.equals(resultSeq, ALLOWED_BYTES)) {
00183                         this.node.logD("Registration successfull");
00184                         result = ALLOWED;
00185                 } else if (Arrays.equals(resultSeq, DENIED_BYTES)) {
00186                         this.node.logD("Registration denied");
00187                         result = DENIED;
00188                 } else if (Arrays.equals(resultSeq, TIMEOUT_BYTES)) {
00189                         this.node.logD("Registration timed out");
00190                         result = TIMEOUT;
00191                 } else {
00192                         final StringBuilder builder = new StringBuilder();
00193 
00194                         for (final char subSeq : resultSeq) {
00195                                 builder.append( Integer.toHexString(subSeq) );
00196                                 builder.append( ' ' );
00197                         }
00198 
00199                         result = builder.toString();
00200                         this.node.logE("Received unknown registration reply: " + result);
00201                 }
00202 
00203                 return result;
00204         }
00205 
00206         private String getRegistrationPayload(final String ip) throws IOException {
00207                 final StringWriter writer = new StringWriter();
00208                 writer.append((char) 0x64);
00209                 writer.append((char) 0x00);
00210                 writeBase64Text(writer, ip);
00211                 writeBase64Text(writer, uniqueId);
00212                 writeBase64Text(writer, applicationName);
00213                 writer.flush();
00214                 return writer.toString();
00215         }
00216 
00217         private static String readText(final Reader reader) throws IOException {
00218                 final char[] buffer = readCharArray(reader);
00219                 return new String(buffer);
00220         }
00221 
00222         private static char[] readCharArray(final Reader reader) throws IOException {
00223                 if (reader.markSupported()) {
00224                         reader.mark(1024);
00225                 }
00226 
00227                 final int length = reader.read();
00228                 final int delimiter = reader.read();
00229                 if (delimiter != 0) {
00230                         if (reader.markSupported()) {
00231                                 reader.reset();
00232                         }
00233                         throw new IOException("Unsupported reply exception");
00234                 }
00235 
00236                 final char[] buffer = new char[length];
00237                 reader.read(buffer);
00238                 return buffer;
00239         }
00240 
00241         private static Writer writeText(final Writer writer, final String text)
00242                         throws IOException {
00243 
00244                 return writer
00245                                 .append((char) text.length())
00246                                 .append((char) 0x00).append(text);
00247         }
00248 
00249         private static Writer writeBase64Text(final Writer writer, final String text)
00250                         throws IOException {
00251                 final String b64 = new String(Base64.encodeBase64(text.getBytes()));
00252                 return writeText(writer, b64);
00253         }
00254 
00255         private void internalSendKey(final SamsungCommand key) throws IOException {
00256                 this.writer.append((char) 0x00);
00257                 writeText(this.writer, TV);
00258                 writeText(this.writer, this.getKeyPayload(key));
00259                 this.writer.flush();
00260 
00261                 //int i =
00262                 this.reader.read(); // Unknown byte 0x00
00263                 //String t =
00264                 readText(this.reader); // Read "iapp.samsung"
00265                 //char[] c =
00266                 readCharArray(this.reader);
00267         }
00268 
00269         public void sendKey(final SamsungCommand key) throws IOException {
00270                 this.node.logD("Sending key " + key.getValue() + "...");
00271                 this.checkConnection();
00272 
00273                 try {
00274                         this.internalSendKey(key);
00275                 } catch (SocketException e) {
00276                         this.node.logE("Could not send key because the server closed the connection. Reconnecting...");
00277                         this.initialize();
00278 
00279                         this.node.logI("Sending key " + key.getValue() + " again...");
00280                         this.internalSendKey(key);
00281                 }
00282 
00283                 this.node.logI("Successfully sent key " + key.getValue());
00284         }
00285 
00286         private String getKeyPayload(final SamsungCommand key) throws IOException {
00287                 final StringWriter writer = new StringWriter();
00288                 writer.append((char) 0x00);
00289                 writer.append((char) 0x00);
00290                 writer.append((char) 0x00);
00291 
00292                 writeBase64Text(writer, key.getValue());
00293                 writer.flush();
00294 
00295                 return writer.toString();
00296         }
00297 
00298         private void internalSendText(final String text) throws IOException {
00299                 this.writer.append((char) 0x01);
00300                 writeText(this.writer, TV);
00301                 writeText(this.writer, this.getTextPayload(text));
00302                 this.writer.flush();
00303 
00304                 if (!this.reader.ready()) {
00305                         return;
00306                 }
00307 
00308                 //final int i =
00309                 this.reader.read(); // Unknown byte 0x02
00310                 //final String t =
00311                 readText(this.reader); // Read "iapp.samsung"
00312                 //final char[] c =
00313                 readCharArray(this.reader);
00314         }
00315 
00316         public void sendText(final String text) throws IOException {
00317                 this.node.logD("Sending text \"" + text + "\"...");
00318                 this.checkConnection();
00319 
00320                 try {
00321                         this.internalSendText(text);
00322                 } catch (SocketException e) {
00323                         this.node.logE("Could not send key because the server closed the connection. Reconnecting...");
00324                         this.initialize();
00325                         this.node.logI("Sending text \"" + text + "\" again...");
00326                         this.internalSendText(text);
00327                 }
00328                 this.node.logD("Successfully sent text \"" + text + "\"");
00329         }
00330 
00331         private String getTextPayload(final String text) throws IOException {
00332                 final StringWriter writer = new StringWriter();
00333                 writer.append((char) 0x01);
00334                 writer.append((char) 0x00);
00335                 writeBase64Text(writer, text);
00336                 writer.flush();
00337                 return writer.toString();
00338         }
00339 
00340 }


smarthome_media_samsungtv_driver
Author(s): Mickael Gaillard , Erwan Le Huitouze
autogenerated on Thu Jun 6 2019 21:03:50