Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
c94a989
[Fix] Compose picture-in-picture. NMS-26673
Sep 18, 2025
dfa8a41
Update screen share feature
Nov 13, 2025
d8cfdc3
[Android]Update .h file.
Nov 13, 2025
e854cd2
Update screen share feature for SwiftUI
Nov 13, 2025
c76d269
Update screen share feature for OC
Nov 14, 2025
edc94b9
Merge branch 'dev/4.6.1' of https://github.com/AgoraIO/API-Examples i…
Nov 14, 2025
3d7a5a7
[FEAT] mac transcoding video
Nov 14, 2025
bd7be45
[FEAT] remove old file
Nov 14, 2025
d0e6fb6
Update script for Swift proj
Nov 17, 2025
798c7b3
Merge branch 'dev/4.6.1' of https://github.com/AgoraIO/API-Examples i…
Nov 17, 2025
5971230
Update script
Nov 17, 2025
56ee4c9
Update script
Nov 17, 2025
88bf58e
Update script
Nov 17, 2025
d8a69d2
Bugfix
Nov 17, 2025
d894b6b
Modify script
Nov 17, 2025
642cff3
update android rtc_sdk_version to 4.6.2.
Nov 24, 2025
56ae8fa
NMS-28354 LiveStreaming: update default video scenario to APPLICATION…
Nov 24, 2025
6246911
fixs compose ScreenSharing
Nov 25, 2025
5db1d1e
update .h file
Nov 27, 2025
a7cf06b
update agora-beauty resources
Nov 27, 2025
bdb154a
Fix PIP issues
Dec 5, 2025
3310861
Update live stream video scenario to "live show"
Nov 24, 2025
81fc96c
Update PIP
Nov 17, 2025
a7ca505
[FEAT] MacOS sdk frameRate param type adapt
Dec 11, 2025
a055f30
feat:CSD-71936
Dec 11, 2025
a5fe702
fixs NMS-28712
Dec 15, 2025
e1f1d43
[FIX] windows rtmp text
Dec 16, 2025
3c0076b
update .h file
Dec 26, 2025
3466979
[FIX] windows sdk file path
chenyuguo-agora Jan 15, 2026
601d827
Update version
Jan 15, 2026
b945f01
doc (android): update readme
Jan 16, 2026
c368b9d
[FEAT] 4.6.2 sdk
Jan 16, 2026
ce3f4e2
Merge branch 'dev/4.6.2' of github.com:AgoraIO/API-Examples into dev/…
Jan 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Android/APIExample-Audio/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ android.nonFinalResIds=false
# read enable simple filter section on README first before set this flag to TRUE
simpleFilter = false

rtc_sdk_version = 4.6.0
rtc_sdk_version = 4.6.2
6 changes: 5 additions & 1 deletion Android/APIExample-Compose/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.APIExampleCompose"
android:supportsPictureInPicture="true"
android:screenOrientation="portrait"
android:configChanges="screenSize|screenLayout|orientation|smallestScreenSize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
Expand All @@ -36,12 +38,14 @@
</intent-filter>
</activity>

<!--
<activity
android:name=".samples.PictureInPictureActivity"
android:supportsPictureInPicture="true"
android:launchMode="singleTask"
android:configChanges="screenSize|screenLayout|orientation|smallestScreenSize"/>
-->

</application>
</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.agora.api.example.compose

import android.util.Log
import androidx.compose.runtime.Composable
import androidx.navigation.NavType
import androidx.navigation.compose.NavHost
Expand All @@ -9,6 +10,7 @@ import androidx.navigation.navArgument
import io.agora.api.example.compose.model.Component
import io.agora.api.example.compose.model.Components
import io.agora.api.example.compose.model.Example
import io.agora.api.example.compose.samples.cleanupPictureInPictureState
import io.agora.api.example.compose.ui.example.Example
import io.agora.api.example.compose.ui.home.Home
import io.agora.api.example.compose.ui.settings.Settings
Expand Down Expand Up @@ -48,7 +50,15 @@ fun NavGraph() {
val example = component.examples[exampleIndex]
Example(
example = example,
onBackClick = { navController.popBackStack() },
onBackClick = {
Log.d("PiPDebug", "NavGraph: onBackClick called for example: ${example.name}")
// Special handling for PictureInPicture example
if (example.name == R.string.example_pictureinpicture) {
Log.d("PiPDebug", "NavGraph: Cleaning up PictureInPicture state")
cleanupPictureInPictureState()
}
navController.popBackStack()
},
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import io.agora.api.example.compose.samples.MediaPlayer
import io.agora.api.example.compose.samples.MediaRecorder
import io.agora.api.example.compose.samples.OriginAudioData
import io.agora.api.example.compose.samples.OriginVideoData
import io.agora.api.example.compose.samples.PictureInPictureEntrance
import io.agora.api.example.compose.samples.PictureInPicture
import io.agora.api.example.compose.samples.PlayAudioFiles
import io.agora.api.example.compose.samples.PreCallTest
import io.agora.api.example.compose.samples.RTMPStreaming
Expand Down Expand Up @@ -54,7 +54,7 @@ val AdvanceExampleList = listOf(
Example(R.string.example_originvideodata) { OriginVideoData() },
Example(R.string.example_customvideosource) { CustomVideoSource() },
Example(R.string.example_customvideorender) { CustomVideoRender() },
Example(R.string.example_pictureinpicture) { PictureInPictureEntrance(it) },
Example(R.string.example_pictureinpicture) { PictureInPicture() },
Example(R.string.example_joinmultichannel) { JoinMultiChannel() },
Example(R.string.example_channelencryption) { ChannelEncryption() },
Example(R.string.example_playaudiofiles) { PlayAudioFiles() },
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.agora.api.example.compose.samples

import android.util.Log
import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
Expand Down Expand Up @@ -57,6 +58,17 @@ import io.agora.rtc2.video.VideoEncoderConfiguration
import io.agora.rtc2.video.VideoEncoderConfiguration.AdvanceOptions
import io.agora.rtc2.video.WatermarkOptions

private const val TAG = "LiveStreaming"

private fun getVideoScenarioName(scenario: Constants.VideoScenario): String {
return when (scenario) {
Constants.VideoScenario.APPLICATION_SCENARIO_GENERAL -> "General"
Constants.VideoScenario.APPLICATION_SCENARIO_MEETING -> "Meeting"
Constants.VideoScenario.APPLICATION_SCENARIO_1V1 -> "1V1"
Constants.VideoScenario.APPLICATION_SCENARIO_LIVESHOW -> "Live Show"
}
}

@Composable
fun LiveStreaming() {
val context = LocalContext.current
Expand All @@ -70,6 +82,9 @@ fun LiveStreaming() {
var localStats by remember { mutableStateOf(VideoStatsInfo()) }
var remoteStats by remember { mutableStateOf(VideoStatsInfo()) }
var clientRole by remember { mutableStateOf(Constants.CLIENT_ROLE_AUDIENCE) }
val settingsValues = remember { mutableStateMapOf<String, Any>().apply {
put("videoScenario", Constants.VideoScenario.APPLICATION_SCENARIO_LIVESHOW)
} }

val rtcEngine = remember {
RtcEngine.create(RtcEngineConfig().apply {
Expand Down Expand Up @@ -177,6 +192,10 @@ fun LiveStreaming() {
), 100, 15
)
)
// Set default video scenario
val defaultScenario = Constants.VideoScenario.APPLICATION_SCENARIO_LIVESHOW
val ret = setVideoScenario(defaultScenario)
Log.d(TAG, "onItemSelected: setVideoScenario " + getVideoScenarioName(defaultScenario) + " ret=" + ret)
}
}
DisposableEffect(lifecycleOwner) {
Expand All @@ -192,6 +211,11 @@ fun LiveStreaming() {
if (allGranted) {
// Permission is granted
Toast.makeText(context, R.string.permission_granted, Toast.LENGTH_LONG).show()
// Set video scenario before joining channel
val scenario = settingsValues["videoScenario"] as? Constants.VideoScenario
?: Constants.VideoScenario.APPLICATION_SCENARIO_LIVESHOW
val ret = rtcEngine.setVideoScenario(scenario)
Log.d(TAG, "onItemSelected: setVideoScenario " + getVideoScenarioName(scenario) + " ret=" + ret)
val mediaOptions = ChannelMediaOptions()
mediaOptions.channelProfile = Constants.CHANNEL_PROFILE_LIVE_BROADCASTING
mediaOptions.clientRoleType = clientRole
Expand All @@ -214,6 +238,7 @@ fun LiveStreaming() {
localStats = localStats,
remoteStats = remoteStats,
localLarge = localLarge,
settingsValues = settingsValues,
onSwitch = {
localLarge = !localLarge
},
Expand Down Expand Up @@ -248,12 +273,12 @@ private fun LiveStreamingView(
localLarge: Boolean = true,
localStats: VideoStatsInfo = VideoStatsInfo(),
remoteStats: VideoStatsInfo = VideoStatsInfo(),
settingsValues: MutableMap<String, Any> = mutableMapOf(),
onSwitch: () -> Unit = {},
onJoinClick: (String) -> Unit,
onLeaveClick: () -> Unit
) {
var openSettingSheet by rememberSaveable { mutableStateOf(false) }
val settingsValues = remember { mutableStateMapOf<String, Any>() }

Box {
Column {
Expand Down Expand Up @@ -349,9 +374,17 @@ private fun LiveStreamingView(
rtcEngine = rtcEngine,
role = clientRole,
remoteUid = remoteUid,
isJoined = isJoined,
values = settingsValues,
onValueChanged = { key, value ->
settingsValues[key] = value
// Update video scenario immediately if not joined
if (key == "videoScenario" && !isJoined) {
val scenario = value as? Constants.VideoScenario
?: Constants.VideoScenario.APPLICATION_SCENARIO_LIVESHOW
val ret = rtcEngine?.setVideoScenario(scenario) ?: -1
Log.d(TAG, "onItemSelected: setVideoScenario " + getVideoScenarioName(scenario) + " ret=" + ret)
}
}
)
}
Expand Down Expand Up @@ -387,15 +420,34 @@ private fun LiveStreamingSettingView(
rtcEngine: RtcEngine? = null,
role: Int = Constants.CLIENT_ROLE_AUDIENCE,
remoteUid: Int = 0,
isJoined: Boolean = false,
values: Map<String, Any> = emptyMap(),
onValueChanged: (String, Any) -> Unit = { _, _ -> }
) {
val context = LocalContext.current
val videoScenario = values["videoScenario"] as? Constants.VideoScenario
?: Constants.VideoScenario.APPLICATION_SCENARIO_LIVESHOW

Column(
modifier = modifier,
horizontalAlignment = Alignment.CenterHorizontally
) {
// Video Scenario selection - must be set before joining channel
DropdownMenuRaw(
title = stringResource(id = R.string.video_scenario),
options = listOf(
stringResource(id = R.string.video_scenario_general) to Constants.VideoScenario.APPLICATION_SCENARIO_GENERAL,
stringResource(id = R.string.video_scenario_meeting) to Constants.VideoScenario.APPLICATION_SCENARIO_MEETING,
stringResource(id = R.string.video_scenario_1v1) to Constants.VideoScenario.APPLICATION_SCENARIO_1V1,
stringResource(id = R.string.video_scenario_liveshow) to Constants.VideoScenario.APPLICATION_SCENARIO_LIVESHOW,
),
selectedValue = videoScenario,
enable = !isJoined,
onSelected = { _, option ->
onValueChanged("videoScenario", option.second)
}
)
Divider(modifier = Modifier.padding(horizontal = 16.dp))
if (role == Constants.CLIENT_ROLE_AUDIENCE) {
SwitchRaw(
title = stringResource(id = R.string.open_low_latency_live),
Expand Down
Loading
Loading