### Robolectric Test Setup with Shadows Source: https://github.com/classicoldsong/moonlight-android/blob/moonlight-noir/android_test_setup.md Demonstrates the basic structure of a Robolectric test class. It configures the test runner, specifies SDK version, and includes custom shadows for native Android classes like MoonBridge and GameManager. The setup includes initializing a context and suppressing test logs. ```java import androidx.test.core.app.ApplicationProvider; import com.limelight.TestLogSuppressor; import org.junit.*; import org.robolectric.*; import org.robolectric.annotation.Config; @Config(sdk = {33}, shadows = {com.limelight.shadows.ShadowMoonBridge.class, com.limelight.shadows.ShadowGameManager.class}) @RunWith(RobolectricTestRunner.class) public class AwesomeFeatureTest { private Context ctx; @BeforeClass public static void init() { TestLogSuppressor.install(); } @Before public void setUp() { ctx = ApplicationProvider.getApplicationContext(); } @Test public void newFeature_doesSomething() { // Arrange // Act // Assert Assert.assertTrue(true); } } ``` ```java import android.content.Context; import androidx.test.core.app.ApplicationProvider; import com.limelight.TestLogSuppressor; import org.junit.*; import org.robolectric.*; import org.robolectric.annotation.Config; @Config(sdk = {33}, shadows = { com.limelight.shadows.ShadowMoonBridge.class, com.limelight.shadows.ShadowGameManager.class}) @RunWith(RobolectricTestRunner.class) public class MyFeatureTest { private Context ctx; @BeforeClass public static void silenceLogs() { TestLogSuppressor.install(); // hides noisy “Invalid ID 0x00000000” spam } @Before public void setUp() { ctx = ApplicationProvider.getApplicationContext(); // extra prep (clear prefs, reset singletons, etc.) } @Test public void something_should_work() { /* your assertions */ } } ``` -------------------------------- ### Robolectric Activity Testing in Java Source: https://github.com/classicoldsong/moonlight-android/blob/moonlight-noir/android_test_setup.md This Java code demonstrates how to use Robolectric's `buildActivity` utility to create, start, and resume an Android Activity within a unit test. It allows for assertions on the Activity's state, such as checking if it's finishing. ```java import org.robolectric.Robolectric; import android.app.Activity; import static org.junit.Assert.assertFalse; // ... inside a test method MyActivity act = Robolectric.buildActivity(MyActivity.class) .create().start().resume().get(); assertFalse(act.isFinishing()); ``` -------------------------------- ### Building and Interacting with an Activity Source: https://github.com/classicoldsong/moonlight-android/blob/moonlight-noir/android_test_setup.md Illustrates how to use Robolectric to build an Android Activity (`MyActivity`) and control its lifecycle (create, start, resume). It then asserts that the activity is not finishing, indicating successful lifecycle progression. ```java MyActivity act = Robolectric.buildActivity(MyActivity.class) .create().start().resume().get(); assertFalse(act.isFinishing()); ``` -------------------------------- ### Manage Game Streaming Connection with NvConnection (Java) Source: https://context7.com/classicoldsong/moonlight-android/llms.txt The NvConnection class handles the lifecycle of a game streaming connection, from establishment to termination. It manages session details and transmits all input events. This snippet demonstrates creating, configuring, starting, and stopping a streaming connection. ```java import android.content.Context; import android.util.Log; import java.security.cert.X509Certificate; // Assuming these classes are available in the Artemis Android library // import com.example.artemis.connection.NvConnection; // import com.example.artemis.connection.NvConnectionListener; // import com.example.artemis.crypto.AndroidCryptoProvider; // import com.example.artemis.crypto.LimelightCryptoProvider; // import com.example.artemis.model.ComputerDetails; // import com.example.artemis.model.NvApp; // import com.example.artemis.stream.StreamConfiguration; // import com.example.artemis.stream.MoonBridge; // Placeholder for actual context, renderers, and certificate Context context = null; // Replace with actual context Object audioRenderer = null; // Replace with actual audio renderer Object videoDecoderRenderer = null; // Replace with actual video decoder renderer X509Certificate serverCert = null; // Replace with obtained certificate // Create a streaming connection to a PC ComputerDetails.AddressTuple hostAddress = new ComputerDetails.AddressTuple("192.168.1.100", 47989); int httpsPort = 47984; String uniqueId = "your-unique-device-id"; LimelightCryptoProvider cryptoProvider = new AndroidCryptoProvider(context); // Configure stream settings StreamConfiguration config = new StreamConfiguration.Builder() .setResolution(1920, 1080) .setRefreshRate(60) .setBitrate(20000) // 20 Mbps .setSupportedVideoFormats(MoonBridge.VIDEO_FORMAT_H265) .setAudioConfiguration(MoonBridge.AUDIO_CONFIGURATION_STEREO) .setApp(new NvApp("Steam", "app-uuid", 123, true)) .setRemoteConfiguration(StreamConfiguration.STREAM_CFG_AUTO) .build(); // Create connection instance NvConnection connection = new NvConnection( context, hostAddress, httpsPort, uniqueId, config, cryptoProvider, serverCert ); // Start streaming with renderers connection.start(audioRenderer, videoDecoderRenderer, new NvConnectionListener() { @Override public void stageStarting(String stage) { Log.d("Stream", "Starting: " + stage); } @Override public void connectionStarted() { Log.d("Stream", "Stream connected successfully"); } @Override public void connectionTerminated(int errorCode) { Log.d("Stream", "Connection ended: " + errorCode); } }); // Stop the connection when done // connection.stop(); // Uncomment to stop the connection ``` -------------------------------- ### Implement NvConnectionListener for Stream Events (Java) Source: https://context7.com/classicoldsong/moonlight-android/llms.txt This Java code snippet demonstrates how to implement the NvConnectionListener interface to handle various streaming events. It includes callbacks for connection stages, success, termination, status updates, messages, rumble feedback, HDR mode, motion events, and controller LEDs. The listener is then used when starting a connection with NvConnection. ```java import android.content.Context; import android.os.Vibrator; import android.os.VibrationEffect; import android.util.Log; import android.widget.Toast; // Assuming MoonBridge and NvConnection are defined elsewhere // import com.example.moonlight.MoonBridge; // import com.example.moonlight.NvConnection; // Placeholder for context, assuming it's available in the scope Context context = null; // Replace with actual context // Placeholder for connection object // NvConnection connection = null; // Replace with actual connection object // Placeholder for renderers // Object audioRenderer = null; // Replace with actual audio renderer // Object videoRenderer = null; // Replace with actual video renderer // Implement connection listener for stream events NvConnectionListener listener = new NvConnectionListener() { @Override public void stageStarting(String stage) { // Called when a connection stage begins // Stages: "App Launch", "RTSP Handshake", "Control Stream", etc. Log.d("Stream", "Starting stage: " + stage); } @Override public void stageComplete(String stage) { Log.d("Stream", "Completed stage: " + stage); } @Override public boolean stageFailed(String stage, int portFlags, int errorCode) { Log.e("Stream", "Stage failed: " + stage + " error: " + errorCode); // Return true to retry, false to abort return errorCode == 0; // Retry on timeout (example logic) } @Override public void connectionStarted() { Log.d("Stream", "Streaming started successfully!"); } @Override public void connectionTerminated(int errorCode) { // Error codes: // ML_ERROR_GRACEFUL_TERMINATION (0) - Normal disconnect // ML_ERROR_NO_VIDEO_TRAFFIC (-100) - No video received // ML_ERROR_NO_VIDEO_FRAME (-101) - No frames decoded Log.d("Stream", "Connection ended: " + errorCode); } @Override public void connectionStatusUpdate(int connectionStatus) { // CONN_STATUS_OKAY (0) or CONN_STATUS_POOR (1) if (connectionStatus == MoonBridge.CONN_STATUS_POOR) { Log.w("Stream", "Poor connection quality detected"); } } @Override public void displayMessage(String message) { // Show error/info message to user if (context != null) { Toast.makeText(context, message, Toast.LENGTH_LONG).show(); } } @Override public void displayTransientMessage(String message) { // Show temporary notification if (context != null) { Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); } } @Override public void rumble(short controllerNumber, short lowFreqMotor, short highFreqMotor) { // Handle controller vibration (0-65535 intensity) if (context != null) { Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); if (vibrator != null) { int duration = 100; // ms int amplitude = Math.max(lowFreqMotor, highFreqMotor) / 256; if (vibrator.hasVibrator()) { vibrator.vibrate(VibrationEffect.createOneShot(duration, amplitude)); } } } } @Override public void rumbleTriggers(short controllerNumber, short leftTrigger, short rightTrigger) { // Handle adaptive trigger feedback (Xbox Series X, DualSense) // Implementation would go here } @Override public void setHdrMode(boolean enabled, byte[] hdrMetadata) { // Toggle HDR display mode Log.d("Stream", "HDR mode: " + enabled); // Implementation to control display HDR would go here } @Override public void setMotionEventState(short controllerNumber, byte eventType, short sampleRateHz) { // Enable/disable gyro/accelerometer reporting // Implementation would go here } @Override public void setControllerLED(short controllerNumber, byte r, byte g, byte b) { // Set controller LED color (DualSense, etc.) // Implementation would go here } }; // Use with NvConnection (assuming 'connection' is initialized) // if (connection != null && audioRenderer != null && videoRenderer != null) { // connection.start(audioRenderer, videoRenderer, listener); // } ``` -------------------------------- ### MoonBridge: Send Controller Battery/Motion and Get Stats (Java) Source: https://context7.com/classicoldsong/moonlight-android/llms.txt Shows how to report controller battery status and motion events (gyroscope) using MoonBridge, and how to retrieve stream statistics like Round-Trip Time (RTT) and pending video/audio frames. These functions are essential for monitoring stream health and providing accurate controller feedback. ```java // Controller battery and motion events MoonBridge.sendControllerBatteryEvent( (byte)0, // Controller number MoonBridge.LI_BATTERY_STATE_DISCHARGING, (byte)75 // 75% charge ); MoonBridge.sendControllerMotionEvent( (byte)0, // Controller number MoonBridge.LI_MOTION_TYPE_GYRO, 0.1f, -0.05f, 0.02f // X, Y, Z rotation rates ); // Get stream statistics long rttInfo = MoonBridge.getEstimatedRttInfo(); int rtt = (int)(rttInfo >> 32); // RTT in ms int rttVariance = (int)(rttInfo & 0xFFFFFFFF); int pendingFrames = MoonBridge.getPendingVideoFrames(); int pendingAudio = MoonBridge.getPendingAudioDuration(); // ms of buffered audio ``` -------------------------------- ### Accessing Computer Details in Java Source: https://context7.com/classicoldsong/moonlight-android/llms.txt This Java code demonstrates how to obtain and access properties of the ComputerDetails class, which typically comes from an NvHTTP object. It shows how to retrieve the host's name, UUID, MAC address, network addresses (local and remote), HTTPS port, connection state, pairing status, running application information, server capabilities like NVIDIA support and virtual display status, and available server commands. ```java NvHTTP http = new NvHTTP(address, httpsPort, uniqueId, serverCert, cryptoProvider); ComputerDetails computer = http.getComputerDetails(true); // Access computer properties String name = computer.name; // "GAMING-PC" String uuid = computer.uuid; // Unique server identifier String macAddress = computer.macAddress; // For Wake-on-LAN // Network addresses ComputerDetails.AddressTuple localAddr = computer.localAddress; // LAN address ComputerDetails.AddressTuple remoteAddr = computer.remoteAddress; // WAN address int httpsPort = computer.httpsPort; // Usually 47984 // Connection state ComputerDetails.State state = computer.state; // ONLINE, OFFLINE, UNKNOWN PairingManager.PairState pairState = computer.pairState; // PAIRED, NOT_PAIRED // Running application int runningGameId = computer.runningGameId; // 0 if no game running String runningGameUUID = computer.runningGameUUID; // Server capabilities boolean isNvidia = computer.nvidiaServer; // true for GeForce Experience boolean vDisplaySupport = computer.vDisplaySupported; // Apollo virtual display boolean vDisplayReady = computer.vDisplayDriverReady; // Server commands (Apollo-specific) List serverCommands = computer.serverCommands; // Create address tuple for connection ComputerDetails.AddressTuple address = new ComputerDetails.AddressTuple( "192.168.1.100", // IP address or hostname 47989 // HTTP port ); // Use address for NvHTTP NvHTTP newHttp = new NvHTTP(address, computer.httpsPort, uniqueId, serverCert, cryptoProvider); ``` -------------------------------- ### Mockito Mocking in Java Source: https://github.com/classicoldsong/moonlight-android/blob/moonlight-noir/android_test_setup.md This Java code snippet illustrates how to create a mock object using Mockito for a class like `NvConnection`. It shows how to define the behavior of mocked methods, such as returning a specific value when a method is called with certain arguments. ```java import org.mockito.Mockito; // ... inside a test method NvConnection conn = Mockito.mock(NvConnection.class); Mockito.when(conn.sendUtf8Text(Mockito.anyString())).thenReturn(0); ``` -------------------------------- ### NvApp: Create and Manage Application Representation (Java) Source: https://context7.com/classicoldsong/moonlight-android/llms.txt Demonstrates the creation and manipulation of `NvApp` objects, which represent streamable applications. This includes initializing `NvApp` instances with various parameters (name, UUID, ID, HDR support), using setters and getters to modify/access properties, and understanding the special `REMOTE_INPUT_UUID` for input-only scenarios. It also shows integration with `StreamConfiguration`. ```java // Create app reference by name (deprecated, use ID instead) NvApp steamByName = new NvApp("Steam"); // Create fully initialized app reference NvApp app = new NvApp( "Cyberpunk 2077", // Display name "550e8400-e29b-41d4-a716", // App UUID 12345, // App ID true // HDR supported ); // App setters (usually populated from server response) NvApp parsedApp = new NvApp(); parsedApp.setAppName("Desktop"); parsedApp.setAppUUID("8CB5C136-DA67-4F99-B4A1-F9CD35005CF4"); parsedApp.setAppId(1); parsedApp.setHdrSupported(false); parsedApp.setAppIndex(0); // App getters String name = app.getAppName(); // "Cyberpunk 2077" String uuid = app.getAppUUID(); // UUID string int id = app.getAppId(); // 12345 boolean hdr = app.isHdrSupported(); // true boolean ready = app.isInitialized(); // true if ID is set // Special Remote Input UUID for input-only mode String remoteInputUUID = NvApp.REMOTE_INPUT_UUID; // For Apollo server // Use with StreamConfiguration StreamConfiguration config = new StreamConfiguration.Builder() .setApp(app) .setResolution(1920, 1080) .build(); ``` -------------------------------- ### Mocking NvConnection with Mockito Source: https://github.com/classicoldsong/moonlight-android/blob/moonlight-noir/android_test_setup.md Demonstrates how to create a mock object for `NvConnection` using Mockito. It specifies the return value for the `sendUtf8Text` method when any string argument is provided, allowing for controlled interaction with this dependency during tests. ```java NvConnection conn = Mockito.mock(NvConnection.class); Mockito.when(conn.sendUtf8Text(Mockito.anyString())).thenReturn(0); ``` -------------------------------- ### Configure Streaming Settings with StreamConfiguration Builder Source: https://context7.com/classicoldsong/moonlight-android/llms.txt Utilizes a builder pattern to configure all streaming parameters, including resolution, bitrate, audio settings, and video codec preferences. Allows setting various video, color, audio, network, application, virtual display, and gamepad configurations. Returns a StreamConfiguration object. ```java StreamConfiguration config = new StreamConfiguration.Builder() .setResolution(2560, 1440) .setRefreshRate(120) .setBitrate(50000) .setLaunchRefreshRate(60) .setSupportedVideoFormats( MoonBridge.VIDEO_FORMAT_H265 | MoonBridge.VIDEO_FORMAT_H265_MAIN10 | MoonBridge.VIDEO_FORMAT_AV1_MAIN8 ) .setColorSpace(MoonBridge.COLORSPACE_REC_709) .setColorRange(MoonBridge.COLOR_RANGE_FULL) .setAudioConfiguration(MoonBridge.AUDIO_CONFIGURATION_51_SURROUND) .setRemoteConfiguration(StreamConfiguration.STREAM_CFG_AUTO) .setMaxPacketSize(1392) .setApp(new NvApp("Desktop", "desktop-uuid", 1, false)) .setVirtualDisplay(true) .setResolutionScaleFactor(100) .setAttachedGamepadMaskByCount(2) .setPersistGamepadsAfterDisconnect(true) .setEnableSops(true) .enableLocalAudioPlayback(false) .enableAdaptiveResolution(false) .setEnableUltraLowLatency(true) .build(); int width = config.getWidth(); int height = config.getHeight(); int bitrate = config.getBitrate(); int refreshRate = config.getRefreshRate(); ``` -------------------------------- ### Resetting Singleton Instance using Reflection Source: https://github.com/classicoldsong/moonlight-android/blob/moonlight-noir/android_test_setup.md Demonstrates how to reset a singleton instance (e.g., `ProfilesManager.instance`) to null before each test using Java reflection. This ensures test isolation by providing a clean state for tests that rely on the singleton. ```java Field f = ProfilesManager.class.getDeclaredField("instance"); f.setAccessible(true); f.set(null, null); // clear before each test ``` -------------------------------- ### Creating a Custom Shadow Class Source: https://github.com/classicoldsong/moonlight-android/blob/moonlight-noir/android_test_setup.md This Java code snippet shows how to create a custom shadow class for a problematic Android class. By using the `@Implements` annotation and providing stub implementations for methods, you can prevent `UnsatisfiedLinkError` or other runtime exceptions during unit testing. ```java @Implements(SomeProblematicClass.class) public class ShadowFoo { @Implementation protected static void __staticInitializer__() {} } ``` -------------------------------- ### Robolectric Test Class Boilerplate Source: https://github.com/classicoldsong/moonlight-android/blob/moonlight-noir/android_test_setup.md This Java code demonstrates the basic structure for a Robolectric test class. It includes necessary annotations for configuring the Android environment, specifying SDK version, and applying shadows for native or problematic classes. It also sets up a test context and a method to silence noisy logs before tests run. ```java import android.content.Context; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; import androidx.test.core.app.ApplicationProvider; @Config(sdk = {33}, shadows = { com.limelight.shadows.ShadowMoonBridge.class, com.limelight.shadows.ShadowGameManager.class}) @RunWith(RobolectricTestRunner.class) public class MyFeatureTest { private Context ctx; @BeforeClass public static void silenceLogs() { TestLogSuppressor.install(); // hides noisy “Invalid ID 0x00000000” spam } @Before public void setUp() { ctx = ApplicationProvider.getApplicationContext(); // extra prep (clear prefs, reset singletons, etc.) } @Test public void something_should_work() { /* your assertions */ } } ``` -------------------------------- ### Communicate with Streaming Server using NvHTTP API (Java) Source: https://context7.com/classicoldsong/moonlight-android/llms.txt The NvHTTP class facilitates HTTP-based communication with the streaming server for various management tasks, including discovery, pairing, and app listing. It supports secure HTTP/HTTPS connections with certificate pinning. This snippet shows how to initialize NvHTTP, retrieve server and app information, check capabilities, and manage applications and clipboard content. -------------------------------- ### Configure Special Keys JSON Format Source: https://github.com/classicoldsong/moonlight-android/wiki/Custom-Special-Keys This JSON structure defines special keys with their IDs, display names, and associated key combinations. The 'keys' array uses Windows Virtual-Key Codes, which can be in HEX or 'VK_*' string format. Indentation must use tabs. ```json { "data": [ { "id": "copy", "name": "COPY", "keys": [ "VK_LCONTROL", "VK_C" ] }, { "id": "paste", "name": "PASTE", "keys": [ "VK_LCONTROL", "VK_V" ] } ] } ``` -------------------------------- ### Resetting Singleton Instance in Java Source: https://github.com/classicoldsong/moonlight-android/blob/moonlight-noir/android_test_setup.md This Java code demonstrates how to reset a singleton instance, often used for managing application state in tests. It uses reflection to access and nullify a private static `instance` field, ensuring a clean state before each test. ```java import java.lang.reflect.Field; // ... inside a test method or setup method Field f = ProfilesManager.class.getDeclaredField("instance"); f.setAccessible(true); f.set(null, null); // clear before each test ``` -------------------------------- ### MoonBridge: Send Mouse, Keyboard, and Text Input (Java) Source: https://context7.com/classicoldsong/moonlight-android/llms.txt Demonstrates how to send various input events using the MoonBridge JNI bindings. This includes relative and absolute mouse movements, button clicks, high-resolution scrolling, keyboard key presses and releases, and direct UTF-8 text input. Ensure the moonlight-core native library is correctly linked. ```java // Mouse input methods MoonBridge.sendMouseMove((short)10, (short)-5); // Relative mouse movement (dx, dy) MoonBridge.sendMousePosition((short)500, (short)300, // Absolute mouse position (short)1920, (short)1080); // Reference dimensions MoonBridge.sendMouseButton(MouseButtonPacket.PRESS_EVENT, MouseButtonPacket.BUTTON_LEFT); // Left click down MoonBridge.sendMouseButton(MouseButtonPacket.RELEASE_EVENT, MouseButtonPacket.BUTTON_LEFT); // Left click up MoonBridge.sendMouseHighResScroll((short)120); // Scroll up (120 = 1 notch) MoonBridge.sendMouseHighResHScroll((short)-120); // Horizontal scroll left // Keyboard input short keyCode = 0x41; // 'A' key MoonBridge.sendKeyboardInput(keyCode, (byte)0x03, // KEY_DOWN (byte)0x00, // No modifiers (byte)0x00); // Flags MoonBridge.sendKeyboardInput(keyCode, (byte)0x04, // KEY_UP (byte)0x00, (byte)0x00); // Send text directly (UTF-8) MoonBridge.sendUtf8Text("Hello World!"); ``` -------------------------------- ### NvConnectionListener Interface Callbacks Source: https://context7.com/classicoldsong/moonlight-android/llms.txt This section details the various callback methods within the NvConnectionListener interface, used to manage streaming connections and receive controller events. ```APIDOC ## NvConnectionListener Interface ### Description The `NvConnectionListener` interface provides callbacks for monitoring connection state changes, handling errors, and receiving controller feedback events. ### Methods #### `stageStarting(String stage)` - **Description**: Called when a connection stage begins. - **Parameters**: - `stage` (String) - The name of the current connection stage (e.g., "App Launch", "RTSP Handshake"). #### `stageComplete(String stage)` - **Description**: Called when a connection stage is successfully completed. - **Parameters**: - `stage` (String) - The name of the completed connection stage. #### `stageFailed(String stage, int portFlags, int errorCode)` - **Description**: Called when a connection stage fails. - **Parameters**: - `stage` (String) - The name of the failed connection stage. - `portFlags` (int) - Flags indicating which ports were affected. - `errorCode` (int) - The error code associated with the failure. - **Returns**: `boolean` - `true` to retry the stage, `false` to abort. #### `connectionStarted()` - **Description**: Called when the streaming connection has successfully started. #### `connectionTerminated(int errorCode)` - **Description**: Called when the streaming connection is terminated. - **Parameters**: - `errorCode` (int) - The error code indicating the reason for termination. Common codes include `ML_ERROR_GRACEFUL_TERMINATION` (0), `ML_ERROR_NO_VIDEO_TRAFFIC` (-100), `ML_ERROR_NO_VIDEO_FRAME` (-101). #### `connectionStatusUpdate(int connectionStatus)` - **Description**: Called to provide updates on the connection quality. - **Parameters**: - `connectionStatus` (int) - The current connection status. `CONN_STATUS_OKAY` (0) for good quality, `CONN_STATUS_POOR` (1) for poor quality. #### `displayMessage(String message)` - **Description**: Called to display an informational or error message to the user. - **Parameters**: - `message` (String) - The message to display. #### `displayTransientMessage(String message)` - **Description**: Called to display a temporary notification message to the user. - **Parameters**: - `message` (String) - The message to display. #### `rumble(short controllerNumber, short lowFreqMotor, short highFreqMotor)` - **Description**: Called to activate controller vibration. - **Parameters**: - `controllerNumber` (short) - The identifier of the controller. - `lowFreqMotor` (short) - Intensity of the low-frequency motor (0-65535). - `highFreqMotor` (short) - Intensity of the high-frequency motor (0-65535). #### `rumbleTriggers(short controllerNumber, short leftTrigger, short rightTrigger)` - **Description**: Called to provide adaptive trigger feedback for supported controllers. - **Parameters**: - `controllerNumber` (short) - The identifier of the controller. - `leftTrigger` (short) - Intensity for the left trigger. - `rightTrigger` (short) - Intensity for the right trigger. #### `setHdrMode(boolean enabled, byte[] hdrMetadata)` - **Description**: Called to toggle the HDR display mode. - **Parameters**: - `enabled` (boolean) - `true` to enable HDR, `false` to disable. - `hdrMetadata` (byte[]) - Optional metadata for HDR configuration. #### `setMotionEventState(short controllerNumber, byte eventType, short sampleRateHz)` - **Description**: Called to enable or disable motion event reporting (gyroscope/accelerometer). - **Parameters**: - `controllerNumber` (short) - The identifier of the controller. - `eventType` (byte) - The type of motion event. - `sampleRateHz` (short) - The desired sample rate in Hz. #### `setControllerLED(short controllerNumber, byte r, byte g, byte b)` - **Description**: Called to set the color of the controller's LED. - **Parameters**: - `controllerNumber` (short) - The identifier of the controller. - `r` (byte) - Red component of the RGB color. - `g` (byte) - Green component of the RGB color. - `b` (byte) - Blue component of the RGB color. ### Usage Example ```java NvConnectionListener listener = new NvConnectionListener() { @Override public void stageStarting(String stage) { Log.d("Stream", "Starting stage: " + stage); } @Override public void stageComplete(String stage) { Log.d("Stream", "Completed stage: " + stage); } @Override public boolean stageFailed(String stage, int portFlags, int errorCode) { Log.e("Stream", "Stage failed: " + stage + " error: " + errorCode); return errorCode == 0; // Retry on timeout } @Override public void connectionStarted() { Log.d("Stream", "Streaming started successfully!"); } @Override public void connectionTerminated(int errorCode) { Log.d("Stream", "Connection ended: " + errorCode); } @Override public void connectionStatusUpdate(int connectionStatus) { if (connectionStatus == MoonBridge.CONN_STATUS_POOR) { Log.w("Stream", "Poor connection quality detected"); } } @Override public void displayMessage(String message) { Toast.makeText(context, message, Toast.LENGTH_LONG).show(); } @Override public void displayTransientMessage(String message) { Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); } @Override public void rumble(short controllerNumber, short lowFreqMotor, short highFreqMotor) { Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); int duration = 100; // ms int amplitude = Math.max(lowFreqMotor, highFreqMotor) / 256; vibrator.vibrate(VibrationEffect.createOneShot(duration, amplitude)); } @Override public void rumbleTriggers(short controllerNumber, short leftTrigger, short rightTrigger) { // Handle adaptive trigger feedback } @Override public void setHdrMode(boolean enabled, byte[] hdrMetadata) { Log.d("Stream", "HDR mode: " + enabled); } @Override public void setMotionEventState(short controllerNumber, byte eventType, short sampleRateHz) { // Enable/disable gyro/accelerometer reporting } @Override public void setControllerLED(short controllerNumber, byte r, byte g, byte b) { // Set controller LED color } }; // Example usage with NvConnection: // connection.start(audioRenderer, videoRenderer, listener); ``` -------------------------------- ### Pair Android Device with Streaming Server Source: https://context7.com/classicoldsong/moonlight-android/llms.txt Handles the secure PIN-based pairing process between the Android client and the streaming server using AES encryption. It generates a PIN, performs the pairing, and handles different pairing states. Requires NvHTTP and PairingManager classes. ```java NvHTTP http = new NvHTTP(address, httpsPort, uniqueId, null, cryptoProvider); PairingManager pairingManager = http.getPairingManager(); String pin = PairingManager.generatePinString(); Log.d("Pairing", "Enter this PIN on your PC: " + pin); String serverInfo = http.getServerInfo(false); PairingManager.PairState result = pairingManager.pair(serverInfo, pin, null); switch (result) { case PAIRED: X509Certificate serverCert = pairingManager.getPairedCert(); Log.d("Pairing", "Successfully paired with server"); break; case PIN_WRONG: Log.e("Pairing", "Wrong PIN entered"); break; case ALREADY_IN_PROGRESS: Log.e("Pairing", "Another device is currently pairing"); break; case FAILED: Log.e("Pairing", "Pairing failed"); break; case NOT_PAIRED: Log.e("Pairing", "Device is not paired"); break; } http.unpair(); ``` -------------------------------- ### Configure Video Formats and Color Spaces with MoonBridge Source: https://context7.com/classicoldsong/moonlight-android/llms.txt Provides constants for supported video codecs (H.264, HEVC, AV1) and capabilities, which can be combined using bitwise OR operations. It includes masks for checking format support, color space constants (REC.709 for SDR, REC.2020 for HDR), and color range settings (limited or full). Decoder capabilities and usage in `StreamConfiguration` are also demonstrated. ```java import com.moonlight.MoonBridge; import com.moonlight.StreamConfiguration; // Video format constants int h264 = MoonBridge.VIDEO_FORMAT_H264; // 0x0001 - H.264/AVC int hevc = MoonBridge.VIDEO_FORMAT_H265; // 0x0100 - HEVC/H.265 Main int hevc10 = MoonBridge.VIDEO_FORMAT_H265_MAIN10; // 0x0200 - HEVC Main10 (HDR) int av1 = MoonBridge.VIDEO_FORMAT_AV1_MAIN8; // 0x1000 - AV1 Main 8-bit int av1_10 = MoonBridge.VIDEO_FORMAT_AV1_MAIN10; // 0x2000 - AV1 Main 10-bit (HDR) // Format masks for checking support int h264Mask = MoonBridge.VIDEO_FORMAT_MASK_H264; // 0x000F int hevcMask = MoonBridge.VIDEO_FORMAT_MASK_H265; // 0x0F00 int av1Mask = MoonBridge.VIDEO_FORMAT_MASK_AV1; // 0xF000 int hdrMask = MoonBridge.VIDEO_FORMAT_MASK_10BIT; // 0x2200 - All 10-bit formats // Combine formats for device capabilities int supportedFormats = MoonBridge.VIDEO_FORMAT_H264 | MoonBridge.VIDEO_FORMAT_H265 | MoonBridge.VIDEO_FORMAT_H265_MAIN10; // Check if HDR is supported boolean supportsHdr = (supportedFormats & MoonBridge.VIDEO_FORMAT_MASK_10BIT) != 0; // Color space and range constants int colorSpace = MoonBridge.COLORSPACE_REC_709; // SDR content int hdrColorSpace = MoonBridge.COLORSPACE_REC_2020; // HDR content int limitedRange = MoonBridge.COLOR_RANGE_LIMITED; // 16-235 int fullRange = MoonBridge.COLOR_RANGE_FULL; // 0-255 // Decoder capabilities int capabilities = MoonBridge.CAPABILITY_DIRECT_SUBMIT | MoonBridge.CAPABILITY_REFERENCE_FRAME_INVALIDATION_HEVC; // Use in configuration StreamConfiguration config = new StreamConfiguration.Builder() .setSupportedVideoFormats(supportedFormats) .setColorSpace(MoonBridge.COLORSPACE_REC_709) .setColorRange(MoonBridge.COLOR_RANGE_FULL) .build(); ``` -------------------------------- ### Configure Audio Channels with MoonBridge.AudioConfiguration Source: https://context7.com/classicoldsong/moonlight-android/llms.txt Defines constants for audio channel configurations such as stereo, 5.1, and 7.1 surround sound. It allows creating custom configurations, retrieving channel counts and masks, converting to integer formats for native code, and obtaining surround audio information for server requests. These configurations are used within `StreamConfiguration`. ```java import com.moonlight.MoonBridge; import com.moonlight.StreamConfiguration; // Available audio configurations MoonBridge.AudioConfiguration stereo = MoonBridge.AUDIO_CONFIGURATION_STEREO; // 2 channels MoonBridge.AudioConfiguration surround51 = MoonBridge.AUDIO_CONFIGURATION_51_SURROUND; // 6 channels MoonBridge.AudioConfiguration surround71 = MoonBridge.AUDIO_CONFIGURATION_71_SURROUND; // 8 channels // Custom audio configuration MoonBridge.AudioConfiguration custom = new MoonBridge.AudioConfiguration( 6, // Channel count 0x3F // Channel mask (FL, FR, FC, LFE, BL, BR) ); // Get configuration properties int channels = stereo.channelCount; // 2 int mask = stereo.channelMask; // 0x3 // Convert to integer for native code int configInt = surround51.toInt(); // Get surround audio info for server launch request int surroundInfo = surround71.getSurroundAudioInfo(); // Use in stream configuration StreamConfiguration config = new StreamConfiguration.Builder() .setAudioConfiguration(MoonBridge.AUDIO_CONFIGURATION_51_SURROUND) .setResolution(1920, 1080) .setRefreshRate(60) .build(); ``` -------------------------------- ### MoonBridge: Send Gamepad, Touch, and Pen Input (Java) Source: https://context7.com/classicoldsong/moonlight-android/llms.txt Illustrates sending advanced input events like gamepad controls, touch screen interactions, and pen/stylus input via the MoonBridge API. This includes controller button and stick states, touch coordinates and pressure, and pen tool information. These methods are crucial for interacting with games and applications on a remote host. ```java // Gamepad input short controllerNumber = 0; short activeGamepadMask = 0x0001; // Controller 0 active int buttonFlags = ControllerPacket.A_FLAG | ControllerPacket.START_FLAG; byte leftTrigger = (byte)128; // Half pressed (0-255) byte rightTrigger = (byte)255; // Fully pressed short leftStickX = 16384; // Right (range: -32768 to 32767) short leftStickY = 0; // Center short rightStickX = 0; short rightStickY = -16384; // Up MoonBridge.sendMultiControllerInput( controllerNumber, activeGamepadMask, buttonFlags, leftTrigger, rightTrigger, leftStickX, leftStickY, rightStickX, rightStickY ); // Touch input (for touchscreen games) int result = MoonBridge.sendTouchEvent( MoonBridge.LI_TOUCH_EVENT_DOWN, // Event type 0, // Pointer ID 0.5f, 0.5f, // Normalized position (0-1) 1.0f, // Pressure 0.05f, 0.05f, // Contact area (short)0 // Rotation ); // Pen/stylus input MoonBridge.sendPenEvent( MoonBridge.LI_TOUCH_EVENT_DOWN, MoonBridge.LI_TOOL_TYPE_PEN, MoonBridge.LI_PEN_BUTTON_PRIMARY, 0.3f, 0.7f, // Position 0.8f, // Pressure 0.01f, 0.01f, // Contact area (short)45, // Rotation in degrees (byte)30 // Tilt angle ); ``` -------------------------------- ### Clearing SharedPreferences Source: https://github.com/classicoldsong/moonlight-android/blob/moonlight-noir/android_test_setup.md Shows how to clear all data from default SharedPreferences for a given context. This is a common practice in unit tests to ensure that tests do not interfere with each other due to lingering preference data. ```java SharedPreferences p = PreferenceManager.getDefaultSharedPreferences(ctx); p.edit().clear().commit(); ``` -------------------------------- ### Clearing SharedPreferences in Java Source: https://github.com/classicoldsong/moonlight-android/blob/moonlight-noir/android_test_setup.md This Java code snippet shows how to clear all data from default SharedPreferences before a test runs. It retrieves the SharedPreferences instance using the application context and then uses an editor to clear all key-value pairs. ```java import android.content.Context; import android.content.SharedPreferences; import android.preference.PreferenceManager; // ... inside a test method or setup method Context ctx = ApplicationProvider.getApplicationContext(); // Assuming ctx is available SharedPreferences p = PreferenceManager.getDefaultSharedPreferences(ctx); p.edit().clear().commit(); ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.