优化xor加解密逻辑适应tx云

This commit is contained in:
2026-02-27 14:19:52 +08:00
parent 6a3421fa4d
commit ae4a045451
6 changed files with 169 additions and 31 deletions

Binary file not shown.

View File

@@ -117,7 +117,14 @@ class FeatureHubActivity : AppCompatActivity() {
private fun setupActions() {
binding.btnHomeLivePush.setOnClickListener {
showPushSettingsDialog { showPushProtocolSheet() }
showPushSettingsDialog {
val settings = settingsStore.read()
if (settings.useUrlMode) {
startActivity(LivePushActivity.createIntent(this, SellyLiveMode.RTMP))
} else {
showPushProtocolSheet()
}
}
}
binding.btnHomeLivePull.setOnClickListener {
showPlayConfigDialog()
@@ -341,6 +348,7 @@ class FeatureHubActivity : AppCompatActivity() {
val current = settingsStore.read()
dialogBinding.etStreamId.setText(generateRandomStreamId())
dialogBinding.etPushUrl.setText(current.pushUrl)
dialogBinding.etFps.setText(current.fps.toString())
dialogBinding.etMaxBitrate.setText(current.maxBitrateKbps.toString())
dialogBinding.etMinBitrate.setText(current.minBitrateKbps.toString())
@@ -354,16 +362,39 @@ class FeatureHubActivity : AppCompatActivity() {
}
)
fun updateModeVisibility(urlMode: Boolean) {
dialogBinding.groupUrlMode.visibility = if (urlMode) View.VISIBLE else View.GONE
dialogBinding.groupStreamIdMode.visibility = if (urlMode) View.GONE else View.VISIBLE
}
dialogBinding.rgPushMode.check(
if (current.useUrlMode) R.id.rbModeUrl else R.id.rbModeStreamId
)
updateModeVisibility(current.useUrlMode)
dialogBinding.rgPushMode.setOnCheckedChangeListener { _, checkedId ->
updateModeVisibility(checkedId == R.id.rbModeUrl)
}
dialogBinding.btnClose.setOnClickListener { dialog.dismiss() }
dialogBinding.btnApply.setOnClickListener {
val useUrlMode = dialogBinding.rgPushMode.checkedRadioButtonId == R.id.rbModeUrl
val pushUrl = dialogBinding.etPushUrl.text?.toString()?.trim().orEmpty()
val streamId = dialogBinding.etStreamId.text?.toString()?.trim().orEmpty()
val fps = dialogBinding.etFps.text?.toString()?.trim()?.toIntOrNull()
val maxKbps = dialogBinding.etMaxBitrate.text?.toString()?.trim()?.toIntOrNull()
val minKbps = dialogBinding.etMinBitrate.text?.toString()?.trim()?.toIntOrNull()
if (streamId.isEmpty()) {
Toast.makeText(this, "请输入 Stream ID", Toast.LENGTH_SHORT).show()
return@setOnClickListener
if (useUrlMode) {
if (pushUrl.isEmpty()) {
Toast.makeText(this, "请输入推流地址", Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
} else {
if (streamId.isEmpty()) {
Toast.makeText(this, "请输入 Stream ID", Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
}
if (fps == null || fps <= 0) {
Toast.makeText(this, "请输入正确的 FPS", Toast.LENGTH_SHORT).show()
@@ -392,7 +423,9 @@ class FeatureHubActivity : AppCompatActivity() {
fps = fps,
maxBitrateKbps = maxKbps,
minBitrateKbps = minKbps,
xorKeyHex = xorKey
xorKeyHex = xorKey,
useUrlMode = useUrlMode,
pushUrl = pushUrl
)
settingsStore.write(updated)
dialog.dismiss()

View File

@@ -10,6 +10,8 @@ data class AvDemoSettings(
val maxBitrateKbps: Int,
val minBitrateKbps: Int,
val xorKeyHex: String = "",
val useUrlMode: Boolean = false,
val pushUrl: String = "",
) {
enum class Resolution { P360, P480, P540, P720 }
@@ -38,7 +40,9 @@ class AvDemoSettingsStore(context: Context) {
fps = prefs.getInt(KEY_FPS, DEFAULT_FPS),
maxBitrateKbps = prefs.getInt(KEY_MAX_KBPS, DEFAULT_MAX_KBPS),
minBitrateKbps = prefs.getInt(KEY_MIN_KBPS, DEFAULT_MIN_KBPS),
xorKeyHex = prefs.getString(KEY_XOR_KEY_HEX, "").orEmpty()
xorKeyHex = prefs.getString(KEY_XOR_KEY_HEX, "").orEmpty(),
useUrlMode = prefs.getBoolean(KEY_USE_URL_MODE, false),
pushUrl = prefs.getString(KEY_PUSH_URL, "").orEmpty()
)
}
@@ -50,6 +54,8 @@ class AvDemoSettingsStore(context: Context) {
putInt(KEY_MAX_KBPS, settings.maxBitrateKbps)
putInt(KEY_MIN_KBPS, settings.minBitrateKbps)
putString(KEY_XOR_KEY_HEX, settings.xorKeyHex)
putBoolean(KEY_USE_URL_MODE, settings.useUrlMode)
putString(KEY_PUSH_URL, settings.pushUrl)
}
}
@@ -66,5 +72,7 @@ class AvDemoSettingsStore(context: Context) {
private const val DEFAULT_MAX_KBPS = 2000
private const val DEFAULT_MIN_KBPS = 500
private const val KEY_XOR_KEY_HEX = "xor_key_hex"
private const val KEY_USE_URL_MODE = "use_url_mode"
private const val KEY_PUSH_URL = "push_url"
}
}

View File

@@ -130,22 +130,31 @@ class LivePushActivity : AppCompatActivity() {
pusher.stopLive()
} else {
val settings = settingsStore.read()
val env = envStore.read()
val streamId = settings.streamId
val authError = LiveAuthHelper.validateAuthConfig(env, streamId)
if (authError != null) {
Toast.makeText(this, authError, Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
val auth = LiveAuthHelper.buildAuthParams(
env = env,
channelId = streamId,
type = LiveTokenSigner.TokenType.PUSH
)
applyStreamConfig(settings)
pusher.token = auth?.tokenResult?.token
pusher.setXorKey(settings.xorKeyHex)
pusher.startLiveWithStreamId(streamId)
if (settings.useUrlMode) {
val pushUrl = settings.pushUrl
if (pushUrl.isEmpty()) {
Toast.makeText(this, "请先在设置中输入推流地址", Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
pusher.startLiveWithUrl(pushUrl)
} else {
val env = envStore.read()
val streamId = settings.streamId
val authError = LiveAuthHelper.validateAuthConfig(env, streamId)
if (authError != null) {
Toast.makeText(this, authError, Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
val auth = LiveAuthHelper.buildAuthParams(
env = env,
channelId = streamId,
type = LiveTokenSigner.TokenType.PUSH
)
pusher.token = auth?.tokenResult?.token
pusher.startLiveWithStreamId(streamId)
}
}
}

View File

@@ -40,28 +40,112 @@
app:tint="@color/brand_primary" />
</RelativeLayout>
<!-- Push Mode -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/push_settings_stream_id"
android:text="@string/push_settings_push_mode"
android:textColor="@color/av_text_primary"
android:textSize="14sp"
android:textStyle="bold" />
<EditText
android:id="@+id/etStreamId"
<RadioGroup
android:id="@+id/rgPushMode"
android:layout_width="match_parent"
android:layout_height="@dimen/av_field_height"
android:layout_marginTop="8dp"
android:background="@drawable/bg_av_input_field"
android:importantForAutofill="no"
android:inputType="text"
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:textColor="@color/av_text_primary"
android:textColorHint="@color/av_text_hint"
android:textSize="14sp" />
android:background="@drawable/bg_av_segment_container"
android:orientation="horizontal">
<RadioButton
android:id="@+id/rbModeStreamId"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/selector_av_segment_left"
android:button="@null"
android:gravity="center"
android:text="@string/push_mode_stream_id"
android:textColor="@color/av_segment_text"
android:textSize="14sp" />
<RadioButton
android:id="@+id/rbModeUrl"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/selector_av_segment_right"
android:button="@null"
android:gravity="center"
android:text="@string/push_mode_url"
android:textColor="@color/av_segment_text"
android:textSize="14sp" />
</RadioGroup>
<!-- URL mode input -->
<LinearLayout
android:id="@+id/groupUrlMode"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/push_settings_push_url"
android:textColor="@color/av_text_primary"
android:textSize="14sp"
android:textStyle="bold" />
<EditText
android:id="@+id/etPushUrl"
android:layout_width="match_parent"
android:layout_height="@dimen/av_field_height"
android:layout_marginTop="8dp"
android:background="@drawable/bg_av_input_field"
android:hint="rtmp://host/app/stream"
android:importantForAutofill="no"
android:inputType="textUri"
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:textColor="@color/av_text_primary"
android:textColorHint="@color/av_text_hint"
android:textSize="14sp" />
</LinearLayout>
<!-- StreamID mode input -->
<LinearLayout
android:id="@+id/groupStreamIdMode"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/push_settings_stream_id"
android:textColor="@color/av_text_primary"
android:textSize="14sp"
android:textStyle="bold" />
<EditText
android:id="@+id/etStreamId"
android:layout_width="match_parent"
android:layout_height="@dimen/av_field_height"
android:layout_marginTop="8dp"
android:background="@drawable/bg_av_input_field"
android:importantForAutofill="no"
android:inputType="text"
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:textColor="@color/av_text_primary"
android:textColorHint="@color/av_text_hint"
android:textSize="14sp" />
</LinearLayout>
<TextView
android:layout_width="wrap_content"

View File

@@ -76,6 +76,10 @@
<string name="push_settings_apply">应用</string>
<string name="push_settings_stream_id">Stream ID</string>
<string name="push_settings_close">关闭设置</string>
<string name="push_settings_push_mode">推流模式</string>
<string name="push_mode_stream_id">StreamID</string>
<string name="push_mode_url">URL</string>
<string name="push_settings_push_url">推流地址</string>
<string name="play_config_title">播放配置</string>
<string name="play_config_protocol_label">播放协议</string>