Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e92a281fd8 | |||
| b4c3f9678a | |||
| 82f79c466a | |||
| d428f316b4 | |||
| 828f4877b6 | |||
| 09e8e8e6b3 | |||
| 77c8051ec6 | |||
| 6bae056e3a | |||
| bb869a51fd | |||
| 25b3d08bb9 |
+6
-3
@@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.limelight"
|
||||
android:versionCode="35"
|
||||
android:versionName="2.5.6" >
|
||||
package="com.limelight.root"
|
||||
android:versionCode="33"
|
||||
android:versionName="2.5.4.1" >
|
||||
|
||||
<uses-sdk
|
||||
android:minSdkVersion="16"
|
||||
@@ -14,6 +14,9 @@
|
||||
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
|
||||
<!-- Root permissions -->
|
||||
<uses-permission android:name="android.permission.ACCESS_SUPERUSER" />
|
||||
|
||||
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
|
||||
<uses-feature android:name="android.hardware.wifi" android:required="false" />
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/** Automatically generated file. DO NOT MODIFY */
|
||||
package com.limelight;
|
||||
package com.limelight.root;
|
||||
|
||||
public final class BuildConfig {
|
||||
public final static boolean DEBUG = true;
|
||||
@@ -5,7 +5,7 @@
|
||||
* should not be modified by hand.
|
||||
*/
|
||||
|
||||
package com.limelight;
|
||||
package com.limelight.root;
|
||||
|
||||
public final class R {
|
||||
public static final class attr {
|
||||
@@ -123,8 +123,8 @@ or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>na
|
||||
<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>
|
||||
<tr><td><code>{@link #ButtonBarContainerTheme_buttonBarButtonStyle com.limelight.root:buttonBarButtonStyle}</code></td><td></td></tr>
|
||||
<tr><td><code>{@link #ButtonBarContainerTheme_buttonBarStyle com.limelight.root:buttonBarStyle}</code></td><td></td></tr>
|
||||
</table>
|
||||
@see #ButtonBarContainerTheme_buttonBarButtonStyle
|
||||
@see #ButtonBarContainerTheme_buttonBarStyle
|
||||
@@ -133,23 +133,23 @@ or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>na
|
||||
0x7f010000, 0x7f010001
|
||||
};
|
||||
/**
|
||||
<p>This symbol is the offset where the {@link com.limelight.R.attr#buttonBarButtonStyle}
|
||||
<p>This symbol is the offset where the {@link com.limelight.root.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 com.limelight:buttonBarButtonStyle
|
||||
@attr name com.limelight.root:buttonBarButtonStyle
|
||||
*/
|
||||
public static final int ButtonBarContainerTheme_buttonBarButtonStyle = 1;
|
||||
/**
|
||||
<p>This symbol is the offset where the {@link com.limelight.R.attr#buttonBarStyle}
|
||||
<p>This symbol is the offset where the {@link com.limelight.root.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 com.limelight:buttonBarStyle
|
||||
@attr name com.limelight.root:buttonBarStyle
|
||||
*/
|
||||
public static final int ButtonBarContainerTheme_buttonBarStyle = 0;
|
||||
};
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <fcntl.h>
|
||||
#include <linux/input.h>
|
||||
#include <unistd.h>
|
||||
#include <poll.h>
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_com_limelight_binding_input_evdev_EvdevReader_open(JNIEnv *env, jobject this, jstring absolutePath) {
|
||||
@@ -26,33 +27,67 @@ Java_com_limelight_binding_input_evdev_EvdevReader_ungrab(JNIEnv *env, jobject t
|
||||
return ioctl(fd, EVIOCGRAB, 0) == 0;
|
||||
}
|
||||
|
||||
// isMouse() and friends are based on Android's EventHub.cpp
|
||||
// has*() and friends are based on Android's EventHub.cpp
|
||||
|
||||
#define test_bit(bit, array) (array[bit/8] & (1<<(bit%8)))
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_limelight_binding_input_evdev_EvdevReader_isMouse(JNIEnv *env, jobject this, jint fd) {
|
||||
unsigned char keyBitmask[(KEY_MAX + 1) / 8];
|
||||
Java_com_limelight_binding_input_evdev_EvdevReader_hasRelAxis(JNIEnv *env, jobject this, jint fd, jshort axis) {
|
||||
unsigned char relBitmask[(REL_MAX + 1) / 8];
|
||||
|
||||
ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keyBitmask)), keyBitmask);
|
||||
ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relBitmask)), relBitmask);
|
||||
|
||||
// If this device has all required features of a mouse, it's a mouse!
|
||||
return test_bit(BTN_MOUSE, keyBitmask) &&
|
||||
test_bit(REL_X, relBitmask) &&
|
||||
test_bit(REL_Y, relBitmask);
|
||||
return test_bit(axis, relBitmask);
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_limelight_binding_input_evdev_EvdevReader_hasAbsAxis(JNIEnv *env, jobject this, jint fd, jshort axis) {
|
||||
unsigned char absBitmask[(ABS_MAX + 1) / 8];
|
||||
|
||||
ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absBitmask)), absBitmask);
|
||||
|
||||
return test_bit(axis, absBitmask);
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_limelight_binding_input_evdev_EvdevReader_hasKey(JNIEnv *env, jobject this, jint fd, jshort key) {
|
||||
unsigned char keyBitmask[(KEY_MAX + 1) / 8];
|
||||
|
||||
ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keyBitmask)), keyBitmask);
|
||||
|
||||
return test_bit(key, keyBitmask);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_com_limelight_binding_input_evdev_EvdevReader_read(JNIEnv *env, jobject this, jint fd, jbyteArray buffer) {
|
||||
jint ret;
|
||||
jbyte *data = (*env)->GetByteArrayElements(env, buffer, NULL);
|
||||
jbyte *data;
|
||||
int pollres;
|
||||
struct pollfd pollinfo;
|
||||
|
||||
data = (*env)->GetByteArrayElements(env, buffer, NULL);
|
||||
if (data == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = read(fd, data, sizeof(struct input_event));
|
||||
do
|
||||
{
|
||||
// Unwait every 250 ms to return to caller if the fd is closed
|
||||
pollinfo.fd = fd;
|
||||
pollinfo.events = POLLIN;
|
||||
pollinfo.revents = 0;
|
||||
pollres = poll(&pollinfo, 1, 250);
|
||||
}
|
||||
while (pollres == 0);
|
||||
|
||||
if (pollres > 0 && (pollinfo.revents & POLLIN)) {
|
||||
// We'll have data available now
|
||||
ret = read(fd, data, sizeof(struct input_event));
|
||||
}
|
||||
else {
|
||||
// There must have been a failure
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
(*env)->ReleaseByteArrayElements(env, buffer, data, 0);
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -14,8 +14,7 @@ export PATH=$PATH:$TOOLCHAIN_PATH/bin
|
||||
--build=x86_64-unknown-linux-gnu \
|
||||
--host=$TOOLCHAIN_BIN_PREFIX \
|
||||
--target=$TOOLCHAIN_BIN_PREFIX \
|
||||
CFLAGS="--sysroot=$SYSROOT -O2 $ADDI_CFLAGS" \
|
||||
$ADDI_CONFIGURE_FLAGS
|
||||
CFLAGS="--sysroot=$SYSROOT -O2 $ADDI_CFLAGS"
|
||||
make clean
|
||||
make -j$PARALLEL_JOBS
|
||||
mkdir android/$CPU
|
||||
@@ -29,7 +28,6 @@ SYSROOT_CPU=mips
|
||||
TOOLCHAIN_BIN_PREFIX=mipsel-linux-android
|
||||
TOOLCHAIN_DIR=mipsel-linux-android-4.9
|
||||
ADDI_CFLAGS="-mips32 -mhard-float -EL -mno-dsp"
|
||||
ADDI_CONFIGURE_FLAGS="--enable-fixed-point" # fixed point
|
||||
build_one
|
||||
}
|
||||
|
||||
@@ -40,7 +38,6 @@ SYSROOT_CPU=mips64
|
||||
TOOLCHAIN_BIN_PREFIX=mips64el-linux-android
|
||||
TOOLCHAIN_DIR=mips64el-linux-android-4.9
|
||||
ADDI_CFLAGS="-mips64r6"
|
||||
ADDI_CONFIGURE_FLAGS="--enable-fixed-point" # fixed point
|
||||
build_one
|
||||
}
|
||||
|
||||
@@ -51,7 +48,6 @@ SYSROOT_CPU=x86
|
||||
TOOLCHAIN_BIN_PREFIX=i686-linux-android
|
||||
TOOLCHAIN_DIR=x86-4.9
|
||||
ADDI_CFLAGS="-march=i686 -mtune=atom -mstackrealign -msse -msse2 -msse3 -mssse3 -mfpmath=sse -m32"
|
||||
ADDI_CONFIGURE_FLAGS="" # floating point for SSE optimizations
|
||||
build_one
|
||||
}
|
||||
|
||||
@@ -62,7 +58,6 @@ SYSROOT_CPU=x86_64
|
||||
TOOLCHAIN_BIN_PREFIX=x86_64-linux-android
|
||||
TOOLCHAIN_DIR=x86_64-4.9
|
||||
ADDI_CFLAGS="-msse -msse2 -msse3 -mssse3 -msse4 -msse4.1 -msse4.2 -mpopcnt -m64"
|
||||
ADDI_CONFIGURE_FLAGS="" # floating point for SSE optimizations
|
||||
build_one
|
||||
}
|
||||
|
||||
@@ -74,12 +69,10 @@ TOOLCHAIN_BIN_PREFIX=arm-linux-androideabi
|
||||
TOOLCHAIN_DIR=arm-linux-androideabi-4.9
|
||||
ADDI_CFLAGS="-marm -mfpu=vfpv3-d16"
|
||||
ADDI_LDFLAGS=""
|
||||
ADDI_CONFIGURE_FLAGS="--enable-fixed-point" # fixed point for NEON, EDSP, Media
|
||||
ADDI_CONFIGURE_FLAGS=""
|
||||
build_one
|
||||
}
|
||||
|
||||
# ARMv8 doesn't currently have assembly in the opus project. We still use fixed point
|
||||
# anyway in the hopes that it will be more performant even without assembly.
|
||||
function build_armv8
|
||||
{
|
||||
CPU=aarch64
|
||||
@@ -88,7 +81,7 @@ TOOLCHAIN_BIN_PREFIX=aarch64-linux-android
|
||||
TOOLCHAIN_DIR=aarch64-linux-android-4.9
|
||||
ADDI_CFLAGS=""
|
||||
ADDI_LDFLAGS=""
|
||||
ADDI_CONFIGURE_FLAGS="--enable-fixed-point"
|
||||
ADDI_CONFIGURE_FLAGS=""
|
||||
build_one
|
||||
}
|
||||
|
||||
|
||||
@@ -592,20 +592,6 @@ OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_samples(const unsigne
|
||||
* @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
|
||||
*/
|
||||
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decoder_get_nb_samples(const OpusDecoder *dec, const unsigned char packet[], opus_int32 len) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2);
|
||||
|
||||
/** Applies soft-clipping to bring a float signal within the [-1,1] range. If
|
||||
* the signal is already in that range, nothing is done. If there are values
|
||||
* outside of [-1,1], then the signal is clipped as smoothly as possible to
|
||||
* both fit in the range and avoid creating excessive distortion in the
|
||||
* process.
|
||||
* @param [in,out] pcm <tt>float*</tt>: Input PCM and modified PCM
|
||||
* @param [in] frame_size <tt>int</tt> Number of samples per channel to process
|
||||
* @param [in] channels <tt>int</tt>: Number of channels
|
||||
* @param [in,out] softclip_mem <tt>float*</tt>: State memory for the soft clipping process (one float per channel, initialized to zero)
|
||||
*/
|
||||
OPUS_EXPORT void opus_pcm_soft_clip(float *pcm, int frame_size, int channels, float *softclip_mem);
|
||||
|
||||
|
||||
/**@}*/
|
||||
|
||||
/** @defgroup opus_repacketizer Repacketizer
|
||||
@@ -911,64 +897,6 @@ OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_repacketizer_get_nb_frames(OpusRepa
|
||||
*/
|
||||
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_repacketizer_out(OpusRepacketizer *rp, unsigned char *data, opus_int32 maxlen) OPUS_ARG_NONNULL(1);
|
||||
|
||||
/** Pads a given Opus packet to a larger size (possibly changing the TOC sequence).
|
||||
* @param[in,out] data <tt>const unsigned char*</tt>: The buffer containing the
|
||||
* packet to pad.
|
||||
* @param len <tt>opus_int32</tt>: The size of the packet.
|
||||
* This must be at least 1.
|
||||
* @param new_len <tt>opus_int32</tt>: The desired size of the packet after padding.
|
||||
* This must be at least as large as len.
|
||||
* @returns an error code
|
||||
* @retval #OPUS_OK \a on success.
|
||||
* @retval #OPUS_BAD_ARG \a len was less than 1 or new_len was less than len.
|
||||
* @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
|
||||
*/
|
||||
OPUS_EXPORT int opus_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len);
|
||||
|
||||
/** Remove all padding from a given Opus packet and rewrite the TOC sequence to
|
||||
* minimize space usage.
|
||||
* @param[in,out] data <tt>const unsigned char*</tt>: The buffer containing the
|
||||
* packet to strip.
|
||||
* @param len <tt>opus_int32</tt>: The size of the packet.
|
||||
* This must be at least 1.
|
||||
* @returns The new size of the output packet on success, or an error code
|
||||
* on failure.
|
||||
* @retval #OPUS_BAD_ARG \a len was less than 1.
|
||||
* @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
|
||||
*/
|
||||
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_packet_unpad(unsigned char *data, opus_int32 len);
|
||||
|
||||
/** Pads a given Opus multi-stream packet to a larger size (possibly changing the TOC sequence).
|
||||
* @param[in,out] data <tt>const unsigned char*</tt>: The buffer containing the
|
||||
* packet to pad.
|
||||
* @param len <tt>opus_int32</tt>: The size of the packet.
|
||||
* This must be at least 1.
|
||||
* @param new_len <tt>opus_int32</tt>: The desired size of the packet after padding.
|
||||
* This must be at least 1.
|
||||
* @param nb_streams <tt>opus_int32</tt>: The number of streams (not channels) in the packet.
|
||||
* This must be at least as large as len.
|
||||
* @returns an error code
|
||||
* @retval #OPUS_OK \a on success.
|
||||
* @retval #OPUS_BAD_ARG \a len was less than 1.
|
||||
* @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
|
||||
*/
|
||||
OPUS_EXPORT int opus_multistream_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len, int nb_streams);
|
||||
|
||||
/** Remove all padding from a given Opus multi-stream packet and rewrite the TOC sequence to
|
||||
* minimize space usage.
|
||||
* @param[in,out] data <tt>const unsigned char*</tt>: The buffer containing the
|
||||
* packet to strip.
|
||||
* @param len <tt>opus_int32</tt>: The size of the packet.
|
||||
* This must be at least 1.
|
||||
* @param nb_streams <tt>opus_int32</tt>: The number of streams (not channels) in the packet.
|
||||
* This must be at least 1.
|
||||
* @returns The new size of the output packet on success, or an error code
|
||||
* on failure.
|
||||
* @retval #OPUS_BAD_ARG \a len was less than 1 or new_len was less than len.
|
||||
* @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
|
||||
*/
|
||||
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_packet_unpad(unsigned char *data, opus_int32 len, int nb_streams);
|
||||
|
||||
/**@}*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -42,15 +42,15 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef CUSTOM_MODES
|
||||
# define OPUS_CUSTOM_EXPORT OPUS_EXPORT
|
||||
# define OPUS_CUSTOM_EXPORT_STATIC OPUS_EXPORT
|
||||
#define OPUS_CUSTOM_EXPORT OPUS_EXPORT
|
||||
#define OPUS_CUSTOM_EXPORT_STATIC OPUS_EXPORT
|
||||
#else
|
||||
# define OPUS_CUSTOM_EXPORT
|
||||
# ifdef OPUS_BUILD
|
||||
# define OPUS_CUSTOM_EXPORT_STATIC static OPUS_INLINE
|
||||
# else
|
||||
# define OPUS_CUSTOM_EXPORT_STATIC
|
||||
# endif
|
||||
#define OPUS_CUSTOM_EXPORT
|
||||
#ifdef CELT_C
|
||||
#define OPUS_CUSTOM_EXPORT_STATIC static inline
|
||||
#else
|
||||
#define OPUS_CUSTOM_EXPORT_STATIC
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/** @defgroup opus_custom Opus Custom
|
||||
@@ -126,9 +126,6 @@ OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomMode *opus_custom_mode_crea
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT void opus_custom_mode_destroy(OpusCustomMode *mode);
|
||||
|
||||
|
||||
#if !defined(OPUS_BUILD) || defined(CELT_ENCODER_C)
|
||||
|
||||
/* Encoder */
|
||||
/** Gets the size of an OpusCustomEncoder structure.
|
||||
* @param [in] mode <tt>OpusCustomMode *</tt>: Mode configuration
|
||||
@@ -140,28 +137,6 @@ OPUS_CUSTOM_EXPORT_STATIC OPUS_WARN_UNUSED_RESULT int opus_custom_encoder_get_si
|
||||
int channels
|
||||
) OPUS_ARG_NONNULL(1);
|
||||
|
||||
# ifdef CUSTOM_MODES
|
||||
/** Initializes a previously allocated encoder state
|
||||
* The memory pointed to by st must be the size returned by opus_custom_encoder_get_size.
|
||||
* This is intended for applications which use their own allocator instead of malloc.
|
||||
* @see opus_custom_encoder_create(),opus_custom_encoder_get_size()
|
||||
* To reset a previously initialized state use the OPUS_RESET_STATE CTL.
|
||||
* @param [in] st <tt>OpusCustomEncoder*</tt>: Encoder state
|
||||
* @param [in] mode <tt>OpusCustomMode *</tt>: Contains all the information about the characteristics of
|
||||
* the stream (must be the same characteristics as used for the
|
||||
* decoder)
|
||||
* @param [in] channels <tt>int</tt>: Number of channels
|
||||
* @return OPUS_OK Success or @ref opus_errorcodes
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT int opus_custom_encoder_init(
|
||||
OpusCustomEncoder *st,
|
||||
const OpusCustomMode *mode,
|
||||
int channels
|
||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
/** Creates a new encoder state. Each stream needs its own encoder
|
||||
* state (can't be shared across simultaneous streams).
|
||||
* @param [in] mode <tt>OpusCustomMode*</tt>: Contains all the information about the characteristics of
|
||||
@@ -177,6 +152,23 @@ OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomEncoder *opus_custom_encode
|
||||
int *error
|
||||
) OPUS_ARG_NONNULL(1);
|
||||
|
||||
/** Initializes a previously allocated encoder state
|
||||
* The memory pointed to by st must be the size returned by opus_custom_encoder_get_size.
|
||||
* This is intended for applications which use their own allocator instead of malloc.
|
||||
* @see opus_custom_encoder_create(),opus_custom_encoder_get_size()
|
||||
* To reset a previously initialized state use the OPUS_RESET_STATE CTL.
|
||||
* @param [in] st <tt>OpusCustomEncoder*</tt>: Encoder state
|
||||
* @param [in] mode <tt>OpusCustomMode *</tt>: Contains all the information about the characteristics of
|
||||
* the stream (must be the same characteristics as used for the
|
||||
* decoder)
|
||||
* @param [in] channels <tt>int</tt>: Number of channels
|
||||
* @return OPUS_OK Success or @ref opus_errorcodes
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT_STATIC int opus_custom_encoder_init(
|
||||
OpusCustomEncoder *st,
|
||||
const OpusCustomMode *mode,
|
||||
int channels
|
||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2);
|
||||
|
||||
/** Destroys a an encoder state.
|
||||
* @param[in] st <tt>OpusCustomEncoder*</tt>: State to be freed.
|
||||
@@ -237,8 +229,6 @@ OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_encode(
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT int opus_custom_encoder_ctl(OpusCustomEncoder * OPUS_RESTRICT st, int request, ...) OPUS_ARG_NONNULL(1);
|
||||
|
||||
|
||||
#if !defined(OPUS_BUILD) || defined(CELT_DECODER_C)
|
||||
/* Decoder */
|
||||
|
||||
/** Gets the size of an OpusCustomDecoder structure.
|
||||
@@ -251,6 +241,20 @@ OPUS_CUSTOM_EXPORT_STATIC OPUS_WARN_UNUSED_RESULT int opus_custom_decoder_get_si
|
||||
int channels
|
||||
) OPUS_ARG_NONNULL(1);
|
||||
|
||||
/** Creates a new decoder state. Each stream needs its own decoder state (can't
|
||||
* be shared across simultaneous streams).
|
||||
* @param [in] mode <tt>OpusCustomMode</tt>: Contains all the information about the characteristics of the
|
||||
* stream (must be the same characteristics as used for the encoder)
|
||||
* @param [in] channels <tt>int</tt>: Number of channels
|
||||
* @param [out] error <tt>int*</tt>: Returns an error code
|
||||
* @return Newly created decoder state.
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomDecoder *opus_custom_decoder_create(
|
||||
const OpusCustomMode *mode,
|
||||
int channels,
|
||||
int *error
|
||||
) OPUS_ARG_NONNULL(1);
|
||||
|
||||
/** Initializes a previously allocated decoder state
|
||||
* The memory pointed to by st must be the size returned by opus_custom_decoder_get_size.
|
||||
* This is intended for applications which use their own allocator instead of malloc.
|
||||
@@ -269,23 +273,6 @@ OPUS_CUSTOM_EXPORT_STATIC int opus_custom_decoder_init(
|
||||
int channels
|
||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/** Creates a new decoder state. Each stream needs its own decoder state (can't
|
||||
* be shared across simultaneous streams).
|
||||
* @param [in] mode <tt>OpusCustomMode</tt>: Contains all the information about the characteristics of the
|
||||
* stream (must be the same characteristics as used for the encoder)
|
||||
* @param [in] channels <tt>int</tt>: Number of channels
|
||||
* @param [out] error <tt>int*</tt>: Returns an error code
|
||||
* @return Newly created decoder state.
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomDecoder *opus_custom_decoder_create(
|
||||
const OpusCustomMode *mode,
|
||||
int channels,
|
||||
int *error
|
||||
) OPUS_ARG_NONNULL(1);
|
||||
|
||||
/** Destroys a an decoder state.
|
||||
* @param[in] st <tt>OpusCustomDecoder*</tt>: State to be freed.
|
||||
*/
|
||||
|
||||
@@ -46,7 +46,7 @@ extern "C" {
|
||||
#define OPUS_OK 0
|
||||
/** One or more invalid/out of range arguments @hideinitializer*/
|
||||
#define OPUS_BAD_ARG -1
|
||||
/** Not enough bytes allocated in the buffer @hideinitializer*/
|
||||
/** The mode struct passed is invalid @hideinitializer*/
|
||||
#define OPUS_BUFFER_TOO_SMALL -2
|
||||
/** An internal error was detected @hideinitializer*/
|
||||
#define OPUS_INTERNAL_ERROR -3
|
||||
@@ -98,18 +98,6 @@ extern "C" {
|
||||
# define OPUS_RESTRICT restrict
|
||||
#endif
|
||||
|
||||
#if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) )
|
||||
# if OPUS_GNUC_PREREQ(2,7)
|
||||
# define OPUS_INLINE __inline__
|
||||
# elif (defined(_MSC_VER))
|
||||
# define OPUS_INLINE __inline
|
||||
# else
|
||||
# define OPUS_INLINE
|
||||
# endif
|
||||
#else
|
||||
# define OPUS_INLINE inline
|
||||
#endif
|
||||
|
||||
/**Warning attributes for opus functions
|
||||
* NONNULL is not used in OPUS_BUILD to avoid the compiler optimizing out
|
||||
* some paranoid null checks. */
|
||||
@@ -160,11 +148,8 @@ extern "C" {
|
||||
#define OPUS_GET_GAIN_REQUEST 4045 /* Should have been 4035 */
|
||||
#define OPUS_SET_LSB_DEPTH_REQUEST 4036
|
||||
#define OPUS_GET_LSB_DEPTH_REQUEST 4037
|
||||
|
||||
#define OPUS_GET_LAST_PACKET_DURATION_REQUEST 4039
|
||||
#define OPUS_SET_EXPERT_FRAME_DURATION_REQUEST 4040
|
||||
#define OPUS_GET_EXPERT_FRAME_DURATION_REQUEST 4041
|
||||
#define OPUS_SET_PREDICTION_DISABLED_REQUEST 4042
|
||||
#define OPUS_GET_PREDICTION_DISABLED_REQUEST 4043
|
||||
|
||||
/* Don't use 4045, it's already taken by OPUS_GET_GAIN_REQUEST */
|
||||
|
||||
@@ -172,7 +157,6 @@ extern "C" {
|
||||
#define __opus_check_int(x) (((void)((x) == (opus_int32)0)), (opus_int32)(x))
|
||||
#define __opus_check_int_ptr(ptr) ((ptr) + ((ptr) - (opus_int32*)(ptr)))
|
||||
#define __opus_check_uint_ptr(ptr) ((ptr) + ((ptr) - (opus_uint32*)(ptr)))
|
||||
#define __opus_check_val16_ptr(ptr) ((ptr) + ((ptr) - (opus_val16*)(ptr)))
|
||||
/** @endcond */
|
||||
|
||||
/** @defgroup opus_ctlvalues Pre-defined values for CTL interface
|
||||
@@ -201,14 +185,6 @@ extern "C" {
|
||||
#define OPUS_BANDWIDTH_SUPERWIDEBAND 1104 /**<12 kHz bandpass @hideinitializer*/
|
||||
#define OPUS_BANDWIDTH_FULLBAND 1105 /**<20 kHz bandpass @hideinitializer*/
|
||||
|
||||
#define OPUS_FRAMESIZE_ARG 5000 /**< Select frame size from the argument (default) */
|
||||
#define OPUS_FRAMESIZE_2_5_MS 5001 /**< Use 2.5 ms frames */
|
||||
#define OPUS_FRAMESIZE_5_MS 5002 /**< Use 5 ms frames */
|
||||
#define OPUS_FRAMESIZE_10_MS 5003 /**< Use 10 ms frames */
|
||||
#define OPUS_FRAMESIZE_20_MS 5004 /**< Use 20 ms frames */
|
||||
#define OPUS_FRAMESIZE_40_MS 5005 /**< Use 40 ms frames */
|
||||
#define OPUS_FRAMESIZE_60_MS 5006 /**< Use 60 ms frames */
|
||||
|
||||
/**@}*/
|
||||
|
||||
|
||||
@@ -454,6 +430,14 @@ extern "C" {
|
||||
* @hideinitializer */
|
||||
#define OPUS_GET_APPLICATION(x) OPUS_GET_APPLICATION_REQUEST, __opus_check_int_ptr(x)
|
||||
|
||||
/** Gets the sampling rate the encoder or decoder was initialized with.
|
||||
* This simply returns the <code>Fs</code> value passed to opus_encoder_init()
|
||||
* or opus_decoder_init().
|
||||
* @param[out] x <tt>opus_int32 *</tt>: Sampling rate of encoder or decoder.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define OPUS_GET_SAMPLE_RATE(x) OPUS_GET_SAMPLE_RATE_REQUEST, __opus_check_int_ptr(x)
|
||||
|
||||
/** Gets the total samples of delay added by the entire codec.
|
||||
* This can be queried by the encoder and then the provided number of samples can be
|
||||
* skipped on from the start of the decoder's output to provide time aligned input
|
||||
@@ -537,52 +521,10 @@ extern "C" {
|
||||
* @hideinitializer */
|
||||
#define OPUS_GET_LSB_DEPTH(x) OPUS_GET_LSB_DEPTH_REQUEST, __opus_check_int_ptr(x)
|
||||
|
||||
/** Configures the encoder's use of variable duration frames.
|
||||
* When variable duration is enabled, the encoder is free to use a shorter frame
|
||||
* size than the one requested in the opus_encode*() call.
|
||||
* It is then the user's responsibility
|
||||
* to verify how much audio was encoded by checking the ToC byte of the encoded
|
||||
* packet. The part of the audio that was not encoded needs to be resent to the
|
||||
* encoder for the next call. Do not use this option unless you <b>really</b>
|
||||
* know what you are doing.
|
||||
* @see OPUS_GET_EXPERT_VARIABLE_DURATION
|
||||
* @param[in] x <tt>opus_int32</tt>: Allowed values:
|
||||
* <dl>
|
||||
* <dt>OPUS_FRAMESIZE_ARG</dt><dd>Select frame size from the argument (default).</dd>
|
||||
* <dt>OPUS_FRAMESIZE_2_5_MS</dt><dd>Use 2.5 ms frames.</dd>
|
||||
* <dt>OPUS_FRAMESIZE_5_MS</dt><dd>Use 2.5 ms frames.</dd>
|
||||
* <dt>OPUS_FRAMESIZE_10_MS</dt><dd>Use 10 ms frames.</dd>
|
||||
* <dt>OPUS_FRAMESIZE_20_MS</dt><dd>Use 20 ms frames.</dd>
|
||||
* <dt>OPUS_FRAMESIZE_40_MS</dt><dd>Use 40 ms frames.</dd>
|
||||
* <dt>OPUS_FRAMESIZE_60_MS</dt><dd>Use 60 ms frames.</dd>
|
||||
* <dt>OPUS_FRAMESIZE_VARIABLE</dt><dd>Optimize the frame size dynamically.</dd>
|
||||
* </dl>
|
||||
/** Gets the duration (in samples) of the last packet successfully decoded or concealed.
|
||||
* @param[out] x <tt>opus_int32 *</tt>: Number of samples (at current sampling rate).
|
||||
* @hideinitializer */
|
||||
#define OPUS_SET_EXPERT_FRAME_DURATION(x) OPUS_SET_EXPERT_FRAME_DURATION_REQUEST, __opus_check_int(x)
|
||||
/** Gets the encoder's configured use of variable duration frames.
|
||||
* @see OPUS_SET_EXPERT_VARIABLE_DURATION
|
||||
* @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
|
||||
* <dl>
|
||||
* <dt>OPUS_FRAMESIZE_ARG</dt><dd>Select frame size from the argument (default).</dd>
|
||||
* <dt>OPUS_FRAMESIZE_2_5_MS</dt><dd>Use 2.5 ms frames.</dd>
|
||||
* <dt>OPUS_FRAMESIZE_5_MS</dt><dd>Use 2.5 ms frames.</dd>
|
||||
* <dt>OPUS_FRAMESIZE_10_MS</dt><dd>Use 10 ms frames.</dd>
|
||||
* <dt>OPUS_FRAMESIZE_20_MS</dt><dd>Use 20 ms frames.</dd>
|
||||
* <dt>OPUS_FRAMESIZE_40_MS</dt><dd>Use 40 ms frames.</dd>
|
||||
* <dt>OPUS_FRAMESIZE_60_MS</dt><dd>Use 60 ms frames.</dd>
|
||||
* <dt>OPUS_FRAMESIZE_VARIABLE</dt><dd>Optimize the frame size dynamically.</dd>
|
||||
* </dl>
|
||||
* @hideinitializer */
|
||||
#define OPUS_GET_EXPERT_FRAME_DURATION(x) OPUS_GET_EXPERT_FRAME_DURATION_REQUEST, __opus_check_int_ptr(x)
|
||||
|
||||
/** If set to 1, disables almost all use of prediction, making frames almost
|
||||
completely independent. This reduces quality. (default : 0)
|
||||
* @hideinitializer */
|
||||
#define OPUS_SET_PREDICTION_DISABLED(x) OPUS_SET_PREDICTION_DISABLED_REQUEST, __opus_check_int(x)
|
||||
/** Gets the encoder's configured prediction status.
|
||||
* @hideinitializer */
|
||||
#define OPUS_GET_PREDICTION_DISABLED(x) OPUS_GET_PREDICTION_DISABLED_REQUEST, __opus_check_int_ptr(x)
|
||||
|
||||
#define OPUS_GET_LAST_PACKET_DURATION(x) OPUS_GET_LAST_PACKET_DURATION_REQUEST, __opus_check_int_ptr(x)
|
||||
/**@}*/
|
||||
|
||||
/** @defgroup opus_genericctls Generic CTLs
|
||||
@@ -636,6 +578,18 @@ extern "C" {
|
||||
* @hideinitializer */
|
||||
#define OPUS_GET_FINAL_RANGE(x) OPUS_GET_FINAL_RANGE_REQUEST, __opus_check_uint_ptr(x)
|
||||
|
||||
/** Gets the pitch of the last decoded frame, if available.
|
||||
* This can be used for any post-processing algorithm requiring the use of pitch,
|
||||
* e.g. time stretching/shortening. If the last frame was not voiced, or if the
|
||||
* pitch was not coded in the frame, then zero is returned.
|
||||
*
|
||||
* This CTL is only implemented for decoder instances.
|
||||
*
|
||||
* @param[out] x <tt>opus_int32 *</tt>: pitch period at 48 kHz (or 0 if not available)
|
||||
*
|
||||
* @hideinitializer */
|
||||
#define OPUS_GET_PITCH(x) OPUS_GET_PITCH_REQUEST, __opus_check_int_ptr(x)
|
||||
|
||||
/** Gets the encoder's configured bandpass or the decoder's last bandpass.
|
||||
* @see OPUS_SET_BANDWIDTH
|
||||
* @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
|
||||
@@ -650,14 +604,6 @@ extern "C" {
|
||||
* @hideinitializer */
|
||||
#define OPUS_GET_BANDWIDTH(x) OPUS_GET_BANDWIDTH_REQUEST, __opus_check_int_ptr(x)
|
||||
|
||||
/** Gets the sampling rate the encoder or decoder was initialized with.
|
||||
* This simply returns the <code>Fs</code> value passed to opus_encoder_init()
|
||||
* or opus_decoder_init().
|
||||
* @param[out] x <tt>opus_int32 *</tt>: Sampling rate of encoder or decoder.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define OPUS_GET_SAMPLE_RATE(x) OPUS_GET_SAMPLE_RATE_REQUEST, __opus_check_int_ptr(x)
|
||||
|
||||
/**@}*/
|
||||
|
||||
/** @defgroup opus_decoderctls Decoder related CTLs
|
||||
@@ -682,23 +628,6 @@ extern "C" {
|
||||
* @hideinitializer */
|
||||
#define OPUS_GET_GAIN(x) OPUS_GET_GAIN_REQUEST, __opus_check_int_ptr(x)
|
||||
|
||||
/** Gets the duration (in samples) of the last packet successfully decoded or concealed.
|
||||
* @param[out] x <tt>opus_int32 *</tt>: Number of samples (at current sampling rate).
|
||||
* @hideinitializer */
|
||||
#define OPUS_GET_LAST_PACKET_DURATION(x) OPUS_GET_LAST_PACKET_DURATION_REQUEST, __opus_check_int_ptr(x)
|
||||
|
||||
/** Gets the pitch of the last decoded frame, if available.
|
||||
* This can be used for any post-processing algorithm requiring the use of pitch,
|
||||
* e.g. time stretching/shortening. If the last frame was not voiced, or if the
|
||||
* pitch was not coded in the frame, then zero is returned.
|
||||
*
|
||||
* This CTL is only implemented for decoder instances.
|
||||
*
|
||||
* @param[out] x <tt>opus_int32 *</tt>: pitch period at 48 kHz (or 0 if not available)
|
||||
*
|
||||
* @hideinitializer */
|
||||
#define OPUS_GET_PITCH(x) OPUS_GET_PITCH_REQUEST, __opus_check_int_ptr(x)
|
||||
|
||||
/**@}*/
|
||||
|
||||
/** @defgroup opus_libinfo Opus library information functions
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<string name="app_name">Limelight</string>
|
||||
<string name="app_name">Limelight (Root)</string>
|
||||
<string name="title_activity_game">Game</string>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.net.UnknownHostException;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
import com.limelight.computers.ComputerManagerService;
|
||||
import com.limelight.root.R;
|
||||
import com.limelight.utils.Dialog;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.limelight;
|
||||
|
||||
import com.limelight.root.R;
|
||||
import com.limelight.utils.Dialog;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.limelight.binding.PlatformBinding;
|
||||
import com.limelight.nvstream.http.GfeHttpResponseException;
|
||||
import com.limelight.nvstream.http.NvApp;
|
||||
import com.limelight.nvstream.http.NvHTTP;
|
||||
import com.limelight.root.R;
|
||||
import com.limelight.utils.Dialog;
|
||||
import com.limelight.utils.SpinnerDialog;
|
||||
|
||||
|
||||
+75
-217
@@ -14,6 +14,7 @@ import com.limelight.nvstream.StreamConfiguration;
|
||||
import com.limelight.nvstream.av.video.VideoDecoderRenderer;
|
||||
import com.limelight.nvstream.input.KeyboardPacket;
|
||||
import com.limelight.nvstream.input.MouseButtonPacket;
|
||||
import com.limelight.root.R;
|
||||
import com.limelight.utils.Dialog;
|
||||
import com.limelight.utils.SpinnerDialog;
|
||||
|
||||
@@ -35,7 +36,6 @@ import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
import android.view.View;
|
||||
import android.view.View.OnGenericMotionListener;
|
||||
import android.view.View.OnSystemUiVisibilityChangeListener;
|
||||
import android.view.View.OnTouchListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
@@ -44,8 +44,7 @@ import android.widget.Toast;
|
||||
|
||||
|
||||
public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
OnGenericMotionListener, OnTouchListener, NvConnectionListener, EvdevListener,
|
||||
OnSystemUiVisibilityChangeListener
|
||||
OnGenericMotionListener, OnTouchListener, NvConnectionListener, EvdevListener
|
||||
{
|
||||
private int lastMouseX = Integer.MIN_VALUE;
|
||||
private int lastMouseY = Integer.MIN_VALUE;
|
||||
@@ -71,11 +70,6 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
private boolean toastsDisabled;
|
||||
|
||||
private EvdevWatcher evdevWatcher;
|
||||
private int modifierFlags = 0;
|
||||
private boolean grabbedInput = true;
|
||||
private boolean grabComboDown = false;
|
||||
private static final int MODIFIER_CTRL = 0x1;
|
||||
private static final int MODIFIER_SHIFT = 0x2;
|
||||
|
||||
private ConfigurableDecoderRenderer decoderRenderer;
|
||||
|
||||
@@ -140,9 +134,6 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
|
||||
}
|
||||
|
||||
// Listen for UI visibility events
|
||||
getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(this);
|
||||
|
||||
// Change volume button behavior
|
||||
setVolumeControlStream(AudioManager.STREAM_MUSIC);
|
||||
|
||||
@@ -199,20 +190,16 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
String host = Game.this.getIntent().getStringExtra(EXTRA_HOST);
|
||||
String app = Game.this.getIntent().getStringExtra(EXTRA_APP);
|
||||
String uniqueId = Game.this.getIntent().getStringExtra(EXTRA_UNIQUEID);
|
||||
|
||||
// Initialize the connection
|
||||
conn = new NvConnection(host, uniqueId, Game.this,
|
||||
new StreamConfiguration(app, width, height, refreshRate, bitrate * 1000, sops),
|
||||
PlatformBinding.getCryptoProvider(this));
|
||||
keybTranslator = new KeyboardTranslator(conn);
|
||||
controllerHandler = new ControllerHandler(conn);
|
||||
|
||||
decoderRenderer = new ConfigurableDecoderRenderer();
|
||||
decoderRenderer.initializeWithFlags(drFlags);
|
||||
|
||||
StreamConfiguration config =
|
||||
new StreamConfiguration(app, width, height,
|
||||
refreshRate, bitrate * 1000, sops,
|
||||
(decoderRenderer.getCapabilities() &
|
||||
VideoDecoderRenderer.CAPABILITY_ADAPTIVE_RESOLUTION) != 0);
|
||||
|
||||
// Initialize the connection
|
||||
conn = new NvConnection(host, uniqueId, Game.this, config, PlatformBinding.getCryptoProvider(this));
|
||||
keybTranslator = new KeyboardTranslator(conn);
|
||||
controllerHandler = new ControllerHandler(conn);
|
||||
|
||||
SurfaceHolder sh = sv.getHolder();
|
||||
if (stretchToFit || !decoderRenderer.isHardwareAccelerated()) {
|
||||
@@ -280,11 +267,11 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
}
|
||||
};
|
||||
|
||||
private void hideSystemUi(int delay) {
|
||||
private void hideSystemUi() {
|
||||
Handler h = getWindow().getDecorView().getHandler();
|
||||
if (h != null) {
|
||||
h.removeCallbacks(hideSystemUi);
|
||||
h.postDelayed(hideSystemUi, delay);
|
||||
h.postDelayed(hideSystemUi, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,7 +283,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
Dialog.closeDialogs();
|
||||
|
||||
displayedFailureDialog = true;
|
||||
stopConnection();
|
||||
conn.stop();
|
||||
|
||||
int averageEndToEndLat = decoderRenderer.getAverageEndToEndLatency();
|
||||
int averageDecoderLat = decoderRenderer.getAverageDecoderLatency();
|
||||
@@ -314,6 +301,10 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
if (message != null) {
|
||||
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
if (evdevWatcher != null) {
|
||||
evdevWatcher.shutdown();
|
||||
}
|
||||
|
||||
finish();
|
||||
}
|
||||
@@ -325,80 +316,6 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
wifiLock.release();
|
||||
}
|
||||
|
||||
private Runnable toggleGrab = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
if (evdevWatcher != null) {
|
||||
if (grabbedInput) {
|
||||
evdevWatcher.ungrabAll();
|
||||
}
|
||||
else {
|
||||
evdevWatcher.regrabAll();
|
||||
}
|
||||
}
|
||||
|
||||
grabbedInput = !grabbedInput;
|
||||
}
|
||||
};
|
||||
|
||||
// Returns true if the key stroke was consumed
|
||||
private boolean handleMagicKeyCombos(short translatedKey, boolean down) {
|
||||
int modifierMask = 0;
|
||||
|
||||
// Mask off the high byte
|
||||
translatedKey &= 0xff;
|
||||
|
||||
if (translatedKey == KeyboardTranslator.VK_CONTROL) {
|
||||
modifierMask = MODIFIER_CTRL;
|
||||
}
|
||||
else if (translatedKey == KeyboardTranslator.VK_SHIFT) {
|
||||
modifierMask = MODIFIER_SHIFT;
|
||||
}
|
||||
|
||||
if (down) {
|
||||
this.modifierFlags |= modifierMask;
|
||||
}
|
||||
else {
|
||||
this.modifierFlags &= ~modifierMask;
|
||||
}
|
||||
|
||||
// Check if Ctrl+Shift+Z is pressed
|
||||
if (translatedKey == KeyboardTranslator.VK_Z &&
|
||||
(modifierFlags & (MODIFIER_CTRL|MODIFIER_SHIFT)) == (MODIFIER_CTRL|MODIFIER_SHIFT))
|
||||
{
|
||||
if (down) {
|
||||
// Now that we've pressed the magic combo
|
||||
// we'll wait for one of the keys to come up
|
||||
grabComboDown = true;
|
||||
}
|
||||
else {
|
||||
// Toggle the grab if Z comes up
|
||||
Handler h = getWindow().getDecorView().getHandler();
|
||||
if (h != null) {
|
||||
h.postDelayed(toggleGrab, 250);
|
||||
}
|
||||
|
||||
grabComboDown = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
// Toggle the grab if control or shift comes up
|
||||
else if (grabComboDown) {
|
||||
Handler h = getWindow().getDecorView().getHandler();
|
||||
if (h != null) {
|
||||
h.postDelayed(toggleGrab, 250);
|
||||
}
|
||||
|
||||
grabComboDown = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Not a special combo
|
||||
return false;
|
||||
}
|
||||
|
||||
private static byte getModifierState(KeyEvent event) {
|
||||
byte modifier = 0;
|
||||
if (event.isShiftPressed()) {
|
||||
@@ -434,21 +351,6 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
// Let this method take duplicate key down events
|
||||
if (handleMagicKeyCombos(translated, true)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Eat repeat down events
|
||||
if (event.getRepeatCount() > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Pass through keyboard input if we're not grabbing
|
||||
if (!grabbedInput) {
|
||||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
keybTranslator.sendKeyDown(translated,
|
||||
getModifierState(event));
|
||||
}
|
||||
@@ -458,6 +360,16 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
|
||||
@Override
|
||||
public boolean onKeyUp(int keyCode, KeyEvent event) {
|
||||
// Pressing a volume button drops the immersive flag so the UI shows up again and doesn't
|
||||
// go away. I'm not sure if that's a bug or a feature, but we're working around it here
|
||||
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
|
||||
Handler h = getWindow().getDecorView().getHandler();
|
||||
if (h != null) {
|
||||
h.removeCallbacks(hideSystemUi);
|
||||
h.postDelayed(hideSystemUi, 2000);
|
||||
}
|
||||
}
|
||||
|
||||
InputDevice dev = event.getDevice();
|
||||
if (dev == null) {
|
||||
return super.onKeyUp(keyCode, event);
|
||||
@@ -477,15 +389,6 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
return super.onKeyUp(keyCode, event);
|
||||
}
|
||||
|
||||
if (handleMagicKeyCombos(translated, false)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Pass through keyboard input if we're not grabbing
|
||||
if (!grabbedInput) {
|
||||
return super.onKeyUp(keyCode, event);
|
||||
}
|
||||
|
||||
keybTranslator.sendKeyUp(translated,
|
||||
getModifierState(event));
|
||||
}
|
||||
@@ -502,35 +405,25 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true if the event was consumed
|
||||
private boolean handleMotionEvent(MotionEvent event) {
|
||||
// Pass through keyboard input if we're not grabbing
|
||||
if (!grabbedInput) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
|
||||
if (controllerHandler.handleMotionEvent(event)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0)
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0)
|
||||
{
|
||||
// This case is for touch-based input devices
|
||||
if (event.getSource() == InputDevice.SOURCE_TOUCHSCREEN ||
|
||||
event.getSource() == InputDevice.SOURCE_STYLUS)
|
||||
event.getSource() == InputDevice.SOURCE_STYLUS)
|
||||
{
|
||||
int actionIndex = event.getActionIndex();
|
||||
|
||||
|
||||
int eventX = (int)event.getX(actionIndex);
|
||||
int eventY = (int)event.getY(actionIndex);
|
||||
|
||||
|
||||
TouchContext context = getTouchContext(actionIndex);
|
||||
if (context == null) {
|
||||
return false;
|
||||
return super.onTouchEvent(event);
|
||||
}
|
||||
|
||||
|
||||
switch (event.getActionMasked())
|
||||
{
|
||||
case MotionEvent.ACTION_POINTER_DOWN:
|
||||
@@ -553,7 +446,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
return super.onTouchEvent(event);
|
||||
}
|
||||
}
|
||||
// This case is for mice
|
||||
@@ -561,12 +454,6 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
{
|
||||
int changedButtons = event.getButtonState() ^ lastButtonState;
|
||||
|
||||
if (event.getActionMasked() == MotionEvent.ACTION_SCROLL) {
|
||||
// Send the vertical scroll packet
|
||||
byte vScrollClicks = (byte) event.getAxisValue(MotionEvent.AXIS_VSCROLL);
|
||||
conn.sendMouseScroll(vScrollClicks);
|
||||
}
|
||||
|
||||
if ((changedButtons & MotionEvent.BUTTON_PRIMARY) != 0) {
|
||||
if ((event.getButtonState() & MotionEvent.BUTTON_PRIMARY) != 0) {
|
||||
conn.sendMouseButtonDown(MouseButtonPacket.BUTTON_LEFT);
|
||||
@@ -575,7 +462,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
conn.sendMouseButtonUp(MouseButtonPacket.BUTTON_LEFT);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ((changedButtons & MotionEvent.BUTTON_SECONDARY) != 0) {
|
||||
if ((event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) {
|
||||
conn.sendMouseButtonDown(MouseButtonPacket.BUTTON_RIGHT);
|
||||
@@ -584,7 +471,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
conn.sendMouseButtonUp(MouseButtonPacket.BUTTON_RIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ((changedButtons & MotionEvent.BUTTON_TERTIARY) != 0) {
|
||||
if ((event.getButtonState() & MotionEvent.BUTTON_TERTIARY) != 0) {
|
||||
conn.sendMouseButtonDown(MouseButtonPacket.BUTTON_MIDDLE);
|
||||
@@ -593,41 +480,47 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
conn.sendMouseButtonUp(MouseButtonPacket.BUTTON_MIDDLE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
updateMousePosition((int)event.getX(), (int)event.getY());
|
||||
|
||||
|
||||
lastButtonState = event.getButtonState();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unknown source
|
||||
return false;
|
||||
return super.onTouchEvent(event);
|
||||
}
|
||||
|
||||
// Handled a known source
|
||||
return true;
|
||||
}
|
||||
|
||||
// Unknown class
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
if (!handleMotionEvent(event)) {
|
||||
return super.onTouchEvent(event);
|
||||
}
|
||||
|
||||
return true;
|
||||
return super.onTouchEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onGenericMotionEvent(MotionEvent event) {
|
||||
if (!handleMotionEvent(event)) {
|
||||
return super.onGenericMotionEvent(event);
|
||||
if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
|
||||
if (controllerHandler.handleMotionEvent(event)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0)
|
||||
{
|
||||
switch (event.getActionMasked())
|
||||
{
|
||||
case MotionEvent.ACTION_HOVER_MOVE:
|
||||
// Send a mouse move update (if neccessary)
|
||||
updateMousePosition((int)event.getX(), (int)event.getY());
|
||||
break;
|
||||
case MotionEvent.ACTION_SCROLL:
|
||||
// Send the vertical scroll packet
|
||||
byte vScrollClicks = (byte) event.getAxisValue(MotionEvent.AXIS_VSCROLL);
|
||||
conn.sendMouseScroll(vScrollClicks);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
return super.onGenericMotionEvent(event);
|
||||
}
|
||||
|
||||
private void updateMousePosition(int eventX, int eventY) {
|
||||
@@ -655,13 +548,15 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
|
||||
@Override
|
||||
public boolean onGenericMotion(View v, MotionEvent event) {
|
||||
return handleMotionEvent(event);
|
||||
// Send it to the activity's motion event handler
|
||||
return onGenericMotionEvent(event);
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
return handleMotionEvent(event);
|
||||
// Send it to the activity's touch event handler
|
||||
return onTouchEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -674,19 +569,6 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
@Override
|
||||
public void stageComplete(Stage stage) {
|
||||
}
|
||||
|
||||
private void stopConnection() {
|
||||
if (connecting || connected) {
|
||||
connecting = connected = false;
|
||||
conn.stop();
|
||||
}
|
||||
|
||||
// Close the Evdev watcher to allow use of captured input devices
|
||||
if (evdevWatcher != null) {
|
||||
evdevWatcher.shutdown();
|
||||
evdevWatcher = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stageFailed(Stage stage) {
|
||||
@@ -697,8 +579,9 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
|
||||
if (!displayedFailureDialog) {
|
||||
displayedFailureDialog = true;
|
||||
stopConnection();
|
||||
Dialog.displayDialog(this, "Connection Error", "Starting "+stage.getName()+" failed", true);
|
||||
conn.stop();
|
||||
connecting = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -707,9 +590,9 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
if (!displayedFailureDialog) {
|
||||
displayedFailureDialog = true;
|
||||
e.printStackTrace();
|
||||
|
||||
stopConnection();
|
||||
Dialog.displayDialog(this, "Connection Terminated", "The connection failed unexpectedly", true);
|
||||
conn.stop();
|
||||
connected = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -723,7 +606,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
connecting = false;
|
||||
connected = true;
|
||||
|
||||
hideSystemUi(1000);
|
||||
hideSystemUi();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -771,7 +654,8 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
@Override
|
||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||
if (connected) {
|
||||
stopConnection();
|
||||
conn.stop();
|
||||
connected = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -813,13 +697,10 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
conn.sendMouseScroll(amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyboardEvent(boolean buttonDown, short keyCode) {
|
||||
short keyMap = keybTranslator.translate(keyCode);
|
||||
if (keyMap != 0) {
|
||||
if (handleMagicKeyCombos(keyMap, buttonDown)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (buttonDown) {
|
||||
keybTranslator.sendKeyDown(keyMap, (byte) 0);
|
||||
}
|
||||
@@ -828,27 +709,4 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSystemUiVisibilityChange(int visibility) {
|
||||
// Don't do anything if we're not connected
|
||||
if (!connected) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This flag is set for all devices
|
||||
if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
|
||||
hideSystemUi(2000);
|
||||
}
|
||||
// This flag is only set on 4.4+
|
||||
else if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT &&
|
||||
(visibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0) {
|
||||
hideSystemUi(2000);
|
||||
}
|
||||
// This flag is only set before 4.4+
|
||||
else if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.KITKAT &&
|
||||
(visibility & View.SYSTEM_UI_FLAG_LOW_PROFILE) == 0) {
|
||||
hideSystemUi(2000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
package com.limelight;
|
||||
|
||||
public class LimelightBuildProps {
|
||||
public static final boolean ROOT_BUILD = false;
|
||||
public static final boolean ROOT_BUILD = true;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import com.limelight.binding.PlatformBinding;
|
||||
import com.limelight.binding.crypto.AndroidCryptoProvider;
|
||||
import com.limelight.computers.ComputerManagerListener;
|
||||
import com.limelight.computers.ComputerManagerService;
|
||||
import com.limelight.nvstream.http.ComputerDetails;
|
||||
@@ -14,6 +13,7 @@ import com.limelight.nvstream.http.NvHTTP;
|
||||
import com.limelight.nvstream.http.PairingManager;
|
||||
import com.limelight.nvstream.http.PairingManager.PairState;
|
||||
import com.limelight.nvstream.wol.WakeOnLanSender;
|
||||
import com.limelight.root.R;
|
||||
import com.limelight.utils.Dialog;
|
||||
|
||||
import android.app.Activity;
|
||||
@@ -60,9 +60,6 @@ public class PcView extends Activity {
|
||||
|
||||
// Start updates
|
||||
startComputerUpdates();
|
||||
|
||||
// Force a keypair to be generated early to avoid discovery delays
|
||||
new AndroidCryptoProvider(PcView.this).getClientCertificate();
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
@@ -160,7 +157,7 @@ public class PcView extends Activity {
|
||||
}
|
||||
}
|
||||
|
||||
private void stopComputerUpdates(boolean wait) {
|
||||
private void stopComputerUpdates() {
|
||||
if (managerBinder != null) {
|
||||
if (!runningPolling) {
|
||||
return;
|
||||
@@ -169,11 +166,6 @@ public class PcView extends Activity {
|
||||
freezeUpdates = true;
|
||||
|
||||
managerBinder.stopPolling();
|
||||
|
||||
if (wait) {
|
||||
managerBinder.waitForPollingStopped();
|
||||
}
|
||||
|
||||
runningPolling = false;
|
||||
}
|
||||
}
|
||||
@@ -198,7 +190,7 @@ public class PcView extends Activity {
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
|
||||
stopComputerUpdates(false);
|
||||
stopComputerUpdates();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -210,7 +202,7 @@ public class PcView extends Activity {
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
|
||||
stopComputerUpdates(false);
|
||||
stopComputerUpdates();
|
||||
|
||||
// Call superclass
|
||||
super.onCreateContextMenu(menu, v, menuInfo);
|
||||
@@ -267,9 +259,6 @@ public class PcView extends Activity {
|
||||
NvHTTP httpConn;
|
||||
String message;
|
||||
try {
|
||||
// Stop updates and wait while pairing
|
||||
stopComputerUpdates(true);
|
||||
|
||||
InetAddress addr = null;
|
||||
if (computer.reachability == ComputerDetails.Reachability.LOCAL) {
|
||||
addr = computer.localIp;
|
||||
@@ -324,9 +313,6 @@ public class PcView extends Activity {
|
||||
Toast.makeText(PcView.this, toastMessage, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
|
||||
// Start polling again
|
||||
startComputerUpdates();
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.limelight;
|
||||
|
||||
import com.limelight.root.R;
|
||||
import com.limelight.utils.Dialog;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
@@ -51,8 +51,6 @@ public class AndroidCryptoProvider implements LimelightCryptoProvider {
|
||||
private RSAPrivateKey key;
|
||||
private byte[] pemCertBytes;
|
||||
|
||||
private static Object globalCryptoLock = new Object();
|
||||
|
||||
static {
|
||||
// Install the Bouncy Castle provider
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
@@ -210,7 +208,7 @@ public class AndroidCryptoProvider implements LimelightCryptoProvider {
|
||||
public X509Certificate getClientCertificate() {
|
||||
// Use a lock here to ensure only one guy will be generating or loading
|
||||
// the certificate and key at a time
|
||||
synchronized (globalCryptoLock) {
|
||||
synchronized (this) {
|
||||
// Return a loaded cert if we have one
|
||||
if (cert != null) {
|
||||
return cert;
|
||||
@@ -237,7 +235,7 @@ public class AndroidCryptoProvider implements LimelightCryptoProvider {
|
||||
public RSAPrivateKey getClientPrivateKey() {
|
||||
// Use a lock here to ensure only one guy will be generating or loading
|
||||
// the certificate and key at a time
|
||||
synchronized (globalCryptoLock) {
|
||||
synchronized (this) {
|
||||
// Return a loaded key if we have one
|
||||
if (key != null) {
|
||||
return key;
|
||||
@@ -262,7 +260,7 @@ public class AndroidCryptoProvider implements LimelightCryptoProvider {
|
||||
}
|
||||
|
||||
public byte[] getPemEncodedClientCertificate() {
|
||||
synchronized (globalCryptoLock) {
|
||||
synchronized (this) {
|
||||
// Call our helper function to do the cert loading/generation for us
|
||||
getClientCertificate();
|
||||
|
||||
|
||||
@@ -47,9 +47,6 @@ public class ControllerHandler {
|
||||
|
||||
public ControllerHandler(NvConnection conn) {
|
||||
this.conn = conn;
|
||||
|
||||
// We want limelight-common to scale the axis values to match Xinput values
|
||||
ControllerPacket.enableAxisScaling = true;
|
||||
}
|
||||
|
||||
private ControllerMapping createMappingForDevice(InputDevice dev) {
|
||||
@@ -138,15 +135,6 @@ public class ControllerHandler {
|
||||
InputDevice.MotionRange lsYRange = dev.getMotionRange(mapping.leftStickYAxis);
|
||||
if (lsXRange != null && lsYRange != null) {
|
||||
mapping.leftStickDeadzoneRadius = Math.max(lsXRange.getFlat(), lsYRange.getFlat());
|
||||
|
||||
// If there isn't a (reasonable) deadzone at all, use 20%
|
||||
if (mapping.leftStickDeadzoneRadius < 0.02f) {
|
||||
mapping.leftStickDeadzoneRadius = 0.20f;
|
||||
}
|
||||
// Check that the deadzone is 12% at minimum
|
||||
else if (mapping.leftStickDeadzoneRadius < 0.12f) {
|
||||
mapping.leftStickDeadzoneRadius = 0.12f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,15 +143,6 @@ public class ControllerHandler {
|
||||
InputDevice.MotionRange rsYRange = dev.getMotionRange(mapping.rightStickYAxis);
|
||||
if (rsXRange != null && rsYRange != null) {
|
||||
mapping.rightStickDeadzoneRadius = Math.max(rsXRange.getFlat(), rsYRange.getFlat());
|
||||
|
||||
// If there isn't a (reasonable) deadzone at all, use 20%
|
||||
if (mapping.rightStickDeadzoneRadius < 0.02f) {
|
||||
mapping.rightStickDeadzoneRadius = 0.20f;
|
||||
}
|
||||
// Check that the deadzone is 12% at minimum
|
||||
else if (mapping.rightStickDeadzoneRadius < 0.12f) {
|
||||
mapping.rightStickDeadzoneRadius = 0.12f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,7 +242,7 @@ public class ControllerHandler {
|
||||
// Scale the input based on the distance from the deadzone
|
||||
inputVector.getNormalized(normalizedInputVector);
|
||||
normalizedInputVector.scalarMultiply((inputVector.getMagnitude() - deadzoneRadius) / (1.0f - deadzoneRadius));
|
||||
|
||||
|
||||
// Bound the X value to -1.0 to 1.0
|
||||
if (normalizedInputVector.getX() > 1.0f) {
|
||||
normalizedInputVector.setX(1.0f);
|
||||
@@ -305,7 +284,7 @@ public class ControllerHandler {
|
||||
event.getAxisValue(mapping.rightStickYAxis), mapping.rightStickDeadzoneRadius);
|
||||
|
||||
rightStickX = (short)(rightStickVector.getX() * 0x7FFE);
|
||||
rightStickY = (short)(-rightStickVector.getY() * 0x7FFE);
|
||||
rightStickY = (short)(-rightStickVector.getY() * 0x7FFE);
|
||||
}
|
||||
|
||||
// Handle controllers with analog triggers
|
||||
|
||||
@@ -8,6 +8,7 @@ public class EvdevEvent {
|
||||
public static final short EV_SYN = 0x00;
|
||||
public static final short EV_KEY = 0x01;
|
||||
public static final short EV_REL = 0x02;
|
||||
public static final short EV_MSC = 0x04;
|
||||
|
||||
/* Relative axes */
|
||||
public static final short REL_X = 0x00;
|
||||
@@ -18,6 +19,15 @@ public class EvdevEvent {
|
||||
public static final short BTN_LEFT = 0x110;
|
||||
public static final short BTN_RIGHT = 0x111;
|
||||
public static final short BTN_MIDDLE = 0x112;
|
||||
public static final short BTN_SIDE = 0x113;
|
||||
public static final short BTN_EXTRA = 0x114;
|
||||
public static final short BTN_FORWARD = 0x115;
|
||||
public static final short BTN_BACK = 0x116;
|
||||
public static final short BTN_TASK = 0x117;
|
||||
public static final short BTN_GAMEPAD = 0x130;
|
||||
|
||||
/* Keys */
|
||||
public static final short KEY_Q = 16;
|
||||
|
||||
public short type;
|
||||
public short code;
|
||||
|
||||
@@ -10,6 +10,7 @@ public class EvdevHandler {
|
||||
private String absolutePath;
|
||||
private EvdevListener listener;
|
||||
private boolean shutdown = false;
|
||||
private int fd = -1;
|
||||
|
||||
private Thread handlerThread = new Thread() {
|
||||
@Override
|
||||
@@ -19,16 +20,17 @@ public class EvdevHandler {
|
||||
// system-wide input problems.
|
||||
|
||||
// Open the /dev/input/eventX file
|
||||
int fd = EvdevReader.open(absolutePath);
|
||||
fd = EvdevReader.open(absolutePath);
|
||||
if (fd == -1) {
|
||||
LimeLog.warning("Unable to open "+absolutePath);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Check if it's a mouse
|
||||
if (!EvdevReader.isMouse(fd)) {
|
||||
// We only handle mice
|
||||
// Check if it's a mouse or keyboard, but not a gamepad
|
||||
if ((!EvdevReader.isMouse(fd) && !EvdevReader.isAlphaKeyboard(fd)) ||
|
||||
EvdevReader.isGamepad(fd)) {
|
||||
// We only handle keyboards and mice
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -38,7 +40,7 @@ public class EvdevHandler {
|
||||
return;
|
||||
}
|
||||
|
||||
LimeLog.info("Grabbed device for raw mouse input: "+absolutePath);
|
||||
LimeLog.info("Grabbed device for raw keyboard/mouse input: "+absolutePath);
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.allocate(EvdevEvent.EVDEV_MAX_EVENT_SIZE).order(ByteOrder.nativeOrder());
|
||||
|
||||
@@ -96,7 +98,31 @@ public class EvdevHandler {
|
||||
listener.mouseButtonEvent(EvdevListener.BUTTON_RIGHT,
|
||||
event.value != 0);
|
||||
break;
|
||||
|
||||
case EvdevEvent.BTN_SIDE:
|
||||
case EvdevEvent.BTN_EXTRA:
|
||||
case EvdevEvent.BTN_FORWARD:
|
||||
case EvdevEvent.BTN_BACK:
|
||||
case EvdevEvent.BTN_TASK:
|
||||
// Other unhandled mouse buttons
|
||||
break;
|
||||
|
||||
default:
|
||||
// We got some unrecognized button. This means
|
||||
// someone is trying to use the other device in this
|
||||
// "combination" input device. We'll try to handle
|
||||
// it via keyboard, but we're not going to disconnect
|
||||
// if we can't
|
||||
short keyCode = EvdevTranslator.translateEvdevKeyCode(event.code);
|
||||
if (keyCode != 0) {
|
||||
listener.keyboardEvent(event.value != 0, keyCode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case EvdevEvent.EV_MSC:
|
||||
break;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
@@ -120,6 +146,13 @@ public class EvdevHandler {
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
// Close the fd. It doesn't matter if this races
|
||||
// with the handler thread. We'll close this out from
|
||||
// under the thread to wake it up
|
||||
if (fd != -1) {
|
||||
EvdevReader.close(fd);
|
||||
}
|
||||
|
||||
shutdown = true;
|
||||
handlerThread.interrupt();
|
||||
|
||||
|
||||
@@ -8,4 +8,5 @@ public interface EvdevListener {
|
||||
public void mouseMove(int deltaX, int deltaY);
|
||||
public void mouseButtonEvent(int buttonId, boolean down);
|
||||
public void mouseScroll(byte amount);
|
||||
public void keyboardEvent(boolean buttonDown, short keyCode);
|
||||
}
|
||||
|
||||
@@ -43,8 +43,26 @@ public class EvdevReader {
|
||||
public static native boolean grab(int fd);
|
||||
public static native boolean ungrab(int fd);
|
||||
|
||||
// Returns true if the device is a mouse
|
||||
public static native boolean isMouse(int fd);
|
||||
// Used for checking device capabilities
|
||||
public static native boolean hasRelAxis(int fd, short axis);
|
||||
public static native boolean hasAbsAxis(int fd, short axis);
|
||||
public static native boolean hasKey(int fd, short key);
|
||||
|
||||
public static boolean isMouse(int fd) {
|
||||
// This is the same check that Android does in EventHub.cpp
|
||||
return hasRelAxis(fd, EvdevEvent.REL_X) &&
|
||||
hasRelAxis(fd, EvdevEvent.REL_Y) &&
|
||||
hasKey(fd, EvdevEvent.BTN_LEFT);
|
||||
}
|
||||
|
||||
public static boolean isAlphaKeyboard(int fd) {
|
||||
// This is the same check that Android does in EventHub.cpp
|
||||
return hasKey(fd, EvdevEvent.KEY_Q);
|
||||
}
|
||||
|
||||
public static boolean isGamepad(int fd) {
|
||||
return hasKey(fd, EvdevEvent.BTN_GAMEPAD);
|
||||
}
|
||||
|
||||
// Returns the bytes read or -1 on error
|
||||
private static native int read(int fd, byte[] buffer);
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
package com.limelight.binding.input.evdev;
|
||||
|
||||
import android.view.KeyEvent;
|
||||
|
||||
public class EvdevTranslator {
|
||||
|
||||
public static final short EVDEV_KEY_CODES[] = {
|
||||
0, //KeyEvent.VK_RESERVED
|
||||
KeyEvent.KEYCODE_ESCAPE,
|
||||
KeyEvent.KEYCODE_1,
|
||||
KeyEvent.KEYCODE_2,
|
||||
KeyEvent.KEYCODE_3,
|
||||
KeyEvent.KEYCODE_4,
|
||||
KeyEvent.KEYCODE_5,
|
||||
KeyEvent.KEYCODE_6,
|
||||
KeyEvent.KEYCODE_7,
|
||||
KeyEvent.KEYCODE_8,
|
||||
KeyEvent.KEYCODE_9,
|
||||
KeyEvent.KEYCODE_0,
|
||||
KeyEvent.KEYCODE_MINUS,
|
||||
KeyEvent.KEYCODE_EQUALS,
|
||||
KeyEvent.KEYCODE_DEL,
|
||||
KeyEvent.KEYCODE_TAB,
|
||||
KeyEvent.KEYCODE_Q,
|
||||
KeyEvent.KEYCODE_W,
|
||||
KeyEvent.KEYCODE_E,
|
||||
KeyEvent.KEYCODE_R,
|
||||
KeyEvent.KEYCODE_T,
|
||||
KeyEvent.KEYCODE_Y,
|
||||
KeyEvent.KEYCODE_U,
|
||||
KeyEvent.KEYCODE_I,
|
||||
KeyEvent.KEYCODE_O,
|
||||
KeyEvent.KEYCODE_P,
|
||||
KeyEvent.KEYCODE_LEFT_BRACKET,
|
||||
KeyEvent.KEYCODE_RIGHT_BRACKET,
|
||||
KeyEvent.KEYCODE_ENTER,
|
||||
KeyEvent.KEYCODE_CTRL_LEFT,
|
||||
KeyEvent.KEYCODE_A,
|
||||
KeyEvent.KEYCODE_S,
|
||||
KeyEvent.KEYCODE_D,
|
||||
KeyEvent.KEYCODE_F,
|
||||
KeyEvent.KEYCODE_G,
|
||||
KeyEvent.KEYCODE_H,
|
||||
KeyEvent.KEYCODE_J,
|
||||
KeyEvent.KEYCODE_K,
|
||||
KeyEvent.KEYCODE_L,
|
||||
KeyEvent.KEYCODE_SEMICOLON,
|
||||
KeyEvent.KEYCODE_APOSTROPHE,
|
||||
KeyEvent.KEYCODE_GRAVE,
|
||||
KeyEvent.KEYCODE_SHIFT_LEFT,
|
||||
KeyEvent.KEYCODE_BACKSLASH,
|
||||
KeyEvent.KEYCODE_Z,
|
||||
KeyEvent.KEYCODE_X,
|
||||
KeyEvent.KEYCODE_C,
|
||||
KeyEvent.KEYCODE_V,
|
||||
KeyEvent.KEYCODE_B,
|
||||
KeyEvent.KEYCODE_N,
|
||||
KeyEvent.KEYCODE_M,
|
||||
KeyEvent.KEYCODE_COMMA,
|
||||
KeyEvent.KEYCODE_PERIOD,
|
||||
KeyEvent.KEYCODE_SLASH,
|
||||
KeyEvent.KEYCODE_SHIFT_RIGHT,
|
||||
KeyEvent.KEYCODE_NUMPAD_MULTIPLY,
|
||||
KeyEvent.KEYCODE_ALT_LEFT,
|
||||
KeyEvent.KEYCODE_SPACE,
|
||||
KeyEvent.KEYCODE_CAPS_LOCK,
|
||||
KeyEvent.KEYCODE_F1,
|
||||
KeyEvent.KEYCODE_F2,
|
||||
KeyEvent.KEYCODE_F3,
|
||||
KeyEvent.KEYCODE_F4,
|
||||
KeyEvent.KEYCODE_F5,
|
||||
KeyEvent.KEYCODE_F6,
|
||||
KeyEvent.KEYCODE_F7,
|
||||
KeyEvent.KEYCODE_F8,
|
||||
KeyEvent.KEYCODE_F9,
|
||||
KeyEvent.KEYCODE_F10,
|
||||
KeyEvent.KEYCODE_NUM_LOCK,
|
||||
KeyEvent.KEYCODE_SCROLL_LOCK,
|
||||
KeyEvent.KEYCODE_NUMPAD_7,
|
||||
KeyEvent.KEYCODE_NUMPAD_8,
|
||||
KeyEvent.KEYCODE_NUMPAD_9,
|
||||
KeyEvent.KEYCODE_NUMPAD_SUBTRACT,
|
||||
KeyEvent.KEYCODE_NUMPAD_4,
|
||||
KeyEvent.KEYCODE_NUMPAD_5,
|
||||
KeyEvent.KEYCODE_NUMPAD_6,
|
||||
KeyEvent.KEYCODE_NUMPAD_ADD,
|
||||
KeyEvent.KEYCODE_NUMPAD_1,
|
||||
KeyEvent.KEYCODE_NUMPAD_2,
|
||||
KeyEvent.KEYCODE_NUMPAD_3,
|
||||
KeyEvent.KEYCODE_NUMPAD_0,
|
||||
KeyEvent.KEYCODE_NUMPAD_DOT,
|
||||
0,
|
||||
0, //KeyEvent.VK_ZENKAKUHANKAKU,
|
||||
0, //KeyEvent.VK_102ND,
|
||||
KeyEvent.KEYCODE_F11,
|
||||
KeyEvent.KEYCODE_F12,
|
||||
0, //KeyEvent.VK_RO,
|
||||
0, //KeyEvent.VK_KATAKANA,
|
||||
0, //KeyEvent.VK_HIRAGANA,
|
||||
0, //KeyEvent.VK_HENKAN,
|
||||
0, //KeyEvent.VK_KATAKANAHIRAGANA,
|
||||
0, //KeyEvent.VK_MUHENKAN,
|
||||
0, //KeyEvent.VK_KPJPCOMMA,
|
||||
KeyEvent.KEYCODE_NUMPAD_ENTER,
|
||||
KeyEvent.KEYCODE_CTRL_RIGHT,
|
||||
KeyEvent.KEYCODE_NUMPAD_DIVIDE,
|
||||
KeyEvent.KEYCODE_SYSRQ,
|
||||
KeyEvent.KEYCODE_ALT_RIGHT,
|
||||
0, //KeyEvent.VK_LINEFEED,
|
||||
KeyEvent.KEYCODE_HOME,
|
||||
KeyEvent.KEYCODE_DPAD_UP,
|
||||
KeyEvent.KEYCODE_PAGE_UP,
|
||||
KeyEvent.KEYCODE_DPAD_LEFT,
|
||||
KeyEvent.KEYCODE_DPAD_RIGHT,
|
||||
KeyEvent.KEYCODE_MOVE_END,
|
||||
KeyEvent.KEYCODE_DPAD_DOWN,
|
||||
KeyEvent.KEYCODE_PAGE_DOWN,
|
||||
KeyEvent.KEYCODE_INSERT,
|
||||
KeyEvent.KEYCODE_FORWARD_DEL,
|
||||
0, //KeyEvent.VK_MACRO,
|
||||
0, //KeyEvent.VK_MUTE,
|
||||
0, //KeyEvent.VK_VOLUMEDOWN,
|
||||
0, //KeyEvent.VK_VOLUMEUP,
|
||||
0, //KeyEvent.VK_POWER, /* SC System Power Down */
|
||||
KeyEvent.KEYCODE_NUMPAD_EQUALS,
|
||||
0, //KeyEvent.VK_KPPLUSMINUS,
|
||||
KeyEvent.KEYCODE_BREAK,
|
||||
0, //KeyEvent.VK_SCALE, /* AL Compiz Scale (Expose) */
|
||||
};
|
||||
|
||||
public static short translateEvdevKeyCode(short evdevKeyCode) {
|
||||
if (evdevKeyCode < EVDEV_KEY_CODES.length) {
|
||||
return EVDEV_KEY_CODES[evdevKeyCode];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,7 +2,6 @@ package com.limelight.binding.input.evdev;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.limelight.LimeLog;
|
||||
|
||||
@@ -15,7 +14,6 @@ public class EvdevWatcher {
|
||||
private HashMap<String, EvdevHandler> handlers = new HashMap<String, EvdevHandler>();
|
||||
private boolean shutdown = false;
|
||||
private boolean init = false;
|
||||
private boolean ungrabbed = false;
|
||||
private EvdevListener listener;
|
||||
private Thread startThread;
|
||||
|
||||
@@ -44,11 +42,7 @@ public class EvdevWatcher {
|
||||
}
|
||||
|
||||
EvdevHandler handler = new EvdevHandler(PATH + "/" + fileName, listener);
|
||||
|
||||
// If we're ungrabbed now, don't start the handler
|
||||
if (!ungrabbed) {
|
||||
handler.start();
|
||||
}
|
||||
handler.start();
|
||||
|
||||
handlers.put(fileName, handler);
|
||||
}
|
||||
@@ -84,31 +78,6 @@ public class EvdevWatcher {
|
||||
return files;
|
||||
}
|
||||
|
||||
public void ungrabAll() {
|
||||
synchronized (handlers) {
|
||||
// Note that we're ungrabbed for now
|
||||
ungrabbed = true;
|
||||
|
||||
// Stop all handlers
|
||||
for (EvdevHandler handler : handlers.values()) {
|
||||
handler.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void regrabAll() {
|
||||
synchronized (handlers) {
|
||||
// We're regrabbing everything now
|
||||
ungrabbed = false;
|
||||
|
||||
for (Map.Entry<String, EvdevHandler> entry : handlers.entrySet()) {
|
||||
// We need to recreate each entry since we can't reuse a stopped one
|
||||
entry.setValue(new EvdevHandler(PATH + "/" + entry.getKey(), listener));
|
||||
entry.getValue().start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void start() {
|
||||
startThread = new Thread() {
|
||||
@Override
|
||||
@@ -150,15 +119,10 @@ public class EvdevWatcher {
|
||||
// Stop the observer
|
||||
observer.stopWatching();
|
||||
|
||||
synchronized (handlers) {
|
||||
synchronized (handlers) {
|
||||
// Stop creating new handlers
|
||||
shutdown = true;
|
||||
|
||||
// If we've already ungrabbed, there's nothing else to do
|
||||
if (ungrabbed) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Stop all handlers
|
||||
for (EvdevHandler handler : handlers.values()) {
|
||||
handler.stop();
|
||||
|
||||
@@ -38,7 +38,6 @@ public class AndroidCpuDecoderRenderer implements VideoDecoderRenderer {
|
||||
|
||||
private int cpuCount = Runtime.getRuntime().availableProcessors();
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private int findOptimalPerformanceLevel() {
|
||||
StringBuilder cpuInfo = new StringBuilder();
|
||||
BufferedReader br = null;
|
||||
@@ -94,7 +93,7 @@ public class AndroidCpuDecoderRenderer implements VideoDecoderRenderer {
|
||||
public boolean setup(int width, int height, int redrawRate, Object renderTarget, int drFlags) {
|
||||
this.targetFps = redrawRate;
|
||||
|
||||
int perfLevel = LOW_PERF; //findOptimalPerformanceLevel();
|
||||
int perfLevel = findOptimalPerformanceLevel();
|
||||
int threadCount;
|
||||
|
||||
int avcFlags = 0;
|
||||
|
||||
@@ -5,16 +5,12 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
|
||||
import org.jcodec.codecs.h264.io.model.SeqParameterSet;
|
||||
import org.jcodec.codecs.h264.io.model.VUIParameters;
|
||||
|
||||
import com.limelight.LimeLog;
|
||||
import com.limelight.nvstream.av.ByteBufferDescriptor;
|
||||
import com.limelight.nvstream.av.DecodeUnit;
|
||||
import com.limelight.nvstream.av.video.VideoDecoderRenderer;
|
||||
import com.limelight.nvstream.av.video.VideoDepacketizer;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.media.MediaCodec;
|
||||
import android.media.MediaCodecInfo;
|
||||
import android.media.MediaCodecInfo.CodecCapabilities;
|
||||
@@ -22,7 +18,6 @@ import android.media.MediaCodecInfo.CodecProfileLevel;
|
||||
import android.media.MediaCodecList;
|
||||
import android.media.MediaFormat;
|
||||
import android.media.MediaCodec.BufferInfo;
|
||||
import android.os.Build;
|
||||
import android.view.SurfaceHolder;
|
||||
|
||||
public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
|
||||
@@ -33,7 +28,6 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
|
||||
private boolean needsSpsBitstreamFixup;
|
||||
private boolean needsSpsNumRefFixup;
|
||||
private VideoDepacketizer depacketizer;
|
||||
private boolean adaptivePlayback;
|
||||
|
||||
private long totalTimeMs;
|
||||
private long decoderTimeMs;
|
||||
@@ -44,19 +38,11 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
|
||||
private int numPpsIn;
|
||||
private int numIframeIn;
|
||||
|
||||
public static final List<String> preferredDecoders;
|
||||
|
||||
private final static byte[] BITSTREAM_RESTRICTIONS = new byte[] {(byte) 0xF1, (byte) 0x83, 0x2A, 0x00};
|
||||
|
||||
public static final List<String> blacklistedDecoderPrefixes;
|
||||
public static final List<String> spsFixupBitstreamFixupDecoderPrefixes;
|
||||
public static final List<String> spsFixupNumRefFixupDecoderPrefixes;
|
||||
public static final List<String> whitelistedAdaptiveResolutionPrefixes;
|
||||
|
||||
static {
|
||||
preferredDecoders = new LinkedList<String>();
|
||||
|
||||
// This is the most reliable of Samsung's decoders
|
||||
preferredDecoders.add("OMX.SEC.AVC.Decoder");
|
||||
}
|
||||
|
||||
static {
|
||||
blacklistedDecoderPrefixes = new LinkedList<String>();
|
||||
@@ -76,59 +62,6 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
|
||||
spsFixupNumRefFixupDecoderPrefixes.add("omx.TI");
|
||||
spsFixupNumRefFixupDecoderPrefixes.add("omx.qcom");
|
||||
spsFixupNumRefFixupDecoderPrefixes.add("omx.sec");
|
||||
|
||||
whitelistedAdaptiveResolutionPrefixes = new LinkedList<String>();
|
||||
whitelistedAdaptiveResolutionPrefixes.add("omx.nvidia");
|
||||
whitelistedAdaptiveResolutionPrefixes.add("omx.qcom");
|
||||
whitelistedAdaptiveResolutionPrefixes.add("omx.sec");
|
||||
whitelistedAdaptiveResolutionPrefixes.add("omx.TI");
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.KITKAT)
|
||||
public MediaCodecDecoderRenderer() {
|
||||
//dumpDecoders();
|
||||
|
||||
MediaCodecInfo decoder = findProbableSafeDecoder();
|
||||
if (decoder == null) {
|
||||
decoder = findFirstDecoder();
|
||||
}
|
||||
if (decoder == null) {
|
||||
// This case is handled later in setup()
|
||||
return;
|
||||
}
|
||||
|
||||
decoderName = decoder.getName();
|
||||
|
||||
// Possibly enable adaptive playback on KitKat and above
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
try {
|
||||
if (decoder.getCapabilitiesForType("video/avc").
|
||||
isFeatureSupported(CodecCapabilities.FEATURE_AdaptivePlayback))
|
||||
{
|
||||
// This will make getCapabilities() return that adaptive playback is supported
|
||||
LimeLog.info("Adaptive playback supported (FEATURE_AdaptivePlayback)");
|
||||
adaptivePlayback = true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Tolerate buggy codecs
|
||||
}
|
||||
}
|
||||
|
||||
if (!adaptivePlayback) {
|
||||
if (isDecoderInList(whitelistedAdaptiveResolutionPrefixes, decoderName)) {
|
||||
LimeLog.info("Adaptive playback supported (whitelist)");
|
||||
adaptivePlayback = true;
|
||||
}
|
||||
}
|
||||
|
||||
needsSpsBitstreamFixup = isDecoderInList(spsFixupBitstreamFixupDecoderPrefixes, decoderName);
|
||||
needsSpsNumRefFixup = isDecoderInList(spsFixupNumRefFixupDecoderPrefixes, decoderName);
|
||||
if (needsSpsBitstreamFixup) {
|
||||
LimeLog.info("Decoder "+decoderName+" needs SPS bitstream restrictions fixup");
|
||||
}
|
||||
if (needsSpsNumRefFixup) {
|
||||
LimeLog.info("Decoder "+decoderName+" needs SPS ref num fixup");
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isDecoderInList(List<String> decoderList, String decoderName) {
|
||||
@@ -167,31 +100,6 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
|
||||
return str;
|
||||
}
|
||||
|
||||
private static MediaCodecInfo findPreferredDecoder() {
|
||||
// This is a different algorithm than the other findXXXDecoder functions,
|
||||
// because we want to evaluate the decoders in our list's order
|
||||
// rather than MediaCodecList's order
|
||||
|
||||
for (String preferredDecoder : preferredDecoders) {
|
||||
for (int i = 0; i < MediaCodecList.getCodecCount(); i++) {
|
||||
MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);
|
||||
|
||||
// Skip encoders
|
||||
if (codecInfo.isEncoder()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check for preferred decoders
|
||||
if (preferredDecoder.equalsIgnoreCase(codecInfo.getName())) {
|
||||
LimeLog.info("Preferred decoder choice is "+codecInfo.getName());
|
||||
return codecInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static MediaCodecInfo findFirstDecoder() {
|
||||
for (int i = 0; i < MediaCodecList.getCodecCount(); i++) {
|
||||
MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);
|
||||
@@ -220,13 +128,7 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
|
||||
}
|
||||
|
||||
public static MediaCodecInfo findProbableSafeDecoder() {
|
||||
// First look for a preferred decoder by name
|
||||
MediaCodecInfo info = findPreferredDecoder();
|
||||
if (info != null) {
|
||||
return info;
|
||||
}
|
||||
|
||||
// Now look for decoders we know are safe
|
||||
// First look for decoders we know are safe
|
||||
try {
|
||||
// If this function completes, it will determine if the decoder is safe
|
||||
return findKnownSafeDecoder();
|
||||
@@ -278,14 +180,21 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
|
||||
return null;
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.KITKAT)
|
||||
@Override
|
||||
public boolean setup(int width, int height, int redrawRate, Object renderTarget, int drFlags) {
|
||||
if (decoderName == null) {
|
||||
//dumpDecoders();
|
||||
|
||||
MediaCodecInfo decoder = findProbableSafeDecoder();
|
||||
if (decoder == null) {
|
||||
decoder = findFirstDecoder();
|
||||
}
|
||||
if (decoder == null) {
|
||||
LimeLog.severe("No available hardware decoder!");
|
||||
return false;
|
||||
}
|
||||
|
||||
decoderName = decoder.getName();
|
||||
|
||||
// Codecs have been known to throw all sorts of crazy runtime exceptions
|
||||
// due to implementation problems
|
||||
try {
|
||||
@@ -294,15 +203,16 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
|
||||
return false;
|
||||
}
|
||||
|
||||
MediaFormat videoFormat = MediaFormat.createVideoFormat("video/avc", width, height);
|
||||
|
||||
// Adaptive playback can also be enabled by the whitelist on pre-KitKat devices
|
||||
// so we don't fill these pre-KitKat
|
||||
if (adaptivePlayback && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
videoFormat.setInteger(MediaFormat.KEY_MAX_WIDTH, width);
|
||||
videoFormat.setInteger(MediaFormat.KEY_MAX_HEIGHT, height);
|
||||
needsSpsBitstreamFixup = isDecoderInList(spsFixupBitstreamFixupDecoderPrefixes, decoder.getName());
|
||||
needsSpsNumRefFixup = isDecoderInList(spsFixupNumRefFixupDecoderPrefixes, decoder.getName());
|
||||
if (needsSpsBitstreamFixup) {
|
||||
LimeLog.info("Decoder "+decoder.getName()+" needs SPS bitstream restrictions fixup");
|
||||
}
|
||||
if (needsSpsNumRefFixup) {
|
||||
LimeLog.info("Decoder "+decoder.getName()+" needs SPS ref num fixup");
|
||||
}
|
||||
|
||||
MediaFormat videoFormat = MediaFormat.createVideoFormat("video/avc", width, height);
|
||||
videoDecoder.configure(videoFormat, ((SurfaceHolder)renderTarget).getSurface(), null, 0);
|
||||
videoDecoder.setVideoScalingMode(MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT);
|
||||
|
||||
@@ -456,44 +366,63 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
|
||||
if (header.data[header.offset+4] == 0x67) {
|
||||
numSpsIn++;
|
||||
|
||||
if (needsSpsBitstreamFixup || needsSpsNumRefFixup) {
|
||||
ByteBuffer spsBuf = ByteBuffer.wrap(header.data);
|
||||
|
||||
// Skip to the start of the NALU data
|
||||
spsBuf.position(header.offset+5);
|
||||
|
||||
SeqParameterSet sps = SeqParameterSet.read(spsBuf);
|
||||
|
||||
if ((needsSpsBitstreamFixup || needsSpsNumRefFixup)) {
|
||||
byte last = header.data[header.length+header.offset-1];
|
||||
|
||||
// TI OMAP4 requires a reference frame count of 1 to decode successfully
|
||||
if (needsSpsNumRefFixup) {
|
||||
LimeLog.info("Fixing up num ref frames");
|
||||
sps.num_ref_frames = 1;
|
||||
this.replace(header, 80, 9, new byte[] {0x40}, 3);
|
||||
}
|
||||
|
||||
// The SPS that comes in the current H264 bytestream doesn't set bitstream_restriction_flag
|
||||
// or max_dec_frame_buffering which increases decoding latency on Tegra.
|
||||
// We manually modify the SPS here to speed-up decoding if the decoder was flagged as needing it.
|
||||
int spsLength;
|
||||
if (needsSpsBitstreamFixup) {
|
||||
LimeLog.info("Adding bitstream restrictions");
|
||||
|
||||
sps.vuiParams.bitstreamRestriction = new VUIParameters.BitstreamRestriction();
|
||||
sps.vuiParams.bitstreamRestriction.motion_vectors_over_pic_boundaries_flag = true;
|
||||
sps.vuiParams.bitstreamRestriction.max_bytes_per_pic_denom = 2;
|
||||
sps.vuiParams.bitstreamRestriction.max_bits_per_mb_denom = 1;
|
||||
sps.vuiParams.bitstreamRestriction.log2_max_mv_length_horizontal = 16;
|
||||
sps.vuiParams.bitstreamRestriction.log2_max_mv_length_vertical = 16;
|
||||
sps.vuiParams.bitstreamRestriction.num_reorder_frames = 0;
|
||||
sps.vuiParams.bitstreamRestriction.max_dec_frame_buffering = 1;
|
||||
if (!needsSpsNumRefFixup) {
|
||||
switch (header.length) {
|
||||
case 26:
|
||||
LimeLog.info("Adding bitstream restrictions to SPS (26)");
|
||||
buf.put(header.data, header.offset, 24);
|
||||
buf.put((byte) 0x11);
|
||||
buf.put((byte) 0xe3);
|
||||
buf.put((byte) 0x06);
|
||||
buf.put((byte) 0x50);
|
||||
spsLength = header.length + 2;
|
||||
break;
|
||||
case 27:
|
||||
LimeLog.info("Adding bitstream restrictions to SPS (27)");
|
||||
buf.put(header.data, header.offset, 25);
|
||||
buf.put((byte) 0x04);
|
||||
buf.put((byte) 0x78);
|
||||
buf.put((byte) 0xc1);
|
||||
buf.put((byte) 0x94);
|
||||
spsLength = header.length + 2;
|
||||
break;
|
||||
default:
|
||||
LimeLog.warning("Unknown SPS of length "+header.length);
|
||||
buf.put(header.data, header.offset, header.length);
|
||||
spsLength = header.length;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Set bitstream restrictions to only buffer single frame
|
||||
// (starts 9 bits before stop bit and 6 bits earlier because of the shortening above)
|
||||
this.replace(header, header.length*8+Integer.numberOfLeadingZeros(last & - last)%8-9-6, 2, BITSTREAM_RESTRICTIONS, 3*8);
|
||||
buf.put(header.data, header.offset, header.length);
|
||||
spsLength = header.length;
|
||||
}
|
||||
}
|
||||
else {
|
||||
buf.put(header.data, header.offset, header.length);
|
||||
spsLength = header.length;
|
||||
}
|
||||
|
||||
// Write the annex B header
|
||||
buf.put(header.data, header.offset, 5);
|
||||
|
||||
// Write the modified SPS to the input buffer
|
||||
sps.write(buf);
|
||||
|
||||
try {
|
||||
videoDecoder.queueInputBuffer(inputIndex,
|
||||
0, buf.position(),
|
||||
0, spsLength,
|
||||
currentTime * 1000, codecFlags);
|
||||
} catch (Exception e) {
|
||||
throw new RendererException(this, e, buf, codecFlags);
|
||||
@@ -524,8 +453,86 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
|
||||
|
||||
@Override
|
||||
public int getCapabilities() {
|
||||
return adaptivePlayback ?
|
||||
VideoDecoderRenderer.CAPABILITY_ADAPTIVE_RESOLUTION : 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace bits in array
|
||||
* @param source array in which bits should be replaced
|
||||
* @param srcOffset offset in bits where replacement should take place
|
||||
* @param srcLength length in bits of data that should be replaced
|
||||
* @param data data array with the the replacement data
|
||||
* @param dataLength length of replacement data in bits
|
||||
*/
|
||||
public void replace(ByteBufferDescriptor source, int srcOffset, int srcLength, byte[] data, int dataLength) {
|
||||
//Add 7 to always round up
|
||||
int length = (source.length*8-srcLength+dataLength+7)/8;
|
||||
|
||||
int bitOffset = srcOffset%8;
|
||||
int byteOffset = srcOffset/8;
|
||||
|
||||
byte dest[] = null;
|
||||
int offset = 0;
|
||||
if (length>source.length) {
|
||||
dest = new byte[length];
|
||||
|
||||
//Copy the first bytes
|
||||
System.arraycopy(source.data, source.offset, dest, offset, byteOffset);
|
||||
} else {
|
||||
dest = source.data;
|
||||
offset = source.offset;
|
||||
}
|
||||
|
||||
int byteLength = (bitOffset+dataLength+7)/8;
|
||||
int bitTrailing = 8 - (srcOffset+dataLength) % 8;
|
||||
for (int i=0;i<byteLength;i++) {
|
||||
byte result = 0;
|
||||
if (i != 0)
|
||||
result = (byte) (data[i-1] << 8-bitOffset);
|
||||
else if (bitOffset > 0)
|
||||
result = (byte) (source.data[byteOffset+source.offset] & (0xFF << 8-bitOffset));
|
||||
|
||||
if (i == 0 || i != byteLength-1) {
|
||||
byte moved = (byte) ((data[i]&0xFF) >>> bitOffset);
|
||||
result |= moved;
|
||||
}
|
||||
|
||||
if (i == byteLength-1 && bitTrailing > 0) {
|
||||
int sourceOffset = srcOffset+srcLength/8;
|
||||
int bitMove = (dataLength-srcLength)%8;
|
||||
if (bitMove<0) {
|
||||
result |= (byte) (source.data[sourceOffset+source.offset] << -bitMove & (0xFF >>> bitTrailing));
|
||||
result |= (byte) (source.data[sourceOffset+1+source.offset] << -bitMove & (0xFF >>> 8+bitMove));
|
||||
} else {
|
||||
byte moved = (byte) ((source.data[sourceOffset+source.offset]&0xFF) >>> bitOffset);
|
||||
result |= moved;
|
||||
}
|
||||
}
|
||||
|
||||
dest[i+byteOffset+offset] = result;
|
||||
}
|
||||
|
||||
//Source offset
|
||||
byteOffset += srcLength/8;
|
||||
bitOffset = (srcOffset+dataLength-srcLength)%8;
|
||||
|
||||
//Offset in destination
|
||||
int destOffset = (srcOffset+dataLength)/8;
|
||||
|
||||
for (int i=1;i<source.length-byteOffset;i++) {
|
||||
int diff = destOffset >= byteOffset-1?i:source.length-byteOffset-i;
|
||||
|
||||
byte result = 0;
|
||||
result = (byte) (source.data[byteOffset+diff-1+source.offset] << 8-bitOffset);
|
||||
byte moved = (byte) ((source.data[byteOffset+diff+source.offset]&0xFF) >>> bitOffset);
|
||||
result ^= moved;
|
||||
|
||||
dest[diff+destOffset+offset] = result;
|
||||
}
|
||||
|
||||
source.data = dest;
|
||||
source.offset = offset;
|
||||
source.length = length;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -46,8 +46,6 @@ public class ComputerManagerService extends Service {
|
||||
private ThreadPoolExecutor pollingPool;
|
||||
private Timer pollingTimer;
|
||||
private ComputerManagerListener listener = null;
|
||||
private AtomicInteger activePolls = new AtomicInteger(0);
|
||||
private boolean stopped;
|
||||
|
||||
private DiscoveryService.DiscoveryBinder discoveryBinder;
|
||||
private ServiceConnection discoveryServiceConnection = new ServiceConnection() {
|
||||
@@ -71,9 +69,6 @@ public class ComputerManagerService extends Service {
|
||||
|
||||
public class ComputerManagerBinder extends Binder {
|
||||
public void startPolling(ComputerManagerListener listener) {
|
||||
// Not stopped
|
||||
stopped = false;
|
||||
|
||||
// Set the listener
|
||||
ComputerManagerService.this.listener = listener;
|
||||
|
||||
@@ -97,14 +92,6 @@ public class ComputerManagerService extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
public void waitForPollingStopped() {
|
||||
while (activePolls.get() != 0) {
|
||||
try {
|
||||
Thread.sleep(250);
|
||||
} catch (InterruptedException e) {}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean addComputerBlocking(InetAddress addr) {
|
||||
return ComputerManagerService.this.addComputerBlocking(addr);
|
||||
}
|
||||
@@ -129,9 +116,6 @@ public class ComputerManagerService extends Service {
|
||||
|
||||
@Override
|
||||
public boolean onUnbind(Intent intent) {
|
||||
// Stopped now
|
||||
stopped = true;
|
||||
|
||||
// Stop mDNS autodiscovery
|
||||
discoveryBinder.stopDiscovery();
|
||||
|
||||
@@ -342,7 +326,7 @@ public class ComputerManagerService extends Service {
|
||||
polledDetails = tryPollIp(details.remoteIp);
|
||||
}
|
||||
|
||||
if (polledDetails == null && !details.localIp.equals(details.remoteIp)) {
|
||||
if (polledDetails == null) {
|
||||
// Failed, so let's try the fallback
|
||||
if (!localFirst) {
|
||||
polledDetails = tryPollIp(details.localIp);
|
||||
@@ -356,8 +340,7 @@ public class ComputerManagerService extends Service {
|
||||
polledDetails.reachability = !localFirst ? ComputerDetails.Reachability.LOCAL :
|
||||
ComputerDetails.Reachability.REMOTE;
|
||||
}
|
||||
}
|
||||
else if (polledDetails != null) {
|
||||
} else {
|
||||
polledDetails.reachability = localFirst ? ComputerDetails.Reachability.LOCAL :
|
||||
ComputerDetails.Reachability.REMOTE;
|
||||
}
|
||||
@@ -402,28 +385,15 @@ public class ComputerManagerService extends Service {
|
||||
public void run() {
|
||||
boolean newPc = (details.name == null);
|
||||
|
||||
// This is called from addComputerManually() where we don't
|
||||
// want to block the initial poll if polling is disabled, so
|
||||
// we explicitly let this through if we've never seen this
|
||||
// PC before. This path won't be triggered normally when polling
|
||||
// is disabled because the mDNS discovery is stopped.
|
||||
if (stopped && !newPc) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!getLocalDatabaseReference()) {
|
||||
return;
|
||||
}
|
||||
|
||||
activePolls.incrementAndGet();
|
||||
|
||||
// Poll the machine
|
||||
if (!doPollMachine(details)) {
|
||||
details.state = ComputerDetails.State.OFFLINE;
|
||||
details.reachability = ComputerDetails.Reachability.OFFLINE;
|
||||
}
|
||||
|
||||
activePolls.decrementAndGet();
|
||||
|
||||
// If it's online, update our persistent state
|
||||
if (details.state == ComputerDetails.State.ONLINE) {
|
||||
|
||||
Reference in New Issue
Block a user