Skip to content

Commit 57ff4aa

Browse files
committed
Android: Device rumble
1 parent d843f7b commit 57ff4aa

File tree

3 files changed

+97
-8
lines changed

3 files changed

+97
-8
lines changed

app/platforms/android-project/app/src/main/java/org/libsdl/app/PlatformUtils.java

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import android.content.Context;
66
import android.content.Intent;
77
import android.content.IntentFilter;
8+
import android.media.AudioAttributes;
89
import android.net.ConnectivityManager;
910
import android.net.Network;
1011
import android.net.NetworkCapabilities;
@@ -13,12 +14,20 @@
1314
import android.net.wifi.WifiInfo;
1415
import android.net.wifi.WifiManager;
1516
import android.os.BatteryManager;
17+
import android.os.Build;
1618
import android.os.Message;
19+
import android.os.VibrationAttributes;
20+
import android.os.VibrationEffect;
21+
import android.os.Vibrator;
1722
import android.provider.Settings;
1823
import android.view.Window;
1924
import android.view.WindowManager;
2025

2126
public class PlatformUtils {
27+
28+
private static Vibrator vibrator;
29+
private static boolean rumbleDisabled;
30+
2231
public static boolean isBatterySupported() {
2332
Context context = SDLActivity.getContext();
2433
Intent batteryIntent = context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
@@ -122,4 +131,83 @@ public static float getAppScreenBrightness(Activity activity) {
122131
if (lp.screenBrightness < 0) return getSystemScreenBrightness(activity);
123132
return lp.screenBrightness;
124133
}
134+
135+
public static void initDeviceRumble() {
136+
Context context = SDLActivity.getContext();
137+
vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
138+
rumbleDisabled = (vibrator == null || !vibrator.hasVibrator());
139+
// if (rumbleDisabled && BuildConfig.DEBUG)
140+
// {
141+
// Log.w("Rumble", "System does not have a Vibrator, or the permission is disabled. " +
142+
// "Rumble has been turned rest. Subsequent calls to static methods will have no effect.");
143+
// }
144+
}
145+
146+
public static void deviceRumble(short lowFreqMotor, short highFreqMotor) {
147+
if (rumbleDisabled) return;
148+
149+
Context context = SDLActivity.getContext();
150+
151+
short lowFreqMotorAdjusted = (short)(Math.min(lowFreqMotor, 0xFF));
152+
short highFreqMotorAdjusted = (short)(Math.min(highFreqMotor, 0xFF));
153+
154+
rumbleSingleVibrator(vibrator, lowFreqMotorAdjusted, highFreqMotorAdjusted);
155+
}
156+
157+
private static void rumbleSingleVibrator(Vibrator vibrator, short lowFreqMotor, short highFreqMotor) {
158+
// Since we can only use a single amplitude value, compute the desired amplitude
159+
// by taking 80% of the big motor and 33% of the small motor, then capping to 255.
160+
// NB: This value is now 0-255 as required by VibrationEffect.
161+
// short lowFreqMotorMSB = (short)((lowFreqMotor >> 8) & 0xFF);
162+
// short highFreqMotorMSB = (short)((highFreqMotor >> 8) & 0xFF);
163+
int simulatedAmplitude = Math.min(255, (int)((lowFreqMotor * 0.80) + (highFreqMotor * 0.33)));
164+
165+
if (simulatedAmplitude == 0) {
166+
// This case is easy - just cancel the current effect and get out.
167+
// NB: We cannot simply check lowFreqMotor == highFreqMotor == 0
168+
// because our simulatedAmplitude could be 0 even though our inputs
169+
// are not (ex: lowFreqMotor == 0 && highFreqMotor == 1).
170+
vibrator.cancel();
171+
return;
172+
}
173+
174+
// Attempt to use amplitude-based control if we're on Oreo and the device
175+
// supports amplitude-based vibration control.
176+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
177+
if (vibrator.hasAmplitudeControl()) {
178+
VibrationEffect effect = VibrationEffect.createOneShot(60000, simulatedAmplitude);
179+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
180+
VibrationAttributes vibrationAttributes = new VibrationAttributes.Builder()
181+
.setUsage(VibrationAttributes.USAGE_MEDIA)
182+
.build();
183+
vibrator.vibrate(effect, vibrationAttributes);
184+
}
185+
else {
186+
AudioAttributes audioAttributes = new AudioAttributes.Builder()
187+
.setUsage(AudioAttributes.USAGE_GAME)
188+
.build();
189+
vibrator.vibrate(effect, audioAttributes);
190+
}
191+
return;
192+
}
193+
}
194+
195+
// If we reach this point, we don't have amplitude controls available, so
196+
// we must emulate it by PWMing the vibration. Ick.
197+
long pwmPeriod = 20;
198+
long onTime = (long)((simulatedAmplitude / 255.0) * pwmPeriod);
199+
long offTime = pwmPeriod - onTime;
200+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
201+
VibrationAttributes vibrationAttributes = new VibrationAttributes.Builder()
202+
.setUsage(VibrationAttributes.USAGE_MEDIA)
203+
.build();
204+
vibrator.vibrate(VibrationEffect.createWaveform(new long[]{0, onTime, offTime}, 0), vibrationAttributes);
205+
}
206+
else {
207+
AudioAttributes audioAttributes = new AudioAttributes.Builder()
208+
.setUsage(AudioAttributes.USAGE_GAME)
209+
.build();
210+
vibrator.vibrate(new long[]{0, onTime, offTime}, 0, audioAttributes);
211+
}
212+
}
125213
}

app/src/streaming/ffmpeg/FFmpegVideoDecoder.cpp

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,12 @@ extern "C" {
2626
#include <libavcodec/jni.h>
2727
#include <libavutil/hwcontext_mediacodec.h>
2828

29-
static JavaVM *mJavaVM = NULL;
30-
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
31-
{
32-
// av_jni_set_java_vm(vm, NULL);
33-
return JNI_VERSION_1_4;
34-
}
29+
//static JavaVM *mJavaVM = NULL;
30+
//JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
31+
//{
32+
//// av_jni_set_java_vm(vm, NULL);
33+
// return JNI_VERSION_1_4;
34+
//}
3535
#endif
3636

3737
FFmpegVideoDecoder::FFmpegVideoDecoder() {
@@ -119,8 +119,9 @@ int FFmpegVideoDecoder::setup(int video_format, int width, int height,
119119

120120
int decoder_threads = Settings::instance().decoder_threads();
121121

122-
if (decoder_threads == 0) {
122+
if (decoder_threads == 0 || Settings::instance().use_hw_decoding()) {
123123
m_decoder_context->thread_type = FF_THREAD_FRAME;
124+
m_decoder_context->thread_count = 1;
124125
} else {
125126
m_decoder_context->thread_type = FF_THREAD_SLICE;
126127
m_decoder_context->thread_count = decoder_threads;

0 commit comments

Comments
 (0)