Skip to content

Commit 4bf563b

Browse files
authored
Merge pull request #2246 from Mentra-Community/ya/replace-rtmp-with-srt
Ya/replace rtmp with srt
2 parents 7d4dd65 + b546692 commit 4bf563b

File tree

91 files changed

+4869
-2317
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

91 files changed

+4869
-2317
lines changed

asg_client/app/build.gradle

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@ dependencies {
310310
// StreamPackLite dependencies
311311
implementation project(':core')
312312
implementation project(':extension-rtmp')
313+
implementation project(':extension-srt')
313314

314315
// OkHttp for network requests
315316
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
@@ -323,6 +324,11 @@ dependencies {
323324
// Sentry SDK for error reporting
324325
implementation 'io.sentry:sentry-android:7.5.0'
325326

327+
// Google WebRTC for Android (WHIP streaming)
328+
// Community-maintained prebuilt of the official Google WebRTC codebase; uses org.webrtc package.
329+
// Pinned to M114 (2023) — compiled with Java 11, compatible with this project's Java 17 toolchain.
330+
implementation 'io.github.webrtc-sdk:android:114.5735.08.1'
331+
326332
// AndroidX Test dependencies
327333
androidTestImplementation 'androidx.test:core:1.5.0'
328334
androidTestImplementation 'androidx.test:runner:1.5.2'

asg_client/app/src/main/AndroidManifest.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,18 @@
171171
android:exported="true"
172172
android:foregroundServiceType="camera|microphone" />
173173

174+
<service
175+
android:name="com.mentra.asg_client.io.streaming.services.SrtStreamingService"
176+
android:enabled="true"
177+
android:exported="true"
178+
android:foregroundServiceType="camera|microphone" />
179+
180+
<service
181+
android:name="com.mentra.asg_client.io.streaming.services.WhipStreamingService"
182+
android:enabled="true"
183+
android:exported="true"
184+
android:foregroundServiceType="camera|microphone" />
185+
174186
<service
175187
android:name="com.mentra.asg_client.io.ota.services.OtaService"
176188
android:enabled="true"

asg_client/app/src/main/java/com/mentra/asg_client/SysControl.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -452,13 +452,20 @@ public static void flashRecordingLed(Context context, long durationMs) {
452452
* @param enable true to enable EIS, false to disable
453453
*/
454454
public static void setEisEnable(Context context, boolean enable) {
455-
Log.d(TAG, "🎥 Setting EIS (vendor.debug.pixsmart.vs) to: " + (enable ? "1" : "0"));
455+
Log.d(TAG, "🎥 Setting EIS to: " + (enable ? "ENABLED" : "DISABLED"));
456+
// Pixsmart EIS
456457
Intent nn = new Intent();
457458
nn.putExtra("cmd", "setProperty");
458459
nn.putExtra("name", "vendor.debug.pixsmart.vs");
459460
nn.putExtra("value", enable ? "1": "0");
460461
sendBroadcast(context, nn);
461-
Log.d(TAG, "✅ EIS property broadcast sent");
462+
// Morpho video EIS
463+
Intent nn2 = new Intent();
464+
nn2.putExtra("cmd", "setProperty");
465+
nn2.putExtra("name", "vendor.debug.morpho.videoeis.mode");
466+
nn2.putExtra("value", enable ? "1": "0");
467+
sendBroadcast(context, nn2);
468+
Log.d(TAG, "✅ EIS properties set (pixsmart + morpho)");
462469
}
463470

464471
/**

asg_client/app/src/main/java/com/mentra/asg_client/camera/CameraNeo.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.mentra.asg_client.io.hardware.interfaces.IHardwareManager;
55
import com.mentra.asg_client.service.utils.ServiceUtils;
66
import com.mentra.asg_client.io.hardware.core.HardwareManagerFactory;
7+
import com.mentra.asg_client.SysControl;
78

89
import android.annotation.SuppressLint;
910
import android.app.NotificationChannel;
@@ -659,11 +660,13 @@ public int onStartCommand(Intent intent, int flags, int startId) {
659660
} else {
660661
pendingVideoSettings = null; // Will use defaults
661662
}
663+
SysControl.setEisEnable(this, true);
662664
setupCameraAndStartRecording(currentVideoId, currentVideoPath);
663665
break;
664666
case ACTION_STOP_VIDEO_RECORDING:
665667
String videoIdToStop = intent.getStringExtra(EXTRA_VIDEO_ID);
666668
stopCurrentVideoRecording(videoIdToStop);
669+
SysControl.setEisEnable(this, false);
667670
break;
668671

669672
case ACTION_START_BUFFER:

asg_client/app/src/main/java/com/mentra/asg_client/io/media/core/MediaCaptureService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,7 @@ public void playBatteryLowSound() {
429429

430430
/**
431431
* Static helper for contexts without MediaCaptureService instance.
432-
* Used by RtmpCommandHandler and other handlers.
432+
* Used by StreamCommandHandler and other handlers.
433433
*/
434434
public static void playBatteryLowSound(Context context) {
435435
IHardwareManager hwManager = HardwareManagerFactory.getInstance(context);

asg_client/app/src/main/java/com/mentra/asg_client/io/streaming/config/RtmpStreamConfig.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99
public class RtmpStreamConfig {
1010

1111
// Default values (matching current hardcoded values)
12-
public static final int DEFAULT_VIDEO_WIDTH = 1280;
13-
public static final int DEFAULT_VIDEO_HEIGHT = 720;
14-
public static final int DEFAULT_VIDEO_BITRATE = 2000000; // 2 Mbps
15-
public static final int DEFAULT_VIDEO_FPS = 30;
12+
public static final int DEFAULT_VIDEO_WIDTH = 960;
13+
public static final int DEFAULT_VIDEO_HEIGHT = 540;
14+
public static final int DEFAULT_VIDEO_BITRATE = 1000000; // 1 Mbps
15+
public static final int DEFAULT_VIDEO_FPS = 15;
1616

1717
public static final int DEFAULT_AUDIO_BITRATE = 64000; // 64 kbps
1818
public static final int DEFAULT_AUDIO_SAMPLE_RATE = 44100;
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package com.mentra.asg_client.io.streaming.config;
2+
3+
import org.json.JSONObject;
4+
5+
/**
6+
* Configuration class for WebRTC / WHIP streaming parameters.
7+
*/
8+
public class WhipStreamConfig {
9+
10+
public static final int DEFAULT_VIDEO_WIDTH = 960;
11+
public static final int DEFAULT_VIDEO_HEIGHT = 540;
12+
public static final int DEFAULT_VIDEO_FPS = 15;
13+
public static final int DEFAULT_VIDEO_BITRATE = 1000000; // 1 Mbps
14+
15+
public static final boolean DEFAULT_ECHO_CANCELLATION = false;
16+
public static final boolean DEFAULT_NOISE_SUPPRESSION = false;
17+
18+
public static final String DEFAULT_STUN_SERVER = "stun:stun.cloudflare.com:3478";
19+
20+
private int videoWidth = DEFAULT_VIDEO_WIDTH;
21+
private int videoHeight = DEFAULT_VIDEO_HEIGHT;
22+
private int videoFps = DEFAULT_VIDEO_FPS;
23+
private int videoBitrate = DEFAULT_VIDEO_BITRATE;
24+
25+
private boolean echoCancellation = DEFAULT_ECHO_CANCELLATION;
26+
private boolean noiseSuppression = DEFAULT_NOISE_SUPPRESSION;
27+
28+
private String stunServer = DEFAULT_STUN_SERVER;
29+
30+
public WhipStreamConfig() {
31+
}
32+
33+
/**
34+
* Parse video and audio config from JSON objects sent by the SDK.
35+
* Supports both full key names and compact keys for MTU-constrained messages:
36+
* Full: { width, height, bitrate, frameRate } / { echoCancellation, noiseSuppression }
37+
* Compact: { w, h, br, fr } / { ec, ns }
38+
*/
39+
public static WhipStreamConfig fromJson(JSONObject videoJson, JSONObject audioJson) {
40+
WhipStreamConfig config = new WhipStreamConfig();
41+
42+
if (videoJson != null) {
43+
config.videoWidth = clamp(optIntWithFallback(videoJson, "width", "w", DEFAULT_VIDEO_WIDTH), 320, 1920);
44+
config.videoHeight = clamp(optIntWithFallback(videoJson, "height", "h", DEFAULT_VIDEO_HEIGHT), 240, 1080);
45+
config.videoBitrate = clamp(optIntWithFallback(videoJson, "bitrate", "br", DEFAULT_VIDEO_BITRATE), 100000, 10000000);
46+
config.videoFps = clamp(optIntWithFallback(videoJson, "frameRate", "fr", DEFAULT_VIDEO_FPS), 10, 60);
47+
}
48+
49+
if (audioJson != null) {
50+
config.echoCancellation = optBoolWithFallback(audioJson, "echoCancellation", "ec", DEFAULT_ECHO_CANCELLATION);
51+
config.noiseSuppression = optBoolWithFallback(audioJson, "noiseSuppression", "ns", DEFAULT_NOISE_SUPPRESSION);
52+
}
53+
54+
return config;
55+
}
56+
57+
private static int optIntWithFallback(JSONObject json, String fullKey, String compactKey, int defaultValue) {
58+
if (json.has(fullKey)) return json.optInt(fullKey, defaultValue);
59+
return json.optInt(compactKey, defaultValue);
60+
}
61+
62+
private static boolean optBoolWithFallback(JSONObject json, String fullKey, String compactKey, boolean defaultValue) {
63+
if (json.has(fullKey)) return json.optBoolean(fullKey, defaultValue);
64+
return json.optBoolean(compactKey, defaultValue);
65+
}
66+
67+
private static int clamp(int value, int min, int max) {
68+
return Math.max(min, Math.min(max, value));
69+
}
70+
71+
// Getters
72+
public int getVideoWidth() { return videoWidth; }
73+
public int getVideoHeight() { return videoHeight; }
74+
public int getVideoFps() { return videoFps; }
75+
public int getVideoBitrate() { return videoBitrate; }
76+
public boolean isEchoCancellation() { return echoCancellation; }
77+
public boolean isNoiseSuppression() { return noiseSuppression; }
78+
public String getStunServer() { return stunServer; }
79+
80+
// Setters with validation (fluent API)
81+
public WhipStreamConfig setVideoWidth(int width) {
82+
this.videoWidth = clamp(width, 320, 1920);
83+
return this;
84+
}
85+
86+
public WhipStreamConfig setVideoHeight(int height) {
87+
this.videoHeight = clamp(height, 240, 1080);
88+
return this;
89+
}
90+
91+
public WhipStreamConfig setVideoFps(int fps) {
92+
this.videoFps = clamp(fps, 10, 60);
93+
return this;
94+
}
95+
96+
public WhipStreamConfig setVideoBitrate(int bitrate) {
97+
this.videoBitrate = clamp(bitrate, 100000, 10000000);
98+
return this;
99+
}
100+
101+
public WhipStreamConfig setEchoCancellation(boolean enabled) {
102+
this.echoCancellation = enabled;
103+
return this;
104+
}
105+
106+
public WhipStreamConfig setNoiseSuppression(boolean enabled) {
107+
this.noiseSuppression = enabled;
108+
return this;
109+
}
110+
111+
public WhipStreamConfig setStunServer(String stunServer) {
112+
this.stunServer = stunServer;
113+
return this;
114+
}
115+
116+
@Override
117+
public String toString() {
118+
return "WhipStreamConfig{"
119+
+ "video=" + videoWidth + "x" + videoHeight + "@" + videoFps + "fps, "
120+
+ (videoBitrate / 1000) + "kbps"
121+
+ ", echo=" + echoCancellation
122+
+ ", noise=" + noiseSuppression
123+
+ ", stun=" + stunServer
124+
+ '}';
125+
}
126+
}

asg_client/app/src/main/java/com/mentra/asg_client/io/streaming/interfaces/StreamingStatusCallback.java

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,57 +2,66 @@
22

33
/**
44
* Callback interface for receiving streaming status updates.
5-
* Extracted from RtmpStreamingService for better separation of concerns.
5+
* Each method receives the streamId from the service that fired the event,
6+
* so the caller doesn't need to look up the active stream globally.
67
*/
78
public interface StreamingStatusCallback {
8-
9+
910
/**
1011
* Called when streaming is starting (connecting)
1112
*
1213
* @param streamingUrl The URL being connected to
14+
* @param streamId The stream ID assigned by the cloud, or null if not yet assigned
1315
*/
14-
void onStreamStarting(String streamingUrl);
16+
void onStreamStarting(String streamingUrl, String streamId);
1517

1618
/**
1719
* Called when streaming has started successfully
1820
*
1921
* @param streamingUrl The URL connected to
22+
* @param streamId The stream ID assigned by the cloud, or null if not yet assigned
2023
*/
21-
void onStreamStarted(String streamingUrl);
24+
void onStreamStarted(String streamingUrl, String streamId);
2225

2326
/**
2427
* Called when streaming has stopped
28+
*
29+
* @param streamId The stream ID of the stopped stream, or null
2530
*/
26-
void onStreamStopped();
31+
void onStreamStopped(String streamId);
2732

2833
/**
2934
* Called when a connection is lost and reconnection is being attempted
3035
*
3136
* @param attempt Current reconnection attempt number
3237
* @param maxAttempts Maximum number of attempts that will be made
3338
* @param reason Reason for reconnection
39+
* @param streamId The stream ID, or null
3440
*/
35-
void onReconnecting(int attempt, int maxAttempts, String reason);
41+
void onReconnecting(int attempt, int maxAttempts, String reason, String streamId);
3642

3743
/**
3844
* Called when reconnection was successful
3945
*
4046
* @param streamingUrl The URL reconnected to
4147
* @param attempt The attempt number that succeeded
48+
* @param streamId The stream ID, or null
4249
*/
43-
void onReconnected(String streamingUrl, int attempt);
50+
void onReconnected(String streamingUrl, int attempt, String streamId);
4451

4552
/**
4653
* Called when all reconnection attempts have failed
4754
*
4855
* @param maxAttempts The maximum number of attempts that were made
56+
* @param streamId The stream ID, or null
4957
*/
50-
void onReconnectFailed(int maxAttempts);
58+
void onReconnectFailed(int maxAttempts, String streamId);
5159

5260
/**
5361
* Called when a streaming error occurs
5462
*
55-
* @param error Error message
63+
* @param error Error message
64+
* @param streamId The stream ID, or null
5665
*/
57-
void onStreamError(String error);
58-
}
66+
void onStreamError(String error, String streamId);
67+
}

0 commit comments

Comments
 (0)