Skip to content

Commit

Permalink
[HMOS]perfect cases and etc.
Browse files Browse the repository at this point in the history
  • Loading branch information
xuchunzhen committed Aug 13, 2024
1 parent cfb4cd9 commit 0ed86ab
Show file tree
Hide file tree
Showing 15 changed files with 367 additions and 91 deletions.
4 changes: 3 additions & 1 deletion HarmonyOS_NEXT/APIExample/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ To build and run the sample application, get an App Id:
export const AppCertificate: String = YOUR APP CERTIFICATE
```
You are all set. Now connect your Android device and run the project.
6. Download the har package from the [official website](https://doc.shengwang.cn/doc/rtc/harmonyos/resources#%E4%B8%8B%E8%BD%BD-sdk) and copy it to `HarmonyOS_NEXT/APIExample/entry/libs/AgoraRtcSdk.har`
You are all set. Now connect your HarmonyOS NEXT device and run the project.
## Contact Us
Expand Down
1 change: 1 addition & 0 deletions HarmonyOS_NEXT/APIExample/README.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
// 注意:App证书放在客户端不安全,推荐放在服务端以确保 App 证书不会泄露。
export const AppCertificate: String = YOUR APP CERTIFICATE
```
6. 在[官网](https://doc.shengwang.cn/doc/rtc/harmonyos/resources#%E4%B8%8B%E8%BD%BD-sdk)上下载har包,并复制到`HarmonyOS_NEXT/APIExample/entry/libs/AgoraRtcSdk.har`
然后你就可以编译并运行项目了。
Expand Down
13 changes: 0 additions & 13 deletions HarmonyOS_NEXT/APIExample/build-profile.json5
Original file line number Diff line number Diff line change
@@ -1,19 +1,6 @@
{
"app": {
"signingConfigs": [
{
"name": "default",
"type": "HarmonyOS",
"material": {
"storePassword": "0000001AFF29DB3BEECB8DFBCB654F4C6508B4014EF1F24FF2EC288A518577ECF1AB218F7E3E2C89130B",
"certpath": "/Users/xcz/Workspaces/DevEcoStudioProjects/apiexample.cer",
"keyAlias": "apiexample",
"keyPassword": "0000001A8B816C41577C05ECEC8B7FF34ECB08629228D14936A048DA498A2225ED4BD6385F64C79D2F69",
"profile": "/Users/xcz/Workspaces/DevEcoStudioProjects/apiexampleDebug.p7b",
"signAlg": "SHA256withECDSA",
"storeFile": "/Users/xcz/Workspaces/DevEcoStudioProjects/apiexample.p12"
}
}
],
"products": [
{
Expand Down
2 changes: 1 addition & 1 deletion HarmonyOS_NEXT/APIExample/entry/oh-package-lock.json5

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion HarmonyOS_NEXT/APIExample/entry/src/main/ets/pages/Data.ets
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,15 @@ export const ADVANCE_ITEMS: ExampleItem[] =
{
title: $r('app.string.item_mediarecorder'),
url: 'pages/advance/MediaRecorder'
},{
},
{
title: $r('app.string.item_localvideotranscoding'),
url: 'pages/advance/LocalVideoTranscoding'
},
{
title: $r('app.string.item_hostcrosschannel'),
url: 'pages/advance/HostCrossChannel'
},
]

export const COLLECTION_CATEGORIES: ExampleCategory[] =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Constants, OrientationMode, RtcEngine, VideoDimensions, VideoEncoderConfiguration } from 'AgoraRtcSdk'
import { OrientationMode, RtcEngine, VideoDimensions } from 'AgoraRtcSdk'
import { TitleBar } from '../common/TitleBar'
import { CommonItemSelect } from '../common/Widgets'
import { GlobalInfo } from './Data'
Expand All @@ -17,7 +17,7 @@ struct Settings {
private dimensionStrList: ResourceStr[] = []
private dimensionSelectedIndex = 0
private frameRateList: number[] = [
15, 24, 30
15, 24, 30, 60
]
private frameRateStrList: ResourceStr[] = []
private frameRateSelectedIndex = 0
Expand Down Expand Up @@ -94,7 +94,10 @@ struct Settings {

Divider().margin({ left: 20, right: 20 })

// Text("SDK Version:" + RtcEngine.getSdkVersion())
Text("SDK Version:" + RtcEngine.getSdkVersion())
.width('100%')
.textAlign(TextAlign.End)
.padding({top: 12, right: 26})
}
}
.backgroundColor($r('app.color.background_shallow_grey'))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
import {
ChannelMediaOptions,
ChannelMediaRelayConfiguration,
Constants,
RtcEngine,
RtcEngineConfig,
VideoCanvas,
VideoEncoderConfiguration
} from 'AgoraRtcSdk';
import { TitleBar } from '../../common/TitleBar';
import Logger from '../../util/Logger';
import ShowToast from '../../util/ShowToast';
import { AppID } from '../../common/KeyCenter';
import PermissionHelper from '../../util/PermissionHelper';
import { common } from '@kit.AbilityKit';
import { GlobalInfo } from '../Data';
import { TokenUtils } from '../../util/TokenUtils';

const TAG: string = 'JoinVideoChannel'

@Entry
@Component
struct HostCrossChannel {
private rtcEngine: RtcEngine | undefined = undefined;
@State channelName: string = ''
@State isJoin: boolean = false
@State localUid: number = 0
@State remoteUid: number = 0
@State relayChannelName: string = ''
@State isRelayStart: boolean = false
@State isRelayPause: boolean = false

aboutToAppear(): void {
Logger.info(TAG, 'aboutToAppear')
let config: RtcEngineConfig = new RtcEngineConfig();
let context = getContext(this) as common.UIAbilityContext;
config.mAppId = AppID;
config.mEventHandler = {};
config.mEventHandler.onUserJoined = (uid: number, collapse: number) => {
Logger.info(TAG, "mEventHandler.onUserJoined: " + uid + " , " + collapse);
if (this.remoteUid == 0) {
this.remoteUid = uid
}
};
config.mEventHandler.onUserOffline = (uid: number, reason: number) => {
Logger.info(TAG, "mEventHandler.onUserOffline: " + uid + " , " + reason)
if (this.remoteUid == uid) {
this.remoteUid = 0
}
};
config.mEventHandler.onJoinChannelSuccess = (cid: string, uid: number, elapsed: number) => {
Logger.info(TAG, "mEventHandler.onJoinChannelSuccess: " + uid);
this.isJoin = true
this.localUid = uid
}
config.mEventHandler.onLeaveChannel = () => {
Logger.info(TAG, "mEventHandler.onLeaveChannel");
this.isJoin = false
this.localUid = 0
this.remoteUid = 0
}
config.mEventHandler.onError = (err: number, message: string) => {
Logger.info(TAG, "mEventHandler.onError: " + err + " message " + message);
ShowToast.longToast("onError " + err + " : " + message)
}
config.mEventHandler.onChannelMediaRelayStateChanged = (state: number, code: number) => {
Logger.info(TAG, "mEventHandler.onChannelMediaRelayStateChanged: state=" + state + " code=" + code);
if (code == 0) {
if (state == 2) {
// RELAY_STATE_RUNNING
this.isRelayStart = true
} else {
this.isRelayStart = false
}
} else {
ShowToast.longToast("onChannelMediaRelayStateChanged error >> " + code + " : " + code)
}
}
config.mContext = context;
Logger.info(TAG, "in thread create engine begin: ");
this.rtcEngine = RtcEngine.create(config);

let encoderConfig = new VideoEncoderConfiguration()
encoderConfig.dimensions = GlobalInfo.settings.dimensions
encoderConfig.frameRate = GlobalInfo.settings.frameRate
encoderConfig.orientationMode = GlobalInfo.settings.orientationMode
this.rtcEngine.setVideoEncoderConfiguration(encoderConfig)
this.rtcEngine.enableVideo()
}

aboutToDisappear(): void {
if (this.rtcEngine != undefined) {
if (this.isJoin) {
this.rtcEngine.stopPreview();
this.rtcEngine.leaveChannel();
}
Logger.info(TAG, "destroy begin")
RtcEngine.destroy().then(() => {
Logger.info(TAG, "destroy done")
});
Logger.info(TAG, "destroy end")
this.rtcEngine = undefined;
}
}

build() {
Column() {
TitleBar({
title: $r('app.string.item_hostcrosschannel'),
showBack: true
})

Column() {
Row() {
if (this.localUid != 0) {
XComponent({
id: 'preview_local',
type: 'surface',
libraryname: Constants.AGORA_LIB_NAME,
}).onLoad(() => {
let localCanvas = new VideoCanvas("preview_local");
localCanvas.uid = this.localUid;
localCanvas.renderMode = VideoCanvas.RENDER_MODE_HIDDEN;
localCanvas.mirrorMode = 0;
this.rtcEngine?.setupLocalVideo(localCanvas);
}).width('50%')
}

if (this.remoteUid != 0) {
XComponent({
id: 'preview_remote',
type: 'surface',
libraryname: Constants.AGORA_LIB_NAME,
}).onLoad(() => {
let localCanvas = new VideoCanvas("preview_remote");
localCanvas.uid = this.remoteUid;
localCanvas.renderMode = VideoCanvas.RENDER_MODE_HIDDEN;
localCanvas.mirrorMode = 0;
this.rtcEngine?.setupRemoteVideo(localCanvas);
}).width('50%')
}
}
.align(Alignment.TopStart)
.height("50%")
.width('100%')
}
.align(Alignment.TopStart)
.layoutWeight(1.0)


Row() {
TextInput({ placeholder: $r('app.string.text_input_target_channel_name') })
.id("input_target_channel_name")
.enabled(!this.isRelayStart)
.enableKeyboardOnFocus(false)
.onChange((value: string) => {
this.relayChannelName = value
})
.layoutWeight(1.0)
.margin({ right: 6 })

// Button(this.isRelayPause ? $r('app.string.resume') : $r('app.string.pause'))
// .id('button_to_pause_relay')
// .enabled(this.isRelayJoin)
// .onClick(async () => {
// focusControl.requestFocus("button_to_pause_relay")
// if (this.isRelayPause) {
// this.rtcEngine?.resumeAllChannelMediaRelay()
// } else {
// this.rtcEngine?.pauseAllChannelMediaRelay()
// }
// })

Button(this.isRelayStart ? $r('app.string.stop') : $r('app.string.start'))
.id('button_to_join_relay')
.enabled(this.isJoin)
.onClick(async () => {
focusControl.requestFocus("button_to_join_relay")
if (this.isRelayStart) {
this.rtcEngine?.stopChannelMediaRelay()
} else {
if (this.relayChannelName == "") {
ShowToast.shortToast("The target channel name is empty!")
return
}
let config = new ChannelMediaRelayConfiguration()
config.srcInfo.channelName = this.channelName
config.srcInfo.uid = this.localUid
config.srcInfo.token = await TokenUtils.genRtcToken(this.channelName, '')
config.destInfos[this.relayChannelName] = {
channelName: this.relayChannelName,
uid: 999,
token: await TokenUtils.genRtcToken(this.relayChannelName, '999')
}
this.rtcEngine?.startOrUpdateChannelMediaRelay(config)
}
})
}
.padding({
left: 12,
right: 12,
top: 6,
bottom: 6
})

Row() {
TextInput({ placeholder: $r('app.string.text_input_channel_name') })
.id("input_channel_name")
.enabled(!this.isJoin)
.enableKeyboardOnFocus(false)
.onChange((value: string) => {
this.channelName = value
})
.layoutWeight(1.0)
.margin({ right: 6 })

Button(this.isJoin ? $r('app.string.leave') : $r('app.string.join'))
.id('button_to_join')
.onClick(async () => {

focusControl.requestFocus("button_to_join")

if (this.isJoin) {
this.rtcEngine?.stopPreview()
this.rtcEngine?.leaveChannel()
} else {
if (this.channelName == "") {
ShowToast.shortToast("The channel name is empty!")
return
}
if (!(await PermissionHelper.checkPermissions(
getContext(this) as common.UIAbilityContext,
['ohos.permission.MICROPHONE', 'ohos.permission.CAMERA']
))) {
ShowToast.shortToast("Permission leak!")
return
}


let mediaOption: ChannelMediaOptions = new ChannelMediaOptions();
mediaOption.publishCameraTrack = true;
mediaOption.publishMicrophoneTrack = true;
mediaOption.autoSubscribeVideo = true;
mediaOption.autoSubscribeAudio = true;
mediaOption.channelProfile = Constants.ChannelProfile.LIVE_BROADCASTING;
mediaOption.clientRoleType = Constants.ClientRole.BROADCASTER;

let token = await TokenUtils.genRtcToken(this.channelName, "")
let ret = this.rtcEngine?.joinChannelWithOptions(token, this.channelName, 0, mediaOption)
if (ret != Constants.ErrorCode.ERR_OK) {
ShowToast.longToast("joinChannelWithOptions error " + ret + " : " +
RtcEngine.getErrorDescription(ret))
return
}

this.rtcEngine?.startPreview()
}
})
}
.padding({
left: 12,
right: 12,
top: 6,
bottom: 6
})
}
.backgroundColor($r('app.color.background_shallow_grey'))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,14 @@ struct LiveStreaming {
focusControl.requestFocus("button_to_linking")
})
.flexGrow(0)

Button($r('app.string.switch_camera'))
.id('button_to_switch_camera')
.enabled(this.isJoin)
.onClick(() => {
this.rtcEngine?.switchCamera()
})
.margin({ left: 12 })
}
.width('100%')
.height('100%')
Expand Down
Loading

0 comments on commit 0ed86ab

Please sign in to comment.