Compare commits

..

10 Commits

Author SHA1 Message Date
Cameron Gutman e92a281fd8 Close the fd to wake the reading thread up for termination 2014-09-10 02:45:21 -07:00
Cameron Gutman b4c3f9678a Use poll() to avoid an infinite blocking read() that causes ANRs during cleanup 2014-09-10 02:35:55 -07:00
Cameron Gutman 82f79c466a Version to 2.5.4.1 2014-09-10 01:57:59 -07:00
Cameron Gutman d428f316b4 Don't unbind after an unexpected event 2014-09-10 01:57:24 -07:00
Cameron Gutman 828f4877b6 Only bind to keyboards and mice that aren't gamepads 2014-09-06 16:25:09 -07:00
Cameron Gutman 09e8e8e6b3 Remove isMouse() and replace it with more precise has*() functions 2014-09-06 16:03:09 -07:00
Cameron Gutman 77c8051ec6 Add support for keyboard and mouse combo devices in raw input mode 2014-09-06 14:09:09 -07:00
Cameron Gutman 6bae056e3a Fix a bug where an error change any permissions would cause the operation to fail and other files to not be changed 2014-09-03 23:33:25 -07:00
Cameron Gutman bb869a51fd Start using com.limelight.root package name 2014-09-03 23:32:37 -07:00
Cameron Gutman 25b3d08bb9 Revert "Remove root-specific stuff. DO NOT MERGE TO root!"
This reverts commit 2c23dbd2be.
2014-09-03 23:08:54 -07:00
41 changed files with 509 additions and 406 deletions
+6 -3
View File
@@ -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="34"
android:versionName="2.5.5" >
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;
};
+45 -10
View File
@@ -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.
+3 -10
View File
@@ -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
}
-72
View File
@@ -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
+39 -52
View File
@@ -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.
*/
+25 -96
View File
@@ -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 -1
View File
@@ -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
View File
@@ -1,5 +1,6 @@
package com.limelight;
import com.limelight.root.R;
import com.limelight.utils.Dialog;
import android.app.Activity;
+1
View File
@@ -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;
+21 -11
View File
@@ -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;
@@ -189,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()) {
@@ -699,4 +696,17 @@ public class Game extends Activity implements SurfaceHolder.Callback,
public void mouseScroll(byte amount) {
conn.sendMouseScroll(amount);
}
@Override
public void keyboardEvent(boolean buttonDown, short keyCode) {
short keyMap = keybTranslator.translate(keyCode);
if (keyMap != 0) {
if (buttonDown) {
keybTranslator.sendKeyDown(keyMap, (byte) 0);
}
else {
keybTranslator.sendKeyUp(keyMap, (byte) 0);
}
}
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
package com.limelight;
public class LimelightBuildProps {
public static final boolean ROOT_BUILD = false;
public static final boolean ROOT_BUILD = true;
}
+4 -14
View File
@@ -13,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;
@@ -156,7 +157,7 @@ public class PcView extends Activity {
}
}
private void stopComputerUpdates(boolean wait) {
private void stopComputerUpdates() {
if (managerBinder != null) {
if (!runningPolling) {
return;
@@ -165,11 +166,6 @@ public class PcView extends Activity {
freezeUpdates = true;
managerBinder.stopPolling();
if (wait) {
managerBinder.waitForPollingStopped();
}
runningPolling = false;
}
}
@@ -194,7 +190,7 @@ public class PcView extends Activity {
protected void onPause() {
super.onPause();
stopComputerUpdates(false);
stopComputerUpdates();
}
@Override
@@ -206,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);
@@ -263,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;
@@ -320,9 +313,6 @@ public class PcView extends Activity {
Toast.makeText(PcView.this, toastMessage, Toast.LENGTH_LONG).show();
}
});
// Start polling again
startComputerUpdates();
}
}).start();
}
+1
View File
@@ -1,5 +1,6 @@
package com.limelight;
import com.limelight.root.R;
import com.limelight.utils.Dialog;
import android.os.Bundle;
@@ -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;
}
}
@@ -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,10 +38,11 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
private int numPpsIn;
private int numIframeIn;
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 {
blacklistedDecoderPrefixes = new LinkedList<String>();
@@ -67,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) {
@@ -238,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 {
@@ -254,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);
@@ -416,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 = false;
sps.vuiParams.bitstreamRestriction.max_bytes_per_pic_denom = 0;
sps.vuiParams.bitstreamRestriction.max_bits_per_mb_denom = 0;
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);
@@ -484,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();
@@ -401,23 +385,15 @@ public class ComputerManagerService extends Service {
public void run() {
boolean newPc = (details.name == null);
if (stopped) {
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) {