mirror of
https://github.com/moonlight-stream/moonlight-android.git
synced 2025-07-20 03:23:07 +00:00
Add implementation of http negotiation, handshake, control, and input packets
This commit is contained in:
parent
b263367528
commit
fcdc23eeb7
@ -7,7 +7,9 @@
|
|||||||
<uses-sdk
|
<uses-sdk
|
||||||
android:minSdkVersion="14"
|
android:minSdkVersion="14"
|
||||||
android:targetSdkVersion="18" />
|
android:targetSdkVersion="18" />
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
@ -23,6 +25,18 @@
|
|||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
<activity
|
||||||
|
android:name="com.limelight.Game"
|
||||||
|
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||||
|
android:label="@string/title_activity_game"
|
||||||
|
android:parentActivityName="com.limelight.Connection"
|
||||||
|
android:theme="@style/FullscreenTheme" >
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
|
android:value="com.limelight.Connection" />
|
||||||
|
</activity>
|
||||||
|
<service
|
||||||
|
android:name="com.limelight.RelayService"></service>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
@ -9,6 +9,17 @@ package com.limelight;
|
|||||||
|
|
||||||
public final class R {
|
public final class R {
|
||||||
public static final class attr {
|
public static final class attr {
|
||||||
|
/** <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"
|
||||||
|
or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".
|
||||||
|
*/
|
||||||
|
public static final int buttonBarButtonStyle=0x7f010001;
|
||||||
|
/** <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"
|
||||||
|
or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".
|
||||||
|
*/
|
||||||
|
public static final int buttonBarStyle=0x7f010000;
|
||||||
|
}
|
||||||
|
public static final class color {
|
||||||
|
public static final int black_overlay=0x7f040000;
|
||||||
}
|
}
|
||||||
public static final class dimen {
|
public static final class dimen {
|
||||||
/** Default screen margins, per the Android Design guidelines.
|
/** Default screen margins, per the Android Design guidelines.
|
||||||
@ -17,17 +28,24 @@ public final class R {
|
|||||||
screen margins) for sw720dp devices (e.g. 10" tablets) in landscape here.
|
screen margins) for sw720dp devices (e.g. 10" tablets) in landscape here.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
public static final int activity_horizontal_margin=0x7f040000;
|
public static final int activity_horizontal_margin=0x7f050000;
|
||||||
public static final int activity_vertical_margin=0x7f040001;
|
public static final int activity_vertical_margin=0x7f050001;
|
||||||
}
|
}
|
||||||
public static final class drawable {
|
public static final class drawable {
|
||||||
public static final int ic_launcher=0x7f020000;
|
public static final int ic_launcher=0x7f020000;
|
||||||
}
|
}
|
||||||
|
public static final class id {
|
||||||
|
public static final int videoView=0x7f080000;
|
||||||
|
}
|
||||||
public static final class layout {
|
public static final class layout {
|
||||||
public static final int activity_connection=0x7f030000;
|
public static final int activity_connection=0x7f030000;
|
||||||
|
public static final int activity_game=0x7f030001;
|
||||||
}
|
}
|
||||||
public static final class string {
|
public static final class string {
|
||||||
public static final int app_name=0x7f050000;
|
public static final int app_name=0x7f060000;
|
||||||
|
public static final int dummy_button=0x7f060002;
|
||||||
|
public static final int dummy_content=0x7f060003;
|
||||||
|
public static final int title_activity_game=0x7f060001;
|
||||||
}
|
}
|
||||||
public static final class style {
|
public static final class style {
|
||||||
/**
|
/**
|
||||||
@ -35,14 +53,17 @@ public final class R {
|
|||||||
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
|
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Theme customizations available in newer API levels can go in
|
Theme customizations available in newer API levels can go in
|
||||||
res/values-vXX/styles.xml, while customizations related to
|
res/values-vXX/styles.xml, while customizations related to
|
||||||
backward-compatibility can go here.
|
backward-compatibility can go here.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Base application theme for API 11+. This theme completely replaces
|
Base application theme for API 11+. This theme completely replaces
|
||||||
AppBaseTheme from res/values/styles.xml on API 11+ devices.
|
AppBaseTheme from res/values/styles.xml on API 11+ devices.
|
||||||
|
|
||||||
|
|
||||||
API 11 theme customizations can go here.
|
API 11 theme customizations can go here.
|
||||||
|
|
||||||
Base application theme for API 14+. This theme completely replaces
|
Base application theme for API 14+. This theme completely replaces
|
||||||
@ -51,10 +72,56 @@ public final class R {
|
|||||||
|
|
||||||
API 14 theme customizations can go here.
|
API 14 theme customizations can go here.
|
||||||
*/
|
*/
|
||||||
public static final int AppBaseTheme=0x7f060000;
|
public static final int AppBaseTheme=0x7f070000;
|
||||||
/** Application theme.
|
/** Application theme.
|
||||||
All customizations that are NOT specific to a particular API-level can go here.
|
All customizations that are NOT specific to a particular API-level can go here.
|
||||||
*/
|
*/
|
||||||
public static final int AppTheme=0x7f060001;
|
public static final int AppTheme=0x7f070001;
|
||||||
|
public static final int ButtonBar=0x7f070003;
|
||||||
|
public static final int ButtonBarButton=0x7f070004;
|
||||||
|
public static final int FullscreenActionBarStyle=0x7f070005;
|
||||||
|
public static final int FullscreenTheme=0x7f070002;
|
||||||
}
|
}
|
||||||
|
public static final class styleable {
|
||||||
|
/**
|
||||||
|
Declare custom theme attributes that allow changing which styles are
|
||||||
|
used for button bars depending on the API level.
|
||||||
|
?android:attr/buttonBarStyle is new as of API 11 so this is
|
||||||
|
necessary to support previous API levels.
|
||||||
|
|
||||||
|
<p>Includes the following attributes:</p>
|
||||||
|
<table>
|
||||||
|
<colgroup align="left" />
|
||||||
|
<colgroup align="left" />
|
||||||
|
<tr><th>Attribute</th><th>Description</th></tr>
|
||||||
|
<tr><td><code>{@link #ButtonBarContainerTheme_buttonBarButtonStyle com.limelight:buttonBarButtonStyle}</code></td><td></td></tr>
|
||||||
|
<tr><td><code>{@link #ButtonBarContainerTheme_buttonBarStyle com.limelight:buttonBarStyle}</code></td><td></td></tr>
|
||||||
|
</table>
|
||||||
|
@see #ButtonBarContainerTheme_buttonBarButtonStyle
|
||||||
|
@see #ButtonBarContainerTheme_buttonBarStyle
|
||||||
|
*/
|
||||||
|
public static final int[] ButtonBarContainerTheme = {
|
||||||
|
0x7f010000, 0x7f010001
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
<p>This symbol is the offset where the {@link com.limelight.R.attr#buttonBarButtonStyle}
|
||||||
|
attribute's value can be found in the {@link #ButtonBarContainerTheme} array.
|
||||||
|
|
||||||
|
|
||||||
|
<p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"
|
||||||
|
or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".
|
||||||
|
@attr name android:buttonBarButtonStyle
|
||||||
|
*/
|
||||||
|
public static final int ButtonBarContainerTheme_buttonBarButtonStyle = 1;
|
||||||
|
/**
|
||||||
|
<p>This symbol is the offset where the {@link com.limelight.R.attr#buttonBarStyle}
|
||||||
|
attribute's value can be found in the {@link #ButtonBarContainerTheme} array.
|
||||||
|
|
||||||
|
|
||||||
|
<p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"
|
||||||
|
or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".
|
||||||
|
@attr name android:buttonBarStyle
|
||||||
|
*/
|
||||||
|
public static final int ButtonBarContainerTheme_buttonBarStyle = 0;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
13
res/layout/activity_game.xml
Normal file
13
res/layout/activity_game.xml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="#0099cc"
|
||||||
|
tools:context=".Game" >
|
||||||
|
|
||||||
|
<VideoView
|
||||||
|
android:id="@+id/videoView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
@ -1,3 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
@ -8,4 +9,16 @@
|
|||||||
<!-- API 11 theme customizations can go here. -->
|
<!-- API 11 theme customizations can go here. -->
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="FullscreenTheme" parent="android:Theme.Holo">
|
||||||
|
<item name="android:actionBarStyle">@style/FullscreenActionBarStyle</item>
|
||||||
|
<item name="android:windowActionBarOverlay">true</item>
|
||||||
|
<item name="android:windowBackground">@null</item>
|
||||||
|
<item name="buttonBarStyle">?android:attr/buttonBarStyle</item>
|
||||||
|
<item name="buttonBarButtonStyle">?android:attr/buttonBarButtonStyle</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="FullscreenActionBarStyle" parent="android:Widget.Holo.ActionBar">
|
||||||
|
<item name="android:background">@color/black_overlay</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
14
res/values/attrs.xml
Normal file
14
res/values/attrs.xml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<resources>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Declare custom theme attributes that allow changing which styles are
|
||||||
|
used for button bars depending on the API level.
|
||||||
|
?android:attr/buttonBarStyle is new as of API 11 so this is
|
||||||
|
necessary to support previous API levels.
|
||||||
|
-->
|
||||||
|
<declare-styleable name="ButtonBarContainerTheme">
|
||||||
|
<attr name="buttonBarStyle" format="reference" />
|
||||||
|
<attr name="buttonBarButtonStyle" format="reference" />
|
||||||
|
</declare-styleable>
|
||||||
|
|
||||||
|
</resources>
|
5
res/values/colors.xml
Normal file
5
res/values/colors.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<resources>
|
||||||
|
|
||||||
|
<color name="black_overlay">#66000000</color>
|
||||||
|
|
||||||
|
</resources>
|
@ -2,5 +2,8 @@
|
|||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<string name="app_name">Limelight</string>
|
<string name="app_name">Limelight</string>
|
||||||
|
<string name="title_activity_game">Game</string>
|
||||||
|
<string name="dummy_button">Dummy Button</string>
|
||||||
|
<string name="dummy_content">DUMMY\nCONTENT</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
@ -17,4 +18,21 @@
|
|||||||
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
|
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="FullscreenTheme" parent="android:Theme.NoTitleBar">
|
||||||
|
<item name="android:windowContentOverlay">@null</item>
|
||||||
|
<item name="android:windowBackground">@null</item>
|
||||||
|
<item name="buttonBarStyle">@style/ButtonBar</item>
|
||||||
|
<item name="buttonBarButtonStyle">@style/ButtonBarButton</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="ButtonBar">
|
||||||
|
<item name="android:paddingLeft">2dp</item>
|
||||||
|
<item name="android:paddingTop">5dp</item>
|
||||||
|
<item name="android:paddingRight">2dp</item>
|
||||||
|
<item name="android:paddingBottom">0dp</item>
|
||||||
|
<item name="android:background">@android:drawable/bottom_bar</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="ButtonBarButton" />
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
30
src/com/limelight/Game.java
Normal file
30
src/com/limelight/Game.java
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package com.limelight;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.widget.MediaController;
|
||||||
|
import android.widget.VideoView;
|
||||||
|
|
||||||
|
|
||||||
|
public class Game extends Activity {
|
||||||
|
private VideoView vv;
|
||||||
|
private MediaController mc;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_game);
|
||||||
|
|
||||||
|
vv = (VideoView) findViewById(R.id.videoView);
|
||||||
|
|
||||||
|
mc = new MediaController(this);
|
||||||
|
mc.setAnchorView(vv);
|
||||||
|
|
||||||
|
Uri video = Uri.parse("rtsp://141.213.191.236:47902/nvstream");
|
||||||
|
vv.setMediaController(mc);
|
||||||
|
vv.setVideoURI(video);
|
||||||
|
|
||||||
|
vv.start();
|
||||||
|
}
|
||||||
|
}
|
73
src/com/limelight/nvstream/NvAudioStream.java
Normal file
73
src/com/limelight/nvstream/NvAudioStream.java
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
package com.limelight.nvstream;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.DatagramPacket;
|
||||||
|
import java.net.DatagramSocket;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.SocketException;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
|
import android.net.rtp.AudioCodec;
|
||||||
|
import android.net.rtp.AudioGroup;
|
||||||
|
import android.net.rtp.AudioStream;
|
||||||
|
|
||||||
|
public class NvAudioStream {
|
||||||
|
private AudioGroup group;
|
||||||
|
private AudioStream stream;
|
||||||
|
|
||||||
|
public static final int PORT = 48000;
|
||||||
|
|
||||||
|
/*public void startStream(String host) throws SocketException, UnknownHostException
|
||||||
|
{
|
||||||
|
System.out.println("Starting audio group");
|
||||||
|
group = new AudioGroup();
|
||||||
|
group.setMode(AudioGroup.MODE_NORMAL);
|
||||||
|
|
||||||
|
System.out.println("Starting audio stream");
|
||||||
|
stream = new AudioStream(InetAddress.getByAddress(new byte[]{0,0,0,0}));
|
||||||
|
stream.setMode(AudioStream.MODE_NORMAL);
|
||||||
|
stream.associate(InetAddress.getByName(host), PORT);
|
||||||
|
stream.setCodec(AudioCodec.PCMA);
|
||||||
|
stream.join(group);
|
||||||
|
|
||||||
|
for (AudioCodec c : AudioCodec.getCodecs())
|
||||||
|
System.out.println(c.type + " " + c.fmtp + " " + c.rtpmap);
|
||||||
|
|
||||||
|
System.out.println("Joined");
|
||||||
|
}*/
|
||||||
|
|
||||||
|
public void start()
|
||||||
|
{
|
||||||
|
new Thread(new Runnable() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
DatagramSocket ds;
|
||||||
|
try {
|
||||||
|
ds = new DatagramSocket(PORT);
|
||||||
|
} catch (SocketException e1) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e1.printStackTrace();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
|
||||||
|
DatagramPacket dp = new DatagramPacket(new byte[1500], 1500);
|
||||||
|
|
||||||
|
try {
|
||||||
|
ds.receive(dp);
|
||||||
|
} catch (IOException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//System.out.println("Got UDP 48000: "+dp.getLength());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
}
|
@ -12,20 +12,67 @@ public class NvConnection {
|
|||||||
this.host = host;
|
this.host = host;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void delay(int ms)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Thread.sleep(ms);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void doShit() throws XmlPullParserException, IOException
|
public void doShit() throws XmlPullParserException, IOException
|
||||||
{
|
{
|
||||||
NvHttp h = new NvHttp(host, "b0:ee:45:57:5d:5f");
|
NvHttp h = new NvHttp(host, "b0:ee:45:57:5d:5f");
|
||||||
|
|
||||||
System.out.println("Shield Shit");
|
System.out.println("Begin Shield Action");
|
||||||
System.out.println(h.getAppVersion());
|
System.out.println(h.getAppVersion());
|
||||||
System.out.println(h.getPairState());
|
System.out.println(h.getPairState());
|
||||||
|
|
||||||
|
|
||||||
int sessionId = h.getSessionId();
|
int sessionId = h.getSessionId();
|
||||||
System.out.println("Session ID: "+sessionId);
|
System.out.println("Session ID: "+sessionId);
|
||||||
int appId = h.getSteamAppId(sessionId);
|
int appId = h.getSteamAppId(sessionId);
|
||||||
System.out.println("Steam app ID: "+appId);
|
System.out.println("Steam app ID: "+appId);
|
||||||
int gameSession = h.launchApp(sessionId, appId);
|
int gameSession = h.launchApp(sessionId, appId);
|
||||||
System.out.println("Started game session: "+gameSession);
|
System.out.println("Started game session: "+gameSession);
|
||||||
|
|
||||||
|
System.out.println("Starting handshake");
|
||||||
|
NvHandshake.performHandshake(host);
|
||||||
|
System.out.println("Handshake complete");
|
||||||
|
|
||||||
|
NvControl nvC = new NvControl(host);
|
||||||
|
|
||||||
|
System.out.println("Starting control");
|
||||||
|
nvC.beginControl();
|
||||||
|
|
||||||
|
System.out.println("Startup controller");
|
||||||
|
NvController controller = new NvController(host);
|
||||||
|
|
||||||
|
// Wait 3 seconds to start input
|
||||||
|
delay(3000);
|
||||||
|
|
||||||
|
System.out.println("Beginning controller input");
|
||||||
|
controller.sendLeftButton();
|
||||||
|
delay(100);
|
||||||
|
controller.clearButtons();
|
||||||
|
delay(250);
|
||||||
|
controller.sendRightButton();
|
||||||
|
delay(100);
|
||||||
|
controller.clearButtons();
|
||||||
|
delay(250);
|
||||||
|
controller.sendRightButton();
|
||||||
|
delay(100);
|
||||||
|
controller.clearButtons();
|
||||||
|
delay(250);
|
||||||
|
controller.sendRightButton();
|
||||||
|
delay(100);
|
||||||
|
controller.clearButtons();
|
||||||
|
delay(250);
|
||||||
|
controller.sendLeftButton();
|
||||||
|
delay(100);
|
||||||
|
controller.clearButtons();
|
||||||
|
|
||||||
|
new NvAudioStream().start();
|
||||||
|
new NvVideoStream().start(host);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
384
src/com/limelight/nvstream/NvControl.java
Normal file
384
src/com/limelight/nvstream/NvControl.java
Normal file
@ -0,0 +1,384 @@
|
|||||||
|
package com.limelight.nvstream;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
|
||||||
|
public class NvControl {
|
||||||
|
|
||||||
|
public static final int PORT = 47995;
|
||||||
|
|
||||||
|
public static final short PTYPE_1 = 0x1204;
|
||||||
|
public static final short PPAYLEN_1 = 0x0004;
|
||||||
|
public static final byte[] PPAYLOAD_1 =
|
||||||
|
{
|
||||||
|
(byte)0x00,
|
||||||
|
(byte)0x05,
|
||||||
|
(byte)0x00,
|
||||||
|
(byte)0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final short PTYPE_KEEPALIVE = 0x13ff;
|
||||||
|
public static final short PPAYLEN_KEEPALIVE = 0x0000;
|
||||||
|
|
||||||
|
public static final short PTYPE_HEARTBEAT = 0x1401;
|
||||||
|
public static final short PPAYLEN_HEARTBEAT = 0x0000;
|
||||||
|
|
||||||
|
public static final short PTYPE_1405 = 0x1405;
|
||||||
|
public static final short PPAYLEN_1405 = 0x0000;
|
||||||
|
|
||||||
|
public static final short PTYPE_1404 = 0x1404;
|
||||||
|
public static final short PPAYLEN_1404 = 0x0010;
|
||||||
|
public static final byte[] PPAYLOAD_1404 = new byte[]
|
||||||
|
{
|
||||||
|
0x02,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x02,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final short PTYPE_CONFIG = 0x1205;
|
||||||
|
public static final short PPAYLEN_CONFIG = 0x0004;
|
||||||
|
public static final int[] PPAYLOAD_CONFIG =
|
||||||
|
{
|
||||||
|
720,
|
||||||
|
266758,
|
||||||
|
1,
|
||||||
|
266762,
|
||||||
|
30,
|
||||||
|
70151,
|
||||||
|
68291329,
|
||||||
|
1280,
|
||||||
|
68291584,
|
||||||
|
1280,
|
||||||
|
68291840,
|
||||||
|
15360,
|
||||||
|
68292096,
|
||||||
|
25600,
|
||||||
|
68292352,
|
||||||
|
2048,
|
||||||
|
68292608,
|
||||||
|
1024,
|
||||||
|
68289024,
|
||||||
|
262144,
|
||||||
|
17957632,
|
||||||
|
302055424,
|
||||||
|
134217729,
|
||||||
|
16777490,
|
||||||
|
70153,
|
||||||
|
68293120,
|
||||||
|
768000,
|
||||||
|
17961216,
|
||||||
|
303235072,
|
||||||
|
335609857,
|
||||||
|
838861842,
|
||||||
|
352321536,
|
||||||
|
1006634002,
|
||||||
|
369098752,
|
||||||
|
335545362,
|
||||||
|
385875968,
|
||||||
|
1042,
|
||||||
|
402653184,
|
||||||
|
134218770,
|
||||||
|
419430400,
|
||||||
|
167773203,
|
||||||
|
436207616,
|
||||||
|
855638290,
|
||||||
|
266779,
|
||||||
|
7000,
|
||||||
|
266780,
|
||||||
|
2000,
|
||||||
|
266781,
|
||||||
|
50,
|
||||||
|
266782,
|
||||||
|
3000,
|
||||||
|
266783,
|
||||||
|
2,
|
||||||
|
266794,
|
||||||
|
5000,
|
||||||
|
266795,
|
||||||
|
500,
|
||||||
|
266784,
|
||||||
|
75,
|
||||||
|
266785,
|
||||||
|
25,
|
||||||
|
266786,
|
||||||
|
10,
|
||||||
|
266787,
|
||||||
|
60,
|
||||||
|
266788,
|
||||||
|
30,
|
||||||
|
266789,
|
||||||
|
3,
|
||||||
|
266790,
|
||||||
|
1000,
|
||||||
|
266791,
|
||||||
|
5000,
|
||||||
|
266792,
|
||||||
|
5000,
|
||||||
|
266793,
|
||||||
|
5000,
|
||||||
|
70190,
|
||||||
|
68301063,
|
||||||
|
10240,
|
||||||
|
68301312,
|
||||||
|
6400,
|
||||||
|
68301568,
|
||||||
|
768000,
|
||||||
|
68299776,
|
||||||
|
768,
|
||||||
|
68300032,
|
||||||
|
2560,
|
||||||
|
68300544,
|
||||||
|
0,
|
||||||
|
34746368,
|
||||||
|
(int)0xFE000000
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final short PTYPE_HELLO = 0x1204;
|
||||||
|
public static final short PPAYLEN_HELLO = 0x0004;
|
||||||
|
public static final byte[] PPAYLOAD_HELLO = new byte[] {
|
||||||
|
0x04, 0x00, 0x00, 0x05
|
||||||
|
};
|
||||||
|
|
||||||
|
private Socket s;
|
||||||
|
private InputStream in;
|
||||||
|
private OutputStream out;
|
||||||
|
|
||||||
|
public NvControl(String host) throws UnknownHostException, IOException
|
||||||
|
{
|
||||||
|
s = new Socket(host, PORT);
|
||||||
|
in = s.getInputStream();
|
||||||
|
out = s.getOutputStream();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendPacket(NvCtlPacket packet) throws IOException
|
||||||
|
{
|
||||||
|
out.write(packet.toWire());
|
||||||
|
out.flush();
|
||||||
|
}
|
||||||
|
public NvControl.NvCtlResponse sendAndGetReply(NvCtlPacket packet) throws IOException
|
||||||
|
{
|
||||||
|
sendPacket(packet);
|
||||||
|
return new NvCtlResponse(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void beginControl() throws IOException
|
||||||
|
{
|
||||||
|
System.out.println("CTL: Sending hello");
|
||||||
|
sendHello();
|
||||||
|
System.out.println("CTL: Sending config");
|
||||||
|
sendConfig();
|
||||||
|
System.out.println("CTL: Initial ping/pong");
|
||||||
|
pingPong();
|
||||||
|
System.out.println("CTL: Sending and waiting for 1405");
|
||||||
|
send1405AndGetResponse();
|
||||||
|
//System.out.println("CTL: Sending 1404");
|
||||||
|
//send1404();
|
||||||
|
System.out.println("CTL: Launching heartbeat thread");
|
||||||
|
|
||||||
|
new Thread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
sendHeartbeat();
|
||||||
|
} catch (IOException e1) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Thread.sleep(3000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void endControl() throws IOException
|
||||||
|
{
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private NvControl.NvCtlResponse send1405AndGetResponse() throws IOException
|
||||||
|
{
|
||||||
|
return sendAndGetReply(new NvCtlPacket(PTYPE_1405, PPAYLEN_1405));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void send1404() throws IOException
|
||||||
|
{
|
||||||
|
sendPacket(new NvCtlPacket(PTYPE_1404, PPAYLEN_1404));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendHello() throws IOException
|
||||||
|
{
|
||||||
|
sendPacket(new NvCtlPacket(PTYPE_HELLO, PPAYLEN_HELLO, PPAYLOAD_HELLO));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendConfig() throws IOException
|
||||||
|
{
|
||||||
|
ByteBuffer conf = ByteBuffer.wrap(new byte[PPAYLOAD_CONFIG.length * 4 + 3]).order(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
|
||||||
|
for (int i : PPAYLOAD_CONFIG)
|
||||||
|
conf.putInt(i);
|
||||||
|
|
||||||
|
conf.putShort((short)0x0013);
|
||||||
|
conf.put((byte) 0x00);
|
||||||
|
|
||||||
|
sendPacket(new NvCtlPacket(PTYPE_CONFIG, PPAYLEN_CONFIG, conf.array()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendHeartbeat() throws IOException
|
||||||
|
{
|
||||||
|
sendPacket(new NvCtlPacket(PTYPE_HEARTBEAT, PPAYLEN_HEARTBEAT));
|
||||||
|
}
|
||||||
|
|
||||||
|
private NvControl.NvCtlResponse pingPong() throws IOException
|
||||||
|
{
|
||||||
|
sendPacket(new NvCtlPacket(PTYPE_KEEPALIVE, PPAYLEN_KEEPALIVE));
|
||||||
|
return new NvControl.NvCtlResponse(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
class NvCtlPacket {
|
||||||
|
public short type;
|
||||||
|
public short paylen;
|
||||||
|
public byte[] payload;
|
||||||
|
|
||||||
|
public NvCtlPacket(InputStream in) throws IOException
|
||||||
|
{
|
||||||
|
byte[] header = new byte[4];
|
||||||
|
|
||||||
|
int offset = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
offset = in.read(header, offset, header.length - offset);
|
||||||
|
} while (offset != header.length);
|
||||||
|
|
||||||
|
ByteBuffer bb = ByteBuffer.wrap(header).order(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
|
||||||
|
type = bb.getShort();
|
||||||
|
paylen = bb.getShort();
|
||||||
|
|
||||||
|
if (paylen != 0)
|
||||||
|
{
|
||||||
|
payload = new byte[paylen];
|
||||||
|
|
||||||
|
offset = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
offset = in.read(payload, offset, payload.length - offset);
|
||||||
|
} while (offset != payload.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public NvCtlPacket(byte[] payload)
|
||||||
|
{
|
||||||
|
ByteBuffer bb = ByteBuffer.wrap(payload).order(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
|
||||||
|
type = bb.getShort();
|
||||||
|
paylen = bb.getShort();
|
||||||
|
|
||||||
|
if (bb.hasRemaining())
|
||||||
|
{
|
||||||
|
payload = new byte[bb.remaining()];
|
||||||
|
bb.get(payload);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public NvCtlPacket(short type, short paylen)
|
||||||
|
{
|
||||||
|
this.type = type;
|
||||||
|
this.paylen = paylen;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NvCtlPacket(short type, short paylen, byte[] payload)
|
||||||
|
{
|
||||||
|
this.type = type;
|
||||||
|
this.paylen = paylen;
|
||||||
|
this.payload = payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getType()
|
||||||
|
{
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getPaylen()
|
||||||
|
{
|
||||||
|
return paylen;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(short type)
|
||||||
|
{
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPaylen(short paylen)
|
||||||
|
{
|
||||||
|
this.paylen = paylen;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] toWire()
|
||||||
|
{
|
||||||
|
ByteBuffer bb = ByteBuffer.allocate(4 + (payload != null ? payload.length : 0)).order(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
|
||||||
|
bb.putShort(type);
|
||||||
|
bb.putShort(paylen);
|
||||||
|
|
||||||
|
if (payload != null)
|
||||||
|
bb.put(payload);
|
||||||
|
|
||||||
|
return bb.array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NvCtlResponse extends NvCtlPacket {
|
||||||
|
public short status;
|
||||||
|
|
||||||
|
public NvCtlResponse(InputStream in) throws IOException {
|
||||||
|
super(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NvCtlResponse(short type, short paylen) {
|
||||||
|
super(type, paylen);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NvCtlResponse(short type, short paylen, byte[] payload) {
|
||||||
|
super(type, paylen, payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NvCtlResponse(byte[] payload) {
|
||||||
|
super(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatusCode(short status)
|
||||||
|
{
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getStatusCode()
|
||||||
|
{
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
40
src/com/limelight/nvstream/NvController.java
Normal file
40
src/com/limelight/nvstream/NvController.java
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package com.limelight.nvstream;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
|
||||||
|
public class NvController {
|
||||||
|
|
||||||
|
public final static int PORT = 35043;
|
||||||
|
|
||||||
|
private Socket s;
|
||||||
|
private OutputStream out;
|
||||||
|
|
||||||
|
public NvController(String host) throws UnknownHostException, IOException
|
||||||
|
{
|
||||||
|
s = new Socket(host, PORT);
|
||||||
|
out = s.getOutputStream();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example
|
||||||
|
public void sendLeftButton() throws IOException
|
||||||
|
{
|
||||||
|
out.write(new NvInputPacket(NvInputPacket.LEFT_FLAG, (byte)0, (byte)0, (short)0, (short)0).toWire());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example
|
||||||
|
public void sendRightButton() throws IOException
|
||||||
|
{
|
||||||
|
out.write(new NvInputPacket(NvInputPacket.RIGHT_FLAG, (byte)0, (byte)0, (short)0, (short)0).toWire());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example
|
||||||
|
public void clearButtons() throws IOException
|
||||||
|
{
|
||||||
|
out.write(new NvInputPacket((short)0, (byte)0, (byte)0, (short)0, (short)0).toWire());
|
||||||
|
}
|
||||||
|
}
|
107
src/com/limelight/nvstream/NvHandshake.java
Normal file
107
src/com/limelight/nvstream/NvHandshake.java
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
package com.limelight.nvstream;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.UnknownHostException;;
|
||||||
|
|
||||||
|
public class NvHandshake {
|
||||||
|
public static final int PORT = 47991;
|
||||||
|
|
||||||
|
// android
|
||||||
|
public static final byte[] PLATFORM_HELLO =
|
||||||
|
{
|
||||||
|
(byte)0x61,
|
||||||
|
(byte)0x6e,
|
||||||
|
(byte)0x64,
|
||||||
|
(byte)0x72,
|
||||||
|
(byte)0x6f,
|
||||||
|
(byte)0x69,
|
||||||
|
(byte)0x64,
|
||||||
|
(byte)0x03,
|
||||||
|
(byte)0x01,
|
||||||
|
(byte)0x00,
|
||||||
|
(byte)0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final byte[] PACKET_2 =
|
||||||
|
{
|
||||||
|
(byte)0x01,
|
||||||
|
(byte)0x03,
|
||||||
|
(byte)0x02,
|
||||||
|
(byte)0x00,
|
||||||
|
(byte)0x08,
|
||||||
|
(byte)0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final byte[] PACKET_3 =
|
||||||
|
{
|
||||||
|
(byte)0x04,
|
||||||
|
(byte)0x01,
|
||||||
|
(byte)0x00,
|
||||||
|
(byte)0x00,
|
||||||
|
|
||||||
|
(byte)0x00,
|
||||||
|
(byte)0x00,
|
||||||
|
(byte)0x00,
|
||||||
|
(byte)0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final byte[] PACKET_4 =
|
||||||
|
{
|
||||||
|
(byte)0x01,
|
||||||
|
(byte)0x01,
|
||||||
|
(byte)0x00,
|
||||||
|
(byte)0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
private static void waitAndDiscardResponse(InputStream in) throws IOException
|
||||||
|
{
|
||||||
|
// Wait for response and discard response
|
||||||
|
in.read();
|
||||||
|
|
||||||
|
try {
|
||||||
|
Thread.sleep(250);
|
||||||
|
} catch (InterruptedException e) { }
|
||||||
|
|
||||||
|
for (int i = 0; i < in.available(); i++)
|
||||||
|
in.read();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void performHandshake(String host) throws UnknownHostException, IOException
|
||||||
|
{
|
||||||
|
Socket s = new Socket(host, PORT);
|
||||||
|
OutputStream out = s.getOutputStream();
|
||||||
|
InputStream in = s.getInputStream();
|
||||||
|
|
||||||
|
// First packet
|
||||||
|
out.write(new byte[]{0x07, 0x00, 0x00, 0x00});
|
||||||
|
out.write(PLATFORM_HELLO);
|
||||||
|
|
||||||
|
System.out.println("HS: Waiting for hello response");
|
||||||
|
|
||||||
|
waitAndDiscardResponse(in);
|
||||||
|
|
||||||
|
// Second packet
|
||||||
|
out.write(PACKET_2);
|
||||||
|
|
||||||
|
System.out.println("HS: Waiting stage 2 response");
|
||||||
|
|
||||||
|
waitAndDiscardResponse(in);
|
||||||
|
|
||||||
|
// Third packet
|
||||||
|
out.write(PACKET_3);
|
||||||
|
|
||||||
|
System.out.println("HS: Waiting for stage 3 response");
|
||||||
|
|
||||||
|
waitAndDiscardResponse(in);
|
||||||
|
|
||||||
|
// Fourth packet
|
||||||
|
out.write(PACKET_4);
|
||||||
|
out.flush();
|
||||||
|
|
||||||
|
// Done
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
}
|
78
src/com/limelight/nvstream/NvInputPacket.java
Normal file
78
src/com/limelight/nvstream/NvInputPacket.java
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
package com.limelight.nvstream;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
|
||||||
|
public class NvInputPacket {
|
||||||
|
public static final byte[] HEADER =
|
||||||
|
{
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x18,
|
||||||
|
0x0A,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x14
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final byte[] TAIL =
|
||||||
|
{
|
||||||
|
(byte)0x9C,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x55,
|
||||||
|
0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final short A_FLAG = 0x1000;
|
||||||
|
public static final short B_FLAG = 0x2000;
|
||||||
|
public static final short X_FLAG = 0x4000;
|
||||||
|
public static final short Y_FLAG = (short)0x8000;
|
||||||
|
public static final short UP_FLAG = 0x0001;
|
||||||
|
public static final short DOWN_FLAG = 0x0002;
|
||||||
|
public static final short LEFT_FLAG = 0x0004;
|
||||||
|
public static final short RIGHT_FLAG = 0x0008;
|
||||||
|
public static final short RB_FLAG = 0x0100;
|
||||||
|
public static final short LB_FLAG = 0x0200;
|
||||||
|
public static final short LS_CLK_FLAG = 0x0004;
|
||||||
|
public static final short RS_CLK_FLAG = 0x0008;
|
||||||
|
public static final short PLAY_FLAG = 0x0001;
|
||||||
|
public static final short BACK_FLAG = 0x0002;
|
||||||
|
|
||||||
|
public static final short PACKET_LENGTH = 28;
|
||||||
|
|
||||||
|
private short buttonFlags;
|
||||||
|
private byte leftTrigger;
|
||||||
|
private byte rightTrigger;
|
||||||
|
private short leftStick;
|
||||||
|
private short rightStick;
|
||||||
|
|
||||||
|
public NvInputPacket(short buttonFlags, byte leftTrigger, byte rightTrigger,
|
||||||
|
short leftStick, short rightStick)
|
||||||
|
{
|
||||||
|
this.buttonFlags = buttonFlags;
|
||||||
|
this.leftTrigger = leftTrigger;
|
||||||
|
this.rightTrigger = rightTrigger;
|
||||||
|
this.leftStick = leftStick;
|
||||||
|
this.rightStick = rightStick;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] toWire()
|
||||||
|
{
|
||||||
|
ByteBuffer bb = ByteBuffer.allocate(PACKET_LENGTH).order(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
|
||||||
|
bb.put(HEADER);
|
||||||
|
bb.putShort(buttonFlags);
|
||||||
|
bb.put(leftTrigger);
|
||||||
|
bb.put(rightTrigger);
|
||||||
|
bb.putShort(leftStick);
|
||||||
|
bb.putShort(rightStick);
|
||||||
|
bb.put(TAIL);
|
||||||
|
|
||||||
|
return bb.array();
|
||||||
|
}
|
||||||
|
}
|
71
src/com/limelight/nvstream/NvVideoStream.java
Normal file
71
src/com/limelight/nvstream/NvVideoStream.java
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
package com.limelight.nvstream;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.DatagramPacket;
|
||||||
|
import java.net.DatagramSocket;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.SocketException;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
|
public class NvVideoStream {
|
||||||
|
public static final int PORT = 47998;
|
||||||
|
public static final int FIRST_FRAME_PORT = 47996;
|
||||||
|
|
||||||
|
private InputStream getFirstFrame(String host) throws UnknownHostException, IOException
|
||||||
|
{
|
||||||
|
Socket s = new Socket(host, FIRST_FRAME_PORT);
|
||||||
|
return s.getInputStream();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start(final String host)
|
||||||
|
{
|
||||||
|
new Thread(new Runnable() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
System.out.println("VID: Waiting for first frame");
|
||||||
|
InputStream firstFrameStream = getFirstFrame(host);
|
||||||
|
firstFrameStream.read();
|
||||||
|
System.out.println("VID: First frame: "+firstFrameStream.available()+1);
|
||||||
|
firstFrameStream.close();
|
||||||
|
System.out.println("VID: Got first frame");
|
||||||
|
} catch (UnknownHostException e2) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e2.printStackTrace();
|
||||||
|
return;
|
||||||
|
} catch (IOException e2) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e2.printStackTrace();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DatagramSocket ds;
|
||||||
|
try {
|
||||||
|
ds = new DatagramSocket(PORT);
|
||||||
|
} catch (SocketException e1) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e1.printStackTrace();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
DatagramPacket dp = new DatagramPacket(new byte[1500], 1500);
|
||||||
|
|
||||||
|
try {
|
||||||
|
ds.receive(dp);
|
||||||
|
} catch (IOException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("Got UDP 47998: "+dp.getLength());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user