├── ios ├── Runner │ ├── Runner-Bridging-Header.h │ ├── Assets.xcassets │ │ ├── LaunchImage.imageset │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ ├── README.md │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ ├── Icon-App-83.5x83.5@2x.png │ │ │ └── Contents.json │ ├── Runner.entitlements │ ├── AppDelegate.swift │ ├── Base.lproj │ │ ├── Main.storyboard │ │ └── LaunchScreen.storyboard │ └── Info.plist ├── build │ └── XCBuildData │ │ ├── build.db │ │ ├── 28b05d5636f9ccc74024efa9ef9d368d-desc.xcbuild │ │ ├── 42719faed8c9a22243d73b2af43c3423-desc.xcbuild │ │ ├── 485b9e15f05548fb6a5fac001a0c3e10-desc.xcbuild │ │ ├── 582af4fac726bf349c1e7f16084b03c0-desc.xcbuild │ │ └── BuildDescriptionCacheIndex-e49fcf9e8f77f4164d3b44e71466ba76 ├── Flutter │ ├── Debug.xcconfig │ ├── Release.xcconfig │ └── AppFrameworkInfo.plist ├── TXLiteAVSDK_ReplayKitExt.framework │ ├── Info.plist │ ├── Modules │ │ └── module.modulemap │ ├── Headers │ │ ├── TXLiteAVSDK_ReplayKitExt.h │ │ └── TXReplayKitExt.h │ └── TXLiteAVSDK_ReplayKitExt ├── Runner.xcodeproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── WorkspaceSettings.xcsettings │ │ └── IDEWorkspaceChecks.plist ├── upload │ ├── upload.entitlements │ ├── Info.plist │ └── SampleHandler.swift ├── .gitignore ├── Podfile └── Podfile.lock ├── android ├── .settings │ └── org.eclipse.buildship.core.prefs ├── gradle.properties ├── app │ ├── src │ │ ├── main │ │ │ ├── res │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── drawable │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── drawable-v21 │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── values │ │ │ │ │ └── styles.xml │ │ │ │ └── values-night │ │ │ │ │ └── styles.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── example │ │ │ │ │ └── trtcscenesdemo │ │ │ │ │ └── MainActivity.kt │ │ │ └── AndroidManifest.xml │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ └── profile │ │ │ └── AndroidManifest.xml │ ├── .project │ └── build.gradle ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── .gitignore ├── settings.gradle ├── build.gradle └── .project ├── lib ├── TRTCCallingDemo │ ├── ui │ │ └── base │ │ │ ├── CallStatus.dart │ │ │ ├── CallTypes.dart │ │ │ ├── CallingScenes.dart │ │ │ └── ExtendButton.dart │ └── model │ │ ├── TRTCCallingDef.dart │ │ ├── TRTCCallingDelegate.dart │ │ └── TRTCCalling.dart ├── utils │ ├── constants.dart │ └── TxUtils.dart ├── TRTCChatSalonDemo │ ├── ui │ │ ├── base │ │ │ └── UserEnum.dart │ │ └── widget │ │ │ ├── DescriptionTitle.dart │ │ │ ├── AudienceItem.dart │ │ │ └── RoomTopMsg.dart │ └── model │ │ ├── TRTCChatSalonDef.dart │ │ ├── TRTCChatSalonDelegate.dart │ │ └── TRTCChatSalon.dart ├── TRTCLiveRoomDemo │ ├── ui │ │ └── base │ │ │ ├── LiveImgButton.dart │ │ │ ├── LiveTextButton.dart │ │ │ ├── FavoriteAnimation.dart │ │ │ ├── LiveMessageList.dart │ │ │ ├── PopUpMessageList.dart │ │ │ ├── PKUserList.dart │ │ │ └── SubVideoList.dart │ └── model │ │ ├── TRTCLiveRoomDef.dart │ │ ├── TRTCLiveRoomDelegate.dart │ │ └── TRTCLiveRoom.dart ├── TRTCMeetingDemo │ ├── model │ │ ├── TRTCMeetingDef.dart │ │ └── TRTCMeetingDelegate.dart │ └── ui │ │ └── TRTCMeetingTools.dart ├── login │ ├── ProfileManager_Mock.dart │ └── LoginPage.dart ├── main.dart ├── routes │ └── routes.dart ├── base │ └── YunApiHelper.dart ├── i10n │ ├── messages_all.dart │ ├── messages_zh_CN.dart │ ├── messages_messages.dart │ └── messages_en_US.dart ├── debug │ └── GenerateTestUserSig.dart └── index.dart ├── assets └── images │ ├── ChatSalon.png │ ├── DownWheat.png │ ├── raiseHand.png │ ├── sound_off.png │ ├── speaking.png │ ├── Anchor-exp.jpg │ ├── Anchor_ICON.png │ ├── after-HandUp.png │ ├── liveRoom │ ├── PK.png │ ├── Like.png │ ├── music.png │ ├── share.png │ ├── Barrage.png │ ├── Comment.png │ ├── Filter.png │ ├── 观看数量@3x.png │ ├── Barrage-ON.png │ ├── closeRoom.png │ ├── CameraSwitch.png │ ├── Microphone-on.png │ ├── Microphone-off.png │ ├── barrage_slider_off.png │ ├── barrage_slider_on.png │ └── music │ │ ├── no_select_hover.png │ │ ├── no_select_normal.png │ │ ├── changetype_child_hover.png │ │ ├── changetype_dashu_hover.png │ │ ├── changetype_luoli_hover.png │ │ ├── reverbtype_ktv_hover.png │ │ ├── reverbtype_ktv_normal.png │ │ ├── changetype_child_normal.png │ │ ├── changetype_dashu_normal.png │ │ ├── changetype_luoli_normal.png │ │ ├── reverbtype_lowdeep_hover.png │ │ ├── changetype_kongling_hover.png │ │ ├── changetype_kongling_normal.png │ │ ├── reverbtype_heavymetal_hover.png │ │ ├── reverbtype_hongliang_hover.png │ │ ├── reverbtype_hongliang_normal.png │ │ ├── reverbtype_lowdeep_normal.png │ │ └── reverbtype_heavymetal_normal.png │ ├── no-speaking.png │ ├── noRaiseHand.png │ ├── Administrator.png │ ├── Audience_ICON.png │ ├── Audience_exp.jpeg │ ├── before-HandUp.png │ ├── bg_main_title.png │ ├── raiseHandList.png │ └── callingDemo │ ├── hangup.png │ ├── search.png │ ├── audioCall.png │ ├── camera-off.png │ ├── camera-on.png │ ├── videoCall.png │ ├── meetingCall.png │ ├── microphone-off.png │ ├── microphone-on.png │ ├── switch-camera.png │ ├── switchToAudio.png │ ├── trtccalling_ic_dialing.png │ ├── trtccalling_ic_dialing_pressed.png │ ├── trtccalling_ic_handsfree_disable.png │ └── trtccalling_ic_handsfree_enable.png ├── .metadata ├── intl.sh ├── .gitignore ├── README.md ├── pubspec.yaml ├── TRTCCallingAudio.md ├── TRTCCallingVideo.md └── i10n-arb ├── intl_zh_CN.arb └── intl_messages.arb /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /android/.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | connection.project.dir= 2 | eclipse.preferences.version=1 3 | -------------------------------------------------------------------------------- /lib/TRTCCallingDemo/ui/base/CallStatus.dart: -------------------------------------------------------------------------------- 1 | enum CallStatus { 2 | calling, //拨打中 3 | answer, //已接听 4 | } 5 | -------------------------------------------------------------------------------- /assets/images/ChatSalon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/ChatSalon.png -------------------------------------------------------------------------------- /assets/images/DownWheat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/DownWheat.png -------------------------------------------------------------------------------- /assets/images/raiseHand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/raiseHand.png -------------------------------------------------------------------------------- /assets/images/sound_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/sound_off.png -------------------------------------------------------------------------------- /assets/images/speaking.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/speaking.png -------------------------------------------------------------------------------- /assets/images/Anchor-exp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/Anchor-exp.jpg -------------------------------------------------------------------------------- /assets/images/Anchor_ICON.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/Anchor_ICON.png -------------------------------------------------------------------------------- /assets/images/after-HandUp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/after-HandUp.png -------------------------------------------------------------------------------- /assets/images/liveRoom/PK.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/liveRoom/PK.png -------------------------------------------------------------------------------- /assets/images/no-speaking.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/no-speaking.png -------------------------------------------------------------------------------- /assets/images/noRaiseHand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/noRaiseHand.png -------------------------------------------------------------------------------- /ios/build/XCBuildData/build.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/ios/build/XCBuildData/build.db -------------------------------------------------------------------------------- /assets/images/Administrator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/Administrator.png -------------------------------------------------------------------------------- /assets/images/Audience_ICON.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/Audience_ICON.png -------------------------------------------------------------------------------- /assets/images/Audience_exp.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/Audience_exp.jpeg -------------------------------------------------------------------------------- /assets/images/before-HandUp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/before-HandUp.png -------------------------------------------------------------------------------- /assets/images/bg_main_title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/bg_main_title.png -------------------------------------------------------------------------------- /assets/images/liveRoom/Like.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/liveRoom/Like.png -------------------------------------------------------------------------------- /assets/images/liveRoom/music.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/liveRoom/music.png -------------------------------------------------------------------------------- /assets/images/liveRoom/share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/liveRoom/share.png -------------------------------------------------------------------------------- /assets/images/raiseHandList.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/raiseHandList.png -------------------------------------------------------------------------------- /assets/images/liveRoom/Barrage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/liveRoom/Barrage.png -------------------------------------------------------------------------------- /assets/images/liveRoom/Comment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/liveRoom/Comment.png -------------------------------------------------------------------------------- /assets/images/liveRoom/Filter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/liveRoom/Filter.png -------------------------------------------------------------------------------- /assets/images/liveRoom/观看数量@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/liveRoom/观看数量@3x.png -------------------------------------------------------------------------------- /lib/TRTCCallingDemo/ui/base/CallTypes.dart: -------------------------------------------------------------------------------- 1 | enum CallTypes { 2 | Type_Call_Someone, //主动拨打某人 3 | Type_Being_Called, //作为用户被叫 4 | } 5 | -------------------------------------------------------------------------------- /lib/TRTCCallingDemo/ui/base/CallingScenes.dart: -------------------------------------------------------------------------------- 1 | enum CallingScenes { 2 | VideoOneVOne, //一对一视频通话 3 | AudioOneVOne, //一对一语音通话 4 | } 5 | -------------------------------------------------------------------------------- /assets/images/callingDemo/hangup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/callingDemo/hangup.png -------------------------------------------------------------------------------- /assets/images/callingDemo/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/callingDemo/search.png -------------------------------------------------------------------------------- /assets/images/liveRoom/Barrage-ON.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/liveRoom/Barrage-ON.png -------------------------------------------------------------------------------- /assets/images/liveRoom/closeRoom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/liveRoom/closeRoom.png -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | android.enableR8=true 5 | -------------------------------------------------------------------------------- /assets/images/callingDemo/audioCall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/callingDemo/audioCall.png -------------------------------------------------------------------------------- /assets/images/callingDemo/camera-off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/callingDemo/camera-off.png -------------------------------------------------------------------------------- /assets/images/callingDemo/camera-on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/callingDemo/camera-on.png -------------------------------------------------------------------------------- /assets/images/callingDemo/videoCall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/callingDemo/videoCall.png -------------------------------------------------------------------------------- /assets/images/liveRoom/CameraSwitch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/liveRoom/CameraSwitch.png -------------------------------------------------------------------------------- /assets/images/liveRoom/Microphone-on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/liveRoom/Microphone-on.png -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /assets/images/callingDemo/meetingCall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/callingDemo/meetingCall.png -------------------------------------------------------------------------------- /assets/images/liveRoom/Microphone-off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/liveRoom/Microphone-off.png -------------------------------------------------------------------------------- /assets/images/callingDemo/microphone-off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/callingDemo/microphone-off.png -------------------------------------------------------------------------------- /assets/images/callingDemo/microphone-on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/callingDemo/microphone-on.png -------------------------------------------------------------------------------- /assets/images/callingDemo/switch-camera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/callingDemo/switch-camera.png -------------------------------------------------------------------------------- /assets/images/callingDemo/switchToAudio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/callingDemo/switchToAudio.png -------------------------------------------------------------------------------- /assets/images/liveRoom/barrage_slider_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/liveRoom/barrage_slider_off.png -------------------------------------------------------------------------------- /assets/images/liveRoom/barrage_slider_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/liveRoom/barrage_slider_on.png -------------------------------------------------------------------------------- /assets/images/liveRoom/music/no_select_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/liveRoom/music/no_select_hover.png -------------------------------------------------------------------------------- /assets/images/liveRoom/music/no_select_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/liveRoom/music/no_select_normal.png -------------------------------------------------------------------------------- /ios/TXLiteAVSDK_ReplayKitExt.framework/Info.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/ios/TXLiteAVSDK_ReplayKitExt.framework/Info.plist -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /assets/images/callingDemo/trtccalling_ic_dialing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/callingDemo/trtccalling_ic_dialing.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /assets/images/liveRoom/music/changetype_child_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/liveRoom/music/changetype_child_hover.png -------------------------------------------------------------------------------- /assets/images/liveRoom/music/changetype_dashu_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/liveRoom/music/changetype_dashu_hover.png -------------------------------------------------------------------------------- /assets/images/liveRoom/music/changetype_luoli_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/liveRoom/music/changetype_luoli_hover.png -------------------------------------------------------------------------------- /assets/images/liveRoom/music/reverbtype_ktv_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/liveRoom/music/reverbtype_ktv_hover.png -------------------------------------------------------------------------------- /assets/images/liveRoom/music/reverbtype_ktv_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/liveRoom/music/reverbtype_ktv_normal.png -------------------------------------------------------------------------------- /assets/images/liveRoom/music/changetype_child_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/liveRoom/music/changetype_child_normal.png -------------------------------------------------------------------------------- /assets/images/liveRoom/music/changetype_dashu_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/liveRoom/music/changetype_dashu_normal.png -------------------------------------------------------------------------------- /assets/images/liveRoom/music/changetype_luoli_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/liveRoom/music/changetype_luoli_normal.png -------------------------------------------------------------------------------- /assets/images/liveRoom/music/reverbtype_lowdeep_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/liveRoom/music/reverbtype_lowdeep_hover.png -------------------------------------------------------------------------------- /assets/images/callingDemo/trtccalling_ic_dialing_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/callingDemo/trtccalling_ic_dialing_pressed.png -------------------------------------------------------------------------------- /assets/images/liveRoom/music/changetype_kongling_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/liveRoom/music/changetype_kongling_hover.png -------------------------------------------------------------------------------- /assets/images/liveRoom/music/changetype_kongling_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/liveRoom/music/changetype_kongling_normal.png -------------------------------------------------------------------------------- /assets/images/liveRoom/music/reverbtype_heavymetal_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/liveRoom/music/reverbtype_heavymetal_hover.png -------------------------------------------------------------------------------- /assets/images/liveRoom/music/reverbtype_hongliang_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/liveRoom/music/reverbtype_hongliang_hover.png -------------------------------------------------------------------------------- /assets/images/liveRoom/music/reverbtype_hongliang_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/liveRoom/music/reverbtype_hongliang_normal.png -------------------------------------------------------------------------------- /assets/images/liveRoom/music/reverbtype_lowdeep_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/liveRoom/music/reverbtype_lowdeep_normal.png -------------------------------------------------------------------------------- /ios/TXLiteAVSDK_ReplayKitExt.framework/Modules/module.modulemap: -------------------------------------------------------------------------------- 1 | framework module TXLiteAVSDK_ReplayKitExt { 2 | umbrella header "TXLiteAVSDK_ReplayKitExt.h" 3 | export * 4 | } 5 | -------------------------------------------------------------------------------- /assets/images/callingDemo/trtccalling_ic_handsfree_disable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/callingDemo/trtccalling_ic_handsfree_disable.png -------------------------------------------------------------------------------- /assets/images/callingDemo/trtccalling_ic_handsfree_enable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/callingDemo/trtccalling_ic_handsfree_enable.png -------------------------------------------------------------------------------- /assets/images/liveRoom/music/reverbtype_heavymetal_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/assets/images/liveRoom/music/reverbtype_heavymetal_normal.png -------------------------------------------------------------------------------- /ios/TXLiteAVSDK_ReplayKitExt.framework/Headers/TXLiteAVSDK_ReplayKitExt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Module: TXReplayKitExt @ TXLiteAVSDK 3 | */ 4 | 5 | #import 6 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/TXLiteAVSDK_ReplayKitExt.framework/TXLiteAVSDK_ReplayKitExt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/ios/TXLiteAVSDK_ReplayKitExt.framework/TXLiteAVSDK_ReplayKitExt -------------------------------------------------------------------------------- /lib/utils/constants.dart: -------------------------------------------------------------------------------- 1 | const USERID_KEY = "UserId"; 2 | const DEFAULT_ROOM_IMAGE = 3 | "https://imgcache.qq.com/operation/dianshi/other/2.4c958e11852b2caa75da6c2726f9248108d6ec8a.png"; 4 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /ios/build/XCBuildData/28b05d5636f9ccc74024efa9ef9d368d-desc.xcbuild: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/ios/build/XCBuildData/28b05d5636f9ccc74024efa9ef9d368d-desc.xcbuild -------------------------------------------------------------------------------- /ios/build/XCBuildData/42719faed8c9a22243d73b2af43c3423-desc.xcbuild: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/ios/build/XCBuildData/42719faed8c9a22243d73b2af43c3423-desc.xcbuild -------------------------------------------------------------------------------- /ios/build/XCBuildData/485b9e15f05548fb6a5fac001a0c3e10-desc.xcbuild: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/ios/build/XCBuildData/485b9e15f05548fb6a5fac001a0c3e10-desc.xcbuild -------------------------------------------------------------------------------- /ios/build/XCBuildData/582af4fac726bf349c1e7f16084b03c0-desc.xcbuild: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/ios/build/XCBuildData/582af4fac726bf349c1e7f16084b03c0-desc.xcbuild -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /lib/TRTCChatSalonDemo/ui/base/UserEnum.dart: -------------------------------------------------------------------------------- 1 | enum UserType { 2 | Anchor, //主播 3 | Administrator, //管理员 4 | Audience, //听众 5 | } 6 | enum UserStatus { 7 | Speaking, //讲话中 8 | Mute, //静音中 9 | } 10 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/example/trtcscenesdemo/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.trtc_scenes_demo 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/build/XCBuildData/BuildDescriptionCacheIndex-e49fcf9e8f77f4164d3b44e71466ba76: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/TRTCFlutterScenesDemo/HEAD/ios/build/XCBuildData/BuildDescriptionCacheIndex-e49fcf9e8f77f4164d3b44e71466ba76 -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip 7 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: c6290500f827e006858ef2d17081b363949f6ce0 8 | channel: master 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /ios/Runner/Runner.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.application-groups 6 | 7 | group.com.tencent.trtc.scenes.demo.ios 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/upload/upload.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.application-groups 6 | 7 | group.com.tencent.trtc.scenes.demo.ios 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/app.flx 22 | Flutter/app.zip 23 | Flutter/flutter_assets/ 24 | Flutter/flutter_export_environment.sh 25 | ServiceDefinitions.json 26 | Runner/GeneratedPluginRegistrant.* 27 | 28 | # Exceptions to above rules. 29 | !default.mode1v3 30 | !default.mode2v3 31 | !default.pbxuser 32 | !default.perspectivev3 33 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.6.10' 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:7.0.2' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | jcenter() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /intl.sh: -------------------------------------------------------------------------------- 1 | 2 | # 生成intl_messages.arb文件 3 | # flutter pub pub run intl_translation:extract_to_arb --output-dir=i10n-arb lib/i10n/localization_intl.dart 4 | 5 | # # 复制生成一份intl_zh_CN.arb文件 6 | # rm i10n-arb/intl_zh_CN.arb 7 | # rm i10n-arb/intl_en_US.arb 8 | # cp i10n-arb/intl_messages.arb i10n-arb/intl_zh_CN.arb 9 | # cp i10n-arb/intl_messages.arb i10n-arb/intl_en_US.arb 10 | 11 | 12 | # 在文件intl_zh_CN.arb添加 "@@locale":"zh_CN" , 13 | # 在文件intl_en_US.arb添加 "@@locale":"en_US" , 14 | 15 | # 根据.arb文件 生成messages_messages.dart和messages_zh_CN.dart 16 | flutter pub pub run intl_translation:generate_from_arb --output-dir=lib/i10n --no-use-deferred-loading lib/i10n/localization_intl.dart i10n-arb/intl_*.arb 17 | 18 | # 把intl_en_US.arb给翻译同学翻译即可 -------------------------------------------------------------------------------- /lib/TRTCLiveRoomDemo/ui/base/LiveImgButton.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class LiveImgButton extends StatelessWidget { 4 | const LiveImgButton( 5 | {Key? key, required this.onTap, required this.imgUrl, this.imgSize = 32}) 6 | : super(key: key); 7 | final Function onTap; 8 | final String imgUrl; 9 | final double imgSize; 10 | @override 11 | Widget build(BuildContext context) { 12 | return Container( 13 | margin: EdgeInsets.all(5), 14 | child: InkWell( 15 | onTap: () { 16 | this.onTap(); 17 | }, 18 | child: Image.asset( 19 | this.imgUrl, 20 | height: this.imgSize, 21 | width: this.imgSize, 22 | ), 23 | ), 24 | ); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/TRTCMeetingDemo/model/TRTCMeetingDef.dart: -------------------------------------------------------------------------------- 1 | // 关键类型定义 2 | 3 | class ActionCallback { 4 | /// 错误码 5 | int code; 6 | 7 | /// 信息描述 8 | String desc; 9 | 10 | ActionCallback({this.code = 0, this.desc = ''}); 11 | } 12 | 13 | class UserListCallback { 14 | /// 错误码 15 | int code; 16 | 17 | /// 信息描述 18 | String desc; 19 | 20 | /// 用户信息列表 21 | List? list; 22 | 23 | UserListCallback({ 24 | this.code = 0, 25 | this.desc = '', 26 | this.list, 27 | }); 28 | } 29 | 30 | class UserInfo { 31 | /// 用户唯一标识 32 | String? userId; 33 | 34 | /// 用户昵称 35 | String? userName; 36 | 37 | /// 用户头像 38 | String? userAvatar; 39 | 40 | UserInfo({ 41 | this.userId, 42 | this.userName, 43 | this.userAvatar, 44 | }); 45 | } 46 | -------------------------------------------------------------------------------- /android/app/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | app 4 | Project app created by Buildship. 5 | 6 | 7 | 8 | 9 | org.eclipse.buildship.core.gradleprojectbuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.buildship.core.gradleprojectnature 16 | 17 | 18 | 19 | 1614138230374 20 | 21 | 30 22 | 23 | org.eclipse.core.resources.regexFilterMatcher 24 | node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /android/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | android 4 | Project android created by Buildship. 5 | 6 | 7 | 8 | 9 | org.eclipse.buildship.core.gradleprojectbuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.buildship.core.gradleprojectnature 16 | 17 | 18 | 19 | 1614138230371 20 | 21 | 30 22 | 23 | org.eclipse.core.resources.regexFilterMatcher 24 | node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /lib/TRTCChatSalonDemo/ui/widget/DescriptionTitle.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class DescriptionTitle extends StatelessWidget { 5 | DescriptionTitle(this.imgUrl, this.title, {Key? key}) : super(key: key); 6 | final String imgUrl; 7 | final String title; 8 | @override 9 | Widget build(BuildContext context) { 10 | return Row( 11 | children: [ 12 | Padding( 13 | padding: EdgeInsets.fromLTRB(15, 0, 0, 0), 14 | child: Image.asset( 15 | imgUrl, 16 | height: 16, 17 | width: 16, 18 | ), 19 | ), 20 | Padding( 21 | padding: EdgeInsets.fromLTRB(10, 0, 0, 0), 22 | child: Text( 23 | title, 24 | style: TextStyle(color: Colors.white), 25 | ), 26 | ), 27 | ], 28 | ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | lib/generated_plugin_registrant.dart 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Android Studio will place build artifacts here 44 | /android/app/debug 45 | /android/app/profile 46 | /android/app/release 47 | ios/SignProvision 48 | lib/debug/Config.dart 49 | ios/Podfile.lock 50 | .vscode -------------------------------------------------------------------------------- /lib/login/ProfileManager_Mock.dart: -------------------------------------------------------------------------------- 1 | import '../utils/TxUtils.dart'; 2 | 3 | class UserModel { 4 | String phone; 5 | String name; 6 | String avatar; 7 | String userId; 8 | UserModel( 9 | {this.phone = '', this.name = '', this.avatar = '', this.userId = ''}); 10 | } 11 | 12 | class ProfileManager { 13 | static ProfileManager? _instance; 14 | 15 | static getInstance() { 16 | if (_instance == null) { 17 | _instance = new ProfileManager(); 18 | } 19 | return _instance; 20 | } 21 | 22 | Future> queryUserInfo(String userId) { 23 | return Future.value([ 24 | UserModel( 25 | phone: userId, 26 | name: userId, 27 | avatar: TxUtils.getDefaltAvatarUrl(), 28 | userId: userId) 29 | ]); 30 | } 31 | 32 | Future querySingleUserInfo(String userId) { 33 | return Future.value(UserModel( 34 | phone: userId, 35 | name: userId, 36 | avatar: TxUtils.getDefaltAvatarUrl(), 37 | userId: userId)); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /lib/TRTCMeetingDemo/ui/TRTCMeetingTools.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | import './TRTCMeetingRoom.dart'; 3 | 4 | class MeetingTool { 5 | // 每4个一屏,得到一个二维数组 6 | static int screenLen = 4; 7 | static List> getScreenList(List list) { 8 | int len = screenLen; //4个一屏 9 | int index = 1; 10 | List> result = []; 11 | 12 | while (index * len < list.length) { 13 | List temp = list.skip((index - 1) * len).take(len).toList(); 14 | result.add(temp); 15 | index++; 16 | } 17 | 18 | List temp = list.skip((index - 1) * len).toList(); 19 | result.add(temp); 20 | 21 | return result; 22 | } 23 | 24 | static Size getViewSize( 25 | Size screenSize, int totalListLength, int screenListLength) { 26 | if (totalListLength < 5) { 27 | if (screenListLength == 1) { 28 | return screenSize; 29 | } 30 | 31 | if (screenListLength == 2) { 32 | return Size(screenSize.width, screenSize.height / 2); 33 | } 34 | } 35 | 36 | return Size(screenSize.width / 2, screenSize.height / 2); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ios/upload/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | upload 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | NSExtension 24 | 25 | NSExtensionPointIdentifier 26 | com.apple.broadcast-services-upload 27 | NSExtensionPrincipalClass 28 | $(PRODUCT_MODULE_NAME).SampleHandler 29 | RPBroadcastProcessMode 30 | RPBroadcastProcessModeSampleBuffer 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /lib/TRTCCallingDemo/ui/base/ExtendButton.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class ExtendButton extends StatelessWidget { 5 | ExtendButton( 6 | {this.imgUrl = "", 7 | this.tips = "", 8 | this.onTap, 9 | this.imgHieght = 0, 10 | this.imgColor, 11 | Key? key}) 12 | : super(key: key); 13 | final String imgUrl; 14 | final double imgHieght; 15 | final Color? imgColor; 16 | final String tips; 17 | final GestureTapCallback? onTap; 18 | 19 | @override 20 | Widget build(BuildContext context) { 21 | return InkWell( 22 | onTap: () { 23 | this.onTap!(); 24 | }, 25 | child: Column( 26 | mainAxisAlignment: MainAxisAlignment.center, 27 | children: [ 28 | Image.asset( 29 | imgUrl, 30 | height: imgHieght > 0 ? this.imgHieght : 52.0, 31 | color: imgColor != null ? imgColor : null, 32 | ), 33 | Container( 34 | margin: EdgeInsets.only(top: 10), 35 | child: Text( 36 | tips, 37 | style: TextStyle(fontSize: 12, color: Colors.white), 38 | ), 39 | ), 40 | ], 41 | ), 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 本文档主要介绍如何快速集成实时音视频(TRTC)SDK,运行TRTC场景化Demo,实现双人音视频通话、语音沙龙、多人视频会议等。 2 | 3 | ## 目录结构 4 | 5 | ``` 6 | ├─ debug // 调试相关 7 | ├─ login // 登录相关 8 | ├─ TRTCCallingDemo // 音视频通话,展示双人音视频通话 9 | ├─ TRTCChatSalonDemo // 类clubHouse语音沙龙 10 | ├─ TRTCLiveRoomDemo // 视频互动直播 11 | ├─ TRTCMeetingDemo // 多人视频会议 12 | ``` 13 | 14 | ## 功能简介 15 | 16 | 在这个示例项目中包含了以下功能: 17 | 18 | - 双人音视频通话 19 | - 类clubHouse语音沙龙 20 | - 视频互动直播 21 | - 多人视频会议 22 | 23 | ## 快速接入 24 | 25 | #### 一对一视频通话 26 | [快速跑通Demo](https://cloud.tencent.com/document/product/647/56295) 27 | 28 | [TRTCCalling API](https://cloud.tencent.com/document/product/647/56296) 29 | 30 | #### 一对一音频通话 31 | [快速跑通Demo](https://cloud.tencent.com/document/product/647/56293) 32 | 33 | [TRTCCalling API](https://cloud.tencent.com/document/product/647/56292) 34 | 35 | #### 类clubHouse语音沙龙 36 | [快速跑通Demo](https://cloud.tencent.com/document/product/647/53582) 37 | 38 | [TRTCCalling API](https://cloud.tencent.com/document/product/647/53583) 39 | 40 | #### 视频互动直播 41 | [快速跑通Demo](https://cloud.tencent.com/document/product/647/57388) 42 | 43 | [TRTCLive API](https://cloud.tencent.com/document/product/647/57389) 44 | 45 | #### 多人视频会议 46 | [快速跑通Demo](https://tcloud-doc.isd.com/document/product/647/58405) 47 | 48 | [TRTCMeeting API](https://tcloud-doc.isd.com/document/product/647/58406) -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/services.dart'; 3 | import 'package:flutter_localizations/flutter_localizations.dart'; 4 | import './i10n/localization_intl.dart'; 5 | import './routes/routes.dart' as router; 6 | 7 | final GlobalKey navigatorKey = new GlobalKey(); 8 | void main() { 9 | FlutterError.onError = (FlutterErrorDetails details) { 10 | FlutterError.dumpErrorToConsole(details); 11 | }; 12 | WidgetsFlutterBinding.ensureInitialized(); 13 | SystemChrome.setPreferredOrientations( 14 | [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]).then((_) { 15 | runApp(MyApp()); 16 | }); 17 | } 18 | 19 | class MyApp extends StatefulWidget { 20 | @override 21 | _MyAppState createState() => _MyAppState(); 22 | } 23 | 24 | class _MyAppState extends State { 25 | @override 26 | Widget build(BuildContext context) { 27 | return MaterialApp( 28 | navigatorKey: navigatorKey, 29 | localizationsDelegates: [ 30 | GlobalMaterialLocalizations.delegate, 31 | GlobalWidgetsLocalizations.delegate, 32 | GlobalCupertinoLocalizations.delegate, 33 | AppLocalizationsDelegate.delegate 34 | ], 35 | supportedLocales: [ 36 | const Locale('en', 'US'), // English 37 | const Locale('zh', 'CN'), // 中文简体 38 | ], 39 | initialRoute: router.initialRoute, 40 | routes: router.routes, 41 | ); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | platform :ios, '9.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | 34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 35 | end 36 | 37 | post_install do |installer| 38 | installer.pods_project.targets.each do |target| 39 | flutter_additional_ios_build_settings(target) 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /lib/TRTCLiveRoomDemo/ui/base/LiveTextButton.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class LiveTextButton extends StatelessWidget { 5 | const LiveTextButton({ 6 | Key? key, 7 | required this.text, 8 | this.size, 9 | this.backgroundColor, 10 | required this.onPressed, 11 | this.radius, 12 | this.textStyle, 13 | }) : super(key: key); 14 | final String text; 15 | final Function onPressed; 16 | final Size? size; 17 | final double? radius; 18 | final Color? backgroundColor; 19 | final TextStyle? textStyle; 20 | @override 21 | Widget build(BuildContext context) { 22 | return ElevatedButton( 23 | style: ButtonStyle( 24 | shape: MaterialStateProperty.all(RoundedRectangleBorder( 25 | side: BorderSide.none, 26 | borderRadius: BorderRadius.all( 27 | Radius.circular(this.radius != null ? this.radius! : 20)), 28 | )), 29 | backgroundColor: MaterialStateProperty.all( 30 | this.backgroundColor != null 31 | ? this.backgroundColor! 32 | : Color(0xFF29CC85)), 33 | minimumSize: MaterialStateProperty.all( 34 | this.size != null ? this.size! : Size(76, 38))), 35 | child: Text( 36 | this.text, 37 | style: this.textStyle != null 38 | ? this.textStyle! 39 | : TextStyle(color: Colors.white, fontSize: 14), 40 | ), 41 | onPressed: () { 42 | this.onPressed(); 43 | }, 44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /lib/routes/routes.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:trtc_scenes_demo/TRTCCallingDemo/ui/base/CallingScenes.dart'; 3 | import 'package:trtc_scenes_demo/TRTCLiveRoomDemo/ui/list/LiveRoomList.dart'; 4 | import 'package:trtc_scenes_demo/TRTCLiveRoomDemo/ui/room/LiveRoomPage.dart'; 5 | import '../TRTCChatSalonDemo/ui/list/VoiceRoomList.dart'; 6 | import '../TRTCChatSalonDemo/ui/list/VoiceRoomCreate.dart'; 7 | import '../TRTCChatSalonDemo/ui/room/VoiceRoomPage.dart'; 8 | import '../index.dart'; 9 | import '../login/LoginPage.dart'; 10 | import '../TRTCChatSalonDemo/ui/base/UserEnum.dart'; 11 | import '../TRTCCallingDemo/ui/TRTCCallingContact.dart'; 12 | import '../TRTCCallingDemo/ui/VideoCall/TRTCCallingVideo.dart'; 13 | import '../TRTCMeetingDemo/ui/TRTCMeetingIndex.dart'; 14 | import '../TRTCMeetingDemo/ui/TRTCMeetingRoom.dart'; 15 | 16 | final String initialRoute = "/"; 17 | final Map routes = { 18 | "/": (context) => IndexPage(), 19 | "/index": (context) => IndexPage(), 20 | "/login": (context) => LoginPage(), 21 | "/chatSalon/list": (context) => VoiceRoomListPage(), 22 | "/chatSalon/roomCreate": (context) => VoiceRoomCreatePage(), 23 | "/chatSalon/roomAnchor": (context) => VoiceRoomPage(UserType.Anchor), 24 | "/chatSalon/roomAudience": (context) => VoiceRoomPage(UserType.Audience), 25 | "/calling/videoContact": (context) => 26 | TRTCCallingContact(CallingScenes.VideoOneVOne), 27 | "/calling/audioContact": (context) => 28 | TRTCCallingContact(CallingScenes.AudioOneVOne), 29 | "/calling/callingView": (context) => TRTCCallingVideo(), 30 | "/liveRoom/roomAudience": (context) => LiveRoomPage(isAdmin: false), 31 | "/liveRoom/roomAnchor": (context) => LiveRoomPage(isAdmin: true), 32 | "/liveRoom/list": (context) => LiveRoomListPage(), 33 | "/meeting/meetingIndex": (context) => TRTCMeetingIndex(), 34 | "/meeting/meetingRoom": (context) => TRTCMeetingRoom(), 35 | }; 36 | -------------------------------------------------------------------------------- /lib/base/YunApiHelper.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:trtc_scenes_demo/debug/GenerateTestUserSig.dart'; 3 | 4 | class YunApiHelper { 5 | static String _url = 6 | 'https://service-c2zjvuxa-1252463788.gz.apigw.tencentcs.com/release/forTest'; 7 | static Dio _dio = new Dio(); 8 | 9 | static Future createRoom(String roomId, 10 | {String roomType = "voiceRoom"}) async { 11 | Response resp = await _dio.get( 12 | _url, 13 | queryParameters: { 14 | "method": "createRoom", 15 | "appId": GenerateTestUserSig.sdkAppId, 16 | "type": roomType, 17 | "roomId": roomId 18 | }, 19 | ); 20 | var data = resp.data; 21 | return Future.value(data["errorCode"] == 0 ? true : false); 22 | } 23 | 24 | static Future destroyRoom(String roomId, 25 | {String roomType = "voiceRoom"}) async { 26 | Response resp = await _dio.get( 27 | _url, 28 | queryParameters: { 29 | "method": "destroyRoom", 30 | "appId": GenerateTestUserSig.sdkAppId, 31 | "type": roomType, 32 | "roomId": roomId 33 | }, 34 | ); 35 | var data = resp.data; 36 | return Future.value(data["errorCode"] == 0 ? true : false); 37 | } 38 | 39 | static Future> getRoomList( 40 | {String roomType = "voiceRoom"}) async { 41 | Response resp = await _dio.get( 42 | _url, 43 | queryParameters: { 44 | "method": "getRoomList", 45 | "appId": GenerateTestUserSig.sdkAppId, 46 | "type": roomType 47 | }, 48 | ); 49 | var data = resp.data; 50 | List roomIdls = []; 51 | if (data["errorCode"] == 0) { 52 | List resList = data["data"] as List; 53 | for (int i = 0; i < resList.length; i++) { 54 | dynamic item = resList[i]; 55 | roomIdls.add(item["roomId"]); 56 | } 57 | } 58 | return Future.value(roomIdls); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /lib/TRTCChatSalonDemo/ui/widget/AudienceItem.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class AudienceItem extends StatefulWidget { 5 | AudienceItem({ 6 | Key? key, 7 | this.userName = "", 8 | this.userImgUrl = "", 9 | }) : super(key: key); 10 | 11 | final String userName; 12 | final String userImgUrl; 13 | @override 14 | State createState() => _AudienceItemState(); 15 | } 16 | 17 | class _AudienceItemState extends State { 18 | @override 19 | Widget build(BuildContext context) { 20 | return Container( 21 | child: Stack( 22 | children: [ 23 | Row( 24 | mainAxisAlignment: MainAxisAlignment.center, 25 | children: [ 26 | ClipRRect( 27 | borderRadius: BorderRadius.circular(60), 28 | child: InkWell( 29 | onTap: () { 30 | // 31 | }, 32 | child: Image.network( 33 | widget.userImgUrl, 34 | height: 60, 35 | ), 36 | ), 37 | ), 38 | ], 39 | ), 40 | Positioned( 41 | right: 0, 42 | left: 0, 43 | bottom: 0, 44 | child: Row( 45 | mainAxisAlignment: MainAxisAlignment.center, 46 | children: [ 47 | Container( 48 | width: 60, 49 | padding: EdgeInsets.fromLTRB(0, 20, 0, 0), 50 | child: Text( 51 | widget.userName, 52 | overflow: TextOverflow.ellipsis, 53 | textAlign: TextAlign.center, 54 | style: TextStyle( 55 | color: Colors.white, 56 | fontSize: 14, 57 | ), 58 | ), 59 | ), 60 | ], 61 | ), 62 | ), 63 | ], 64 | ), 65 | ); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | compileSdkVersion 31 30 | 31 | sourceSets { 32 | main.java.srcDirs += 'src/main/kotlin' 33 | } 34 | 35 | lintOptions { 36 | disable 'InvalidPackage' 37 | checkReleaseBuilds false 38 | } 39 | 40 | defaultConfig { 41 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 42 | applicationId "com.example.trtc_scenes_demo" 43 | minSdkVersion 19 44 | targetSdkVersion 31 45 | versionCode flutterVersionCode.toInteger() 46 | versionName flutterVersionName 47 | } 48 | 49 | buildTypes { 50 | release { 51 | // TODO: Add your own signing config for the release build. 52 | // Signing with the debug keys for now, so `flutter run --release` works. 53 | signingConfig signingConfigs.debug 54 | } 55 | } 56 | } 57 | 58 | flutter { 59 | source '../..' 60 | } 61 | 62 | dependencies { 63 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 64 | } 65 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | trtc_scenes_demo 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | NSCameraUsageDescription 26 | 授权摄像头权限才能正常视频通话 27 | NSMicrophoneUsageDescription 28 | 授权麦克风权限才能正常语音通话 29 | NSPhotoLibraryUsageDescription 30 | App需要您的同意,才能访问相册 31 | UIBackgroundModes 32 | 33 | audio 34 | 35 | UIFileSharingEnabled 36 | YES 37 | UILaunchStoryboardName 38 | LaunchScreen 39 | UIMainStoryboardFile 40 | Main 41 | UISupportedInterfaceOrientations 42 | 43 | UIInterfaceOrientationPortrait 44 | UIInterfaceOrientationLandscapeLeft 45 | UIInterfaceOrientationLandscapeRight 46 | 47 | UISupportedInterfaceOrientations~ipad 48 | 49 | UIInterfaceOrientationPortrait 50 | UIInterfaceOrientationPortraitUpsideDown 51 | UIInterfaceOrientationLandscapeLeft 52 | UIInterfaceOrientationLandscapeRight 53 | 54 | UIViewControllerBasedStatusBarAppearance 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /lib/TRTCLiveRoomDemo/ui/base/FavoriteAnimation.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:flutter/material.dart'; 4 | 5 | class FavoriteAnimation extends StatefulWidget { 6 | const FavoriteAnimation({Key? key, this.isVisible = false}) : super(key: key); 7 | final bool isVisible; 8 | @override 9 | _FavoriteAnimationState createState() => _FavoriteAnimationState(); 10 | } 11 | 12 | class _FavoriteAnimationState extends State 13 | with TickerProviderStateMixin { 14 | late Animation animation; 15 | late AnimationController controller; 16 | @override 17 | void initState() { 18 | super.initState(); 19 | controller = 20 | AnimationController(duration: Duration(seconds: 2), vsync: this); 21 | animation = new Tween( 22 | begin: 1.0, 23 | end: 0.0, 24 | ).animate(controller); 25 | //controller.forward(); 26 | } 27 | 28 | @override 29 | void dispose() { 30 | controller.dispose(); 31 | super.dispose(); 32 | } 33 | 34 | @override 35 | void didUpdateWidget(FavoriteAnimation oldWidget) { 36 | super.didUpdateWidget(oldWidget); 37 | if (widget.isVisible) { 38 | controller.reset(); 39 | controller.forward(); 40 | } 41 | } 42 | 43 | @override 44 | Widget build(BuildContext context) { 45 | double currVal = animation.value; 46 | double bottom = 100; 47 | 48 | return AnimatedBuilder( 49 | animation: animation, 50 | builder: (BuildContext context, Widget? child) { 51 | return Positioned( 52 | right: (1.0 - animation.value) * 45 + 20, 53 | bottom: (1.0 - animation.value) * 180 + 70, 54 | child: Opacity( 55 | opacity: animation.value, 56 | child: Container( 57 | child: widget.isVisible 58 | ? Icon( 59 | Icons.favorite, 60 | size: 42, 61 | color: Colors.redAccent, 62 | ) 63 | : Container(), 64 | ), 65 | ), 66 | ); 67 | }); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /lib/TRTCChatSalonDemo/model/TRTCChatSalonDef.dart: -------------------------------------------------------------------------------- 1 | // 关键类定义 2 | 3 | class ActionCallback { 4 | /// 错误码 5 | int code; 6 | 7 | /// 信息描述 8 | String desc; 9 | 10 | ActionCallback({this.code = 0, this.desc = ''}); 11 | } 12 | 13 | class RoomInfo { 14 | /// 【字段含义】房间唯一标识 15 | int roomId; 16 | 17 | /// 【字段含义】房间名称 18 | String? roomName; 19 | 20 | /// 【字段含义】房间封面图 21 | String? coverUrl; 22 | 23 | /// 【字段含义】房主id 24 | String? ownerId; 25 | 26 | /// 【字段含义】房主昵称 27 | String? ownerName; 28 | 29 | /// 【字段含义】房间人数 30 | int? memberCount; 31 | 32 | RoomInfo( 33 | {required this.roomId, 34 | this.roomName, 35 | this.coverUrl, 36 | this.memberCount, 37 | this.ownerId, 38 | this.ownerName}); 39 | } 40 | 41 | class RoomInfoCallback { 42 | /// 错误码 43 | int code; 44 | 45 | /// 信息描述 46 | String desc; 47 | 48 | List? list; 49 | 50 | RoomInfoCallback({required this.code, required this.desc, this.list}); 51 | } 52 | 53 | class RoomParam { 54 | /// 房间名称 55 | String roomName; 56 | 57 | /// 房间封面图 58 | String? coverUrl; 59 | 60 | RoomParam({required this.roomName, this.coverUrl}); 61 | } 62 | 63 | class MemberListCallback { 64 | /// 错误码 65 | int code; 66 | 67 | /// 信息描述 68 | String desc; 69 | 70 | /// nextSeq 分页拉取标志,第一次拉取填0,回调成功如果 nextSeq 不为零,需要分页,传入再次拉取,直至为0。 71 | int nextSeq; 72 | 73 | List? list; 74 | 75 | MemberListCallback( 76 | {this.code = 0, this.desc = '', this.nextSeq = 0, this.list}); 77 | } 78 | 79 | class UserListCallback { 80 | /// 错误码 81 | int code; 82 | 83 | /// 信息描述 84 | String desc; 85 | 86 | /// 用户信息列表 87 | List? list; 88 | 89 | UserListCallback({this.code = 0, this.desc = '', this.list}); 90 | } 91 | 92 | class UserInfo { 93 | /// 用户唯一标识 94 | String? userId; 95 | 96 | /// 用户昵称 97 | String? userName; 98 | 99 | /// 用户头像 100 | String? userAvatar; 101 | 102 | /// 主播是否开麦 103 | bool? mute; 104 | 105 | UserInfo({this.userId, this.userName, this.userAvatar, this.mute}); 106 | } 107 | -------------------------------------------------------------------------------- /lib/TRTCCallingDemo/model/TRTCCallingDef.dart: -------------------------------------------------------------------------------- 1 | // 关键类定义 2 | 3 | class ActionCallback { 4 | /// 错误码 5 | int code; 6 | 7 | /// 信息描述 8 | String desc; 9 | 10 | ActionCallback({this.code = 0, this.desc = ''}); 11 | } 12 | 13 | class RoomInfo { 14 | /// 【字段含义】房间唯一标识 15 | int roomId; 16 | 17 | /// 【字段含义】房间名称 18 | String? roomName; 19 | 20 | /// 【字段含义】房间封面图 21 | String? coverUrl; 22 | 23 | /// 【字段含义】房主id 24 | String ownerId; 25 | 26 | /// 【字段含义】房主昵称 27 | String? ownerName; 28 | 29 | /// 【字段含义】房间人数 30 | int? memberCount; 31 | 32 | RoomInfo( 33 | {required this.roomId, 34 | this.roomName, 35 | this.coverUrl, 36 | this.memberCount, 37 | required this.ownerId, 38 | this.ownerName}); 39 | } 40 | 41 | class RoomInfoCallback { 42 | /// 错误码 43 | int code; 44 | 45 | /// 信息描述 46 | String desc; 47 | 48 | List? list; 49 | 50 | RoomInfoCallback({required this.code, required this.desc, this.list}); 51 | } 52 | 53 | class RoomParam { 54 | /// 房间名称 55 | String? roomName; 56 | 57 | /// 房间封面图 58 | String? coverUrl; 59 | 60 | RoomParam({this.roomName, this.coverUrl}); 61 | } 62 | 63 | class MemberListCallback { 64 | /// 错误码 65 | int code; 66 | 67 | /// 信息描述 68 | String desc; 69 | 70 | /// nextSeq 分页拉取标志,第一次拉取填0,回调成功如果 nextSeq 不为零,需要分页,传入再次拉取,直至为0。 71 | int nextSeq; 72 | 73 | List? list; 74 | 75 | MemberListCallback( 76 | {this.code = 0, this.desc = '', this.nextSeq = 0, this.list}); 77 | } 78 | 79 | class UserListCallback { 80 | /// 错误码 81 | int code; 82 | 83 | /// 信息描述 84 | String desc; 85 | 86 | /// 用户信息列表 87 | List? list; 88 | 89 | UserListCallback({this.code = 0, this.desc = '', this.list}); 90 | } 91 | 92 | class UserInfo { 93 | /// 用户唯一标识 94 | String userId; 95 | 96 | /// 用户昵称 97 | String userName; 98 | 99 | /// 用户头像 100 | String userAvatar; 101 | 102 | /// 主播是否开麦 103 | bool mute; 104 | 105 | UserInfo( 106 | {required this.userId, 107 | required this.userName, 108 | required this.userAvatar, 109 | required this.mute}); 110 | } 111 | -------------------------------------------------------------------------------- /lib/TRTCLiveRoomDemo/ui/base/LiveMessageList.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class MessageColor { 4 | const MessageColor(this.msg, this.color); 5 | final String msg; 6 | final Color? color; 7 | } 8 | 9 | class LiveMessageList extends StatefulWidget { 10 | const LiveMessageList({Key? key, this.messageList}) : super(key: key); 11 | 12 | final List>? messageList; 13 | @override 14 | _LiveMessageListState createState() => _LiveMessageListState(); 15 | } 16 | 17 | class _LiveMessageListState extends State { 18 | Widget getMessageList() { 19 | return Container(); 20 | } 21 | 22 | @override 23 | Widget build(BuildContext context) { 24 | return Positioned( 25 | left: 0, 26 | bottom: 120, 27 | //right: 200, 28 | width: 250, 29 | child: Container( 30 | height: 200, 31 | padding: EdgeInsets.only(left: 10, right: 10), 32 | child: ListView.separated( 33 | itemCount: widget.messageList!.length, 34 | separatorBuilder: (BuildContext context, int index) => Divider(), 35 | padding: EdgeInsets.only(top: 10, bottom: 0), 36 | itemBuilder: (context, index) { 37 | List msgColorList = widget.messageList![index]; 38 | // widget.messageList![index] 39 | List ls = msgColorList.map((msgObj) { 40 | return TextSpan( 41 | text: msgObj.msg, 42 | style: TextStyle( 43 | color: msgObj.color == null ? Colors.white : msgObj.color, 44 | ), 45 | ); 46 | }).toList(); 47 | return Container( 48 | decoration: new BoxDecoration( 49 | color: Color.fromRGBO(0, 0, 0, 0.2), 50 | borderRadius: BorderRadius.all(Radius.circular(16)), 51 | ), 52 | height: 32, 53 | padding: EdgeInsets.only(left: 10, right: 10), 54 | child: Align( 55 | alignment: Alignment.centerLeft, 56 | child: RichText( 57 | text: TextSpan( 58 | style: TextStyle( 59 | fontSize: 14, 60 | ), 61 | children: ls), 62 | ), 63 | ), 64 | ); 65 | }, 66 | ), 67 | ), 68 | ); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /ios/upload/SampleHandler.swift: -------------------------------------------------------------------------------- 1 | import ReplayKit 2 | import TXLiteAVSDK_ReplayKitExt 3 | 4 | 5 | let APPGROUP = "group.com.tencent.trtc.scenes.demo.ios" 6 | 7 | class SampleHandler: RPBroadcastSampleHandler, TXReplayKitExtDelegate { 8 | 9 | let recordScreenKey = Notification.Name.init("TRTCRecordScreenKey") 10 | 11 | override func broadcastStarted(withSetupInfo setupInfo: [String : NSObject]?) { 12 | // User has requested to start the broadcast. Setup info from the UI extension can be supplied but optional. 13 | TXReplayKitExt.sharedInstance().setup(withAppGroup: APPGROUP, delegate: self) 14 | } 15 | 16 | override func broadcastPaused() { 17 | // User has requested to pause the broadcast. Samples will stop being delivered. 18 | } 19 | 20 | override func broadcastResumed() { 21 | // User has requested to resume the broadcast. Samples delivery will resume. 22 | } 23 | 24 | override func broadcastFinished() { 25 | // User has requested to finish the broadcast. 26 | TXReplayKitExt.sharedInstance().broadcastFinished(); 27 | } 28 | 29 | func broadcastFinished(_ broadcast: TXReplayKitExt, reason: TXReplayKitExtReason) { 30 | var tip = "" 31 | switch reason { 32 | case TXReplayKitExtReason.requestedByMain: 33 | tip = "屏幕共享已结束" 34 | break 35 | case TXReplayKitExtReason.disconnected: 36 | tip = "应用断开" 37 | break 38 | case TXReplayKitExtReason.versionMismatch: 39 | tip = "集成错误(SDK 版本号不相符合)" 40 | break 41 | default: 42 | break 43 | } 44 | 45 | let error = NSError(domain: NSStringFromClass(self.classForCoder), code: 0, userInfo: [NSLocalizedFailureReasonErrorKey:tip]) 46 | finishBroadcastWithError(error) 47 | } 48 | 49 | override func processSampleBuffer(_ sampleBuffer: CMSampleBuffer, with sampleBufferType: RPSampleBufferType) { 50 | switch sampleBufferType { 51 | case RPSampleBufferType.video: 52 | // Handle video sample buffer 53 | TXReplayKitExt.sharedInstance() .sendVideoSampleBuffer(sampleBuffer) 54 | break 55 | case RPSampleBufferType.audioApp: 56 | // Handle audio sample buffer for app audio 57 | break 58 | case RPSampleBufferType.audioMic: 59 | // Handle audio sample buffer for mic audio 60 | break 61 | @unknown default: 62 | // Handle other sample buffer types 63 | fatalError("Unknown type of sample buffer") 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /lib/i10n/messages_all.dart: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT. This is code generated via package:intl/generate_localized.dart 2 | // This is a library that looks up messages for specific locales by 3 | // delegating to the appropriate library. 4 | 5 | // Ignore issues from commonly used lints in this file. 6 | // ignore_for_file:implementation_imports, file_names, unnecessary_new 7 | // ignore_for_file:unnecessary_brace_in_string_interps, directives_ordering 8 | // ignore_for_file:argument_type_not_assignable, invalid_assignment 9 | // ignore_for_file:prefer_single_quotes, prefer_generic_function_type_aliases 10 | // ignore_for_file:comment_references 11 | 12 | import 'dart:async'; 13 | 14 | import 'package:intl/intl.dart'; 15 | import 'package:intl/message_lookup_by_library.dart'; 16 | import 'package:intl/src/intl_helpers.dart'; 17 | 18 | import 'messages_en_US.dart' as messages_en_us; 19 | import 'messages_messages.dart' as messages_messages; 20 | import 'messages_zh_CN.dart' as messages_zh_cn; 21 | 22 | typedef Future LibraryLoader(); 23 | Map _deferredLibraries = { 24 | 'en_US': () => new Future.value(null), 25 | 'messages': () => new Future.value(null), 26 | 'zh_CN': () => new Future.value(null), 27 | }; 28 | 29 | MessageLookupByLibrary? _findExact(String localeName) { 30 | switch (localeName) { 31 | case 'en_US': 32 | return messages_en_us.messages; 33 | case 'messages': 34 | return messages_messages.messages; 35 | case 'zh_CN': 36 | return messages_zh_cn.messages; 37 | default: 38 | return null; 39 | } 40 | } 41 | 42 | /// User programs should call this before using [localeName] for messages. 43 | Future initializeMessages(String localeName) async { 44 | var availableLocale = Intl.verifiedLocale( 45 | localeName, (locale) => _deferredLibraries[locale] != null, 46 | onFailure: (_) => null); 47 | if (availableLocale == null) { 48 | return new Future.value(false); 49 | } 50 | var lib = _deferredLibraries[availableLocale]; 51 | await (lib == null ? new Future.value(false) : lib()); 52 | initializeInternalMessageLookup(() => new CompositeMessageLookup()); 53 | messageLookup.addLocale(availableLocale, _findGeneratedMessagesFor); 54 | return new Future.value(true); 55 | } 56 | 57 | bool _messagesExistFor(String locale) { 58 | try { 59 | return _findExact(locale) != null; 60 | } catch (e) { 61 | return false; 62 | } 63 | } 64 | 65 | MessageLookupByLibrary? _findGeneratedMessagesFor(String locale) { 66 | var actualLocale = 67 | Intl.verifiedLocale(locale, _messagesExistFor, onFailure: (_) => null); 68 | if (actualLocale == null) return null; 69 | return _findExact(actualLocale); 70 | } 71 | -------------------------------------------------------------------------------- /lib/TRTCLiveRoomDemo/model/TRTCLiveRoomDef.dart: -------------------------------------------------------------------------------- 1 | // 关键类型定义 2 | 3 | class ActionCallback { 4 | /// 错误码 5 | int code; 6 | 7 | /// 信息描述 8 | String desc; 9 | 10 | ActionCallback({this.code = 0, this.desc = ''}); 11 | } 12 | 13 | class TRTCLiveRoomConfig { 14 | /// 【字段含义】观众端使用CDN播放 15 | /// 【特殊说明】true: 默认进房使用CDN播放 false: 使用低延时播放 16 | bool useCDNFirst; 17 | 18 | TRTCLiveRoomConfig({required this.useCDNFirst}); 19 | } 20 | 21 | class IMAnchorInfo { 22 | String? userId; 23 | String? streamId; 24 | String? name; 25 | 26 | IMAnchorInfo({this.userId, this.streamId, this.name}); 27 | } 28 | 29 | class RoomInfo { 30 | /// 【字段含义】房间唯一标识 31 | int roomId; 32 | 33 | /// 【字段含义】房间名称 34 | String? roomName; 35 | 36 | /// 【字段含义】房间封面图 37 | String? coverUrl; 38 | 39 | /// 【字段含义】房主id 40 | String ownerId; 41 | 42 | /// 【字段含义】房主昵称 43 | String? ownerName; 44 | 45 | /// 【字段含义】房间人数 46 | int? memberCount; 47 | 48 | RoomInfo( 49 | {required this.roomId, 50 | this.roomName, 51 | this.coverUrl, 52 | this.memberCount, 53 | required this.ownerId, 54 | this.ownerName}); 55 | } 56 | 57 | class RoomInfoCallback { 58 | /// 错误码 59 | int code; 60 | 61 | /// 信息描述 62 | String desc; 63 | 64 | List? list; 65 | 66 | RoomInfoCallback({required this.code, required this.desc, this.list}); 67 | } 68 | 69 | class RoomParam { 70 | /// 房间名称 71 | String roomName; 72 | 73 | /// 房间封面图 74 | String? coverUrl; 75 | 76 | /// 音质 77 | int? quality; 78 | 79 | RoomParam({required this.roomName, this.coverUrl, this.quality}); 80 | } 81 | 82 | class MemberListCallback { 83 | /// 错误码 84 | int code; 85 | 86 | /// 信息描述 87 | String desc; 88 | 89 | /// nextSeq 分页拉取标志,第一次拉取填0,回调成功如果 nextSeq 不为零,需要分页,传入再次拉取,直至为0。 90 | int nextSeq; 91 | 92 | List? list; 93 | 94 | MemberListCallback( 95 | {this.code = 0, this.desc = '', this.nextSeq = 0, this.list}); 96 | } 97 | 98 | class UserListCallback { 99 | /// 错误码 100 | int code; 101 | 102 | /// 信息描述 103 | String desc; 104 | 105 | /// 用户信息列表 106 | List? list; 107 | 108 | /// nextSeq 分页拉取标志,第一次拉取填0,回调成功如果 nextSeq 不为零,需要分页,传入再次拉取,直至为0。 109 | int nextSeq; 110 | 111 | UserListCallback( 112 | {this.code = 0, this.desc = '', this.list, this.nextSeq = 0}); 113 | } 114 | 115 | class UserInfo { 116 | /// 用户唯一标识 117 | String userId; 118 | 119 | /// 用户昵称 120 | String? userName; 121 | 122 | /// 用户头像 123 | String? userAvatar; 124 | 125 | UserInfo({ 126 | required this.userId, 127 | this.userName, 128 | this.userAvatar, 129 | }); 130 | } 131 | -------------------------------------------------------------------------------- /lib/TRTCLiveRoomDemo/ui/base/PopUpMessageList.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:flutter/material.dart'; 4 | 5 | class PopUpMessageList extends StatefulWidget { 6 | const PopUpMessageList({Key? key, this.popupMessageList}) : super(key: key); 7 | final List? popupMessageList; 8 | @override 9 | _PopUpMessageListState createState() => _PopUpMessageListState(); 10 | } 11 | 12 | class _PopUpMessageListState extends State 13 | with SingleTickerProviderStateMixin { 14 | late Animation animation; 15 | late AnimationController controller; 16 | final _random = new Random(); 17 | 18 | static List colorList = [ 19 | Color(0xFF3074FD), 20 | Color(0xFFFCAF41), 21 | Color(0xFFFC6091), 22 | Color(0xFF3CCFA5), 23 | Color(0xFFFF8607), 24 | Color(0xFFF7AF97), 25 | Color(0xFF3074FD), 26 | Color(0xFFFCAF41), 27 | Color(0xFFFC6091), 28 | Color(0xFF3CCFA5), 29 | ]; 30 | 31 | @override 32 | void initState() { 33 | super.initState(); 34 | controller = 35 | AnimationController(duration: Duration(seconds: 10), vsync: this); 36 | animation = new Tween( 37 | begin: -50.0, 38 | end: 900.0, 39 | ).animate(controller); 40 | controller.repeat(reverse: false); 41 | } 42 | 43 | @override 44 | void dispose() { 45 | controller.dispose(); 46 | super.dispose(); 47 | } 48 | 49 | Widget getMessagePositioned(String message, int index) { 50 | int colorIndex = index % 10; 51 | if (colorIndex < 0) { 52 | colorIndex = 0; 53 | } 54 | return Positioned( 55 | right: animation.value - (50.0 * colorIndex), 56 | top: 0 + (20.0 * colorIndex), 57 | child: Text( 58 | message, 59 | style: TextStyle( 60 | color: colorList[colorIndex], 61 | fontSize: 16, 62 | fontWeight: FontWeight.bold, 63 | ), 64 | )); 65 | } 66 | 67 | @override 68 | Widget build(BuildContext context) { 69 | return AnimatedBuilder( 70 | animation: animation, 71 | builder: (BuildContext context, Widget? child) { 72 | return Positioned( 73 | left: 0, 74 | right: 0, 75 | top: 95, 76 | child: Container( 77 | height: 200, 78 | color: Colors.transparent, 79 | child: Stack( 80 | alignment: Alignment.topRight, 81 | children: widget.popupMessageList!.map((e) { 82 | return getMessagePositioned( 83 | e, widget.popupMessageList!.indexOf(e)); 84 | }).toList()), 85 | ), 86 | ); 87 | }); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /ios/TXLiteAVSDK_ReplayKitExt.framework/Headers/TXReplayKitExt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Module: TXReplayKitExt @ TXLiteAVSDK 3 | * 4 | * Function: 腾讯云 ReplayKit 录屏功能在Extension中的主要接口类 5 | * 6 | * Version: 9.2.10637 7 | */ 8 | 9 | /// @defgroup TXReplayKitExt_ios TXReplayKitExt 10 | /// 腾讯云 ReplayKit 录屏功能在Extension中的主要接口类 11 | /// @{ 12 | 13 | #import 14 | #import 15 | #import 16 | 17 | NS_ASSUME_NONNULL_BEGIN 18 | 19 | typedef NS_ENUM(NSUInteger, TXReplayKitExtReason) { 20 | /// 主进程请求结束 21 | TXReplayKitExtReasonRequestedByMain, 22 | /// 链接断开,主进程退出 23 | TXReplayKitExtReasonDisconnected, 24 | /// 版本号与主进程SDK不符 25 | TXReplayKitExtReasonVersionMismatch 26 | }; 27 | 28 | @protocol TXReplayKitExtDelegate; 29 | 30 | /// 屏幕分享主入口类 31 | API_AVAILABLE(ios(11.0)) 32 | @interface TXReplayKitExt : NSObject 33 | 34 | /// 获取单例 35 | + (instancetype)sharedInstance; 36 | 37 | /// 初始化方法 38 | /// 39 | /// 需要在 RPBroadcastSampleHandler 的实现类中的 broadcastStartedWithSetupInfo 方法中调用 40 | /// @param appGroup App group ID 41 | /// @param delegate 回调对象 42 | - (void)setupWithAppGroup:(NSString *)appGroup delegate:(id)delegate; 43 | 44 | /// 录屏暂停方法 45 | /// 46 | /// 通过系统控制中心停止录屏时,会回调 RPBroadcastSampleHandler.broadcastPaused,在 broadcastPaused 方法中调用 47 | - (void)broadcastPaused; 48 | 49 | /// 录屏恢复方法 50 | /// 51 | /// 通过系统控制中心停止录屏时,会回调 RPBroadcastSampleHandler.broadcastResumed,在 broadcastResumed 方法中调用 52 | - (void)broadcastResumed; 53 | 54 | /// 录屏完成方法 55 | /// 56 | /// 通过系统控制中心停止录屏时,会回调 RPBroadcastSampleHandler.broadcastFinished,在 broadcastFinished 方法中调用 57 | - (void)broadcastFinished; 58 | 59 | /// 媒体数据(音视频)发送方法 60 | /// 61 | /// 需要在 RPBroadcastSampleHandler 的实现类中的 processSampleBuffer: 方法中调用 62 | /// 63 | /// @param sampleBuffer 系统回调的视频或音频帧 64 | /// @param sampleBufferType 媒体输入类型 65 | /// @note 66 | /// - sampleBufferType 当前支持 RPSampleBufferTypeVideo 和 RPSampleBufferTypeAudioApp 类型的数据帧处理。 67 | /// - RPSampleBufferTypeAudioMic 不支持,请在主 app 处理麦克风采集数据 68 | - (void)sendSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType; 69 | 70 | /// 视频发送方法 71 | /// 已废弃,请使用 - (void)sendSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType; 代替 72 | /// 需要在 RPBroadcastSampleHandler 的实现类中的 processSampleBuffer: 方法中调用 73 | /// 74 | /// @param sampleBuffer 系统回调的视频帧 75 | - (void)sendVideoSampleBuffer:(CMSampleBufferRef)sampleBuffer __attribute__((deprecated("use sendSampleBuffer:withType instead"))); 76 | 77 | @end 78 | 79 | @protocol TXReplayKitExtDelegate 80 | 81 | /// 录屏完成回调 82 | /// 83 | /// @param broadcast 发出回调的实例 84 | /// @param reason 结束原因代码, 参见 TXReplayKitExtReason 85 | - (void)broadcastFinished:(TXReplayKitExt *)broadcast reason:(TXReplayKitExtReason)reason; 86 | 87 | @end 88 | 89 | NS_ASSUME_NONNULL_END 90 | /// @} -------------------------------------------------------------------------------- /lib/TRTCChatSalonDemo/model/TRTCChatSalonDelegate.dart: -------------------------------------------------------------------------------- 1 | /// TRTCChatSalonDelegate回调事件 2 | enum TRTCChatSalonDelegate { 3 | /// 错误回调,表示 SDK 不可恢复的错误,一定要监听并分情况给用户适当的界面提示 4 | /// 5 | /// 参数param: 6 | /// 7 | /// errCode 错误码 8 | /// 9 | /// errMsg 错误信息 10 | /// 11 | /// extraInfo 扩展信息字段,个别错误码可能会带额外的信息帮助定位问题 12 | onError, 13 | 14 | /// 警告回调,用于告知您一些非严重性问题,例如出现卡顿或者可恢复的解码失败。 15 | /// 16 | /// 参数param: 17 | /// 18 | /// warningCode 错误码 19 | /// 20 | /// warningMsg 警告信息 21 | /// 22 | /// extraInfo 扩展信息字段,个别警告码可能会带额外的信息帮助定位问题 23 | onWarning, 24 | 25 | ///本地进房 26 | /// 27 | /// 如果加入成功,result 会是一个正数(result > 0),代表加入房间的时间消耗,单位是毫秒(ms)。 28 | /// 29 | /// 如果加入失败,result 会是一个负数(result < 0),代表进房失败的错误码。 30 | /// 31 | /// 参数param: 32 | /// 33 | /// result > 0 时为进房耗时(ms),result < 0 时为进房错误码 34 | onEnterRoom, 35 | 36 | //离开房间的事件回调 37 | onExitRoom, 38 | 39 | /// 有观众举手,申请上麦 40 | /// 41 | /// 参数param: 42 | /// 43 | /// userId 申请举手的用户id 44 | onRaiseHand, 45 | 46 | /// 观众申请举手后,收到群主同意举手的回调 47 | onAgreeToSpeak, 48 | 49 | /// 观众申请举手后,群主拒绝举手的回调 50 | onRefuseToSpeak, 51 | 52 | /// 收到被群主踢下麦的回调 53 | onKickMic, 54 | 55 | /// 房间被销毁,当主播调用destroyRoom后,成员会收到该回调 56 | onRoomDestroy, 57 | 58 | /// 主播列表发生变化的通知 59 | /// 60 | /// 参数: 61 | /// 62 | /// userId:用户id 63 | /// 64 | /// mute:静音状态 65 | onAnchorListChange, 66 | 67 | /// 有成员上麦(主动申请上麦,群主同意) 68 | /// 69 | /// 参数: 70 | /// 71 | /// userId 上麦的用户id 72 | /// 73 | /// userName 用户昵称 74 | /// 75 | /// userAvatar 用户头像 76 | /// 77 | /// mute 麦位状态 78 | onAnchorEnterMic, 79 | 80 | /// 有成员下麦(主动下麦/主播踢人下麦) 81 | /// 82 | /// 参数: 83 | /// userId 下麦的用户id 84 | onAnchorLeaveMic, 85 | 86 | /// 主播是否禁麦 87 | /// 88 | /// 参数: 89 | /// userId 用户id 90 | /// mute 是否禁麦 91 | onMicMute, 92 | 93 | /// 观众进入房间 94 | /// 95 | /// 参数: 96 | /// 97 | /// userId:用户id 98 | /// 99 | /// userName:用户昵称 100 | /// 101 | /// userAvatar:用户头像地址 102 | onAudienceEnter, 103 | 104 | /// 观众离开房间 105 | /// 106 | /// 参数: 107 | /// 108 | /// userId: 用户id 109 | onAudienceExit, 110 | 111 | /// 用于提示音量大小的回调,包括每个 userId 的音量和远端总音量。 112 | /// 113 | /// 您可以通过调用 TRTCCloud 中的 enableAudioVolumeEvaluation 接口来开关这个回调或者设置它的触发间隔。 需要注意的是,调用 enableAudioVolumeEvaluation 开启音量回调后,无论频道内是否有人说话,都会按设置的时间间隔调用这个回调; 如果没有人说话,则 userVolumes 为空,totalVolume 为0。 114 | /// 115 | /// 注意:userId 为本地用户 ID 时表示自己的音量,userVolumes 内仅包含正在说话(音量不为0)的用户音量信息。 116 | /// 117 | /// 参数param: 118 | /// 119 | /// userVolumes 所有正在说话的房间成员的音量,取值范围0 - 100。 120 | /// 121 | /// totalVolume 所有远端成员的总音量, 取值范围0 - 100。 122 | onUserVolumeUpdate, 123 | 124 | /// 收到群文本消息,可以用作文本聊天室 125 | /// 126 | /// 参数: 127 | /// 128 | /// message:文本消息 129 | /// 130 | /// sendId:发送者id 131 | /// 132 | /// userAvatar:发送者头像 133 | /// 134 | /// userName:发送者用户昵称 135 | onRecvRoomTextMsg, 136 | 137 | //其他用户登录了同一账号,被踢下线 138 | onKickedOffline 139 | } 140 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Bugly (2.5.91) 3 | - Flutter (1.0.0) 4 | - flutter_bugly (0.0.1): 5 | - Bugly 6 | - Flutter 7 | - fluttertoast (0.0.2): 8 | - Flutter 9 | - Toast 10 | - HydraAsync (2.0.6) 11 | - "permission_handler (5.1.0+2)": 12 | - Flutter 13 | - replay_kit_launcher (0.3.0): 14 | - Flutter 15 | - shared_preferences (0.0.1): 16 | - Flutter 17 | - tencent_im_sdk_plugin (1.0.5): 18 | - Flutter 19 | - HydraAsync 20 | - TXIMSDK_Plus_iOS (= 5.8.1668) 21 | - tencent_trtc_cloud (0.0.7): 22 | - Flutter 23 | - TXLiteAVSDK_TRTC (= 9.5.11004) 24 | - Toast (4.0.0) 25 | - TXIMSDK_Plus_iOS (5.8.1668) 26 | - TXLiteAVSDK_TRTC (9.5.11004) 27 | - url_launcher (0.0.1): 28 | - Flutter 29 | 30 | DEPENDENCIES: 31 | - Flutter (from `Flutter`) 32 | - flutter_bugly (from `.symlinks/plugins/flutter_bugly/ios`) 33 | - fluttertoast (from `.symlinks/plugins/fluttertoast/ios`) 34 | - permission_handler (from `.symlinks/plugins/permission_handler/ios`) 35 | - replay_kit_launcher (from `.symlinks/plugins/replay_kit_launcher/ios`) 36 | - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) 37 | - tencent_im_sdk_plugin (from `.symlinks/plugins/tencent_im_sdk_plugin/ios`) 38 | - tencent_trtc_cloud (from `.symlinks/plugins/tencent_trtc_cloud/ios`) 39 | - url_launcher (from `.symlinks/plugins/url_launcher/ios`) 40 | 41 | SPEC REPOS: 42 | trunk: 43 | - Bugly 44 | - HydraAsync 45 | - Toast 46 | - TXIMSDK_Plus_iOS 47 | - TXLiteAVSDK_TRTC 48 | 49 | EXTERNAL SOURCES: 50 | Flutter: 51 | :path: Flutter 52 | flutter_bugly: 53 | :path: ".symlinks/plugins/flutter_bugly/ios" 54 | fluttertoast: 55 | :path: ".symlinks/plugins/fluttertoast/ios" 56 | permission_handler: 57 | :path: ".symlinks/plugins/permission_handler/ios" 58 | replay_kit_launcher: 59 | :path: ".symlinks/plugins/replay_kit_launcher/ios" 60 | shared_preferences: 61 | :path: ".symlinks/plugins/shared_preferences/ios" 62 | tencent_im_sdk_plugin: 63 | :path: ".symlinks/plugins/tencent_im_sdk_plugin/ios" 64 | tencent_trtc_cloud: 65 | :path: ".symlinks/plugins/tencent_trtc_cloud/ios" 66 | url_launcher: 67 | :path: ".symlinks/plugins/url_launcher/ios" 68 | 69 | SPEC CHECKSUMS: 70 | Bugly: afe841bba2ea6de6d432a3c125240a5e75949c55 71 | Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c 72 | flutter_bugly: c9800f4d5bc5bdc27ffdde3417a26ba44266e0c3 73 | fluttertoast: 6122fa75143e992b1d3470f61000f591a798cc58 74 | HydraAsync: 8d589bd725b0224f899afafc9a396327405f8063 75 | permission_handler: ccb20a9fad0ee9b1314a52b70b76b473c5f8dab0 76 | replay_kit_launcher: 9c6874fe17ce278a6f0e99e3698acf194480e9a2 77 | shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d 78 | tencent_im_sdk_plugin: b42d69c70d2b8dd8013e660bc6024c96de82cb05 79 | tencent_trtc_cloud: f522eb10ddd74baecc7a5e644478ff08dd018a07 80 | Toast: 91b396c56ee72a5790816f40d3a94dd357abc196 81 | TXIMSDK_Plus_iOS: e61e34c3dc6606549bff41b2abd7e2575af3813e 82 | TXLiteAVSDK_TRTC: 49d2f320fbb99c040a3d7287fe983cbbcc94f28b 83 | url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef 84 | 85 | PODFILE CHECKSUM: a75497545d4391e2d394c3668e20cfb1c2bbd4aa 86 | 87 | COCOAPODS: 1.10.1 88 | -------------------------------------------------------------------------------- /lib/debug/GenerateTestUserSig.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Module: GenerateTestUserSig 3 | * 4 | * Function: 用于生成测试用的 UserSig,UserSig 是腾讯云为其云服务设计的一种安全保护签名。 5 | * 其计算方法是对 SDKAppID、UserID 和 EXPIRETIME 进行加密,加密算法为 HMAC-SHA256。 6 | * 7 | * Attention: 请不要将如下代码发布到您的线上正式版本的 App 中,原因如下: 8 | * 9 | * 本文件中的代码虽然能够正确计算出 UserSig,但仅适合快速调通 SDK 的基本功能,不适合线上产品, 10 | * 这是因为客户端代码中的 SECRETKEY 很容易被反编译逆向破解,尤其是 Web 端的代码被破解的难度几乎为零。 11 | * 一旦您的密钥泄露,攻击者就可以计算出正确的 UserSig 来盗用您的腾讯云流量。 12 | * 13 | * 正确的做法是将 UserSig 的计算代码和加密密钥放在您的业务服务器上,然后由 App 按需向您的服务器获取实时算出的 UserSig。 14 | * 由于破解服务器的成本要高于破解客户端 App,所以服务器计算的方案能够更好地保护您的加密密钥。 15 | * 16 | * Reference:https://cloud.tencent.com/document/product/647/17275#Server 17 | */ 18 | import 'dart:convert'; 19 | import 'dart:io'; 20 | import 'package:crypto/crypto.dart'; 21 | 22 | class GenerateTestUserSig { 23 | /* 24 | * 腾讯云 SDKAppId,需要替换为您自己账号下的 SDKAppId。 25 | * 26 | * 进入腾讯云实时音视频[控制台](https://console.cloud.tencent.com/trtc ) 创建应用,即可看到 SDKAppId, 27 | * 它是腾讯云用于区分客户的唯一标识。 28 | */ 29 | static int sdkAppId = 0; 30 | 31 | /* 32 | * 签名过期时间,建议不要设置的过短 33 | *

34 | * 时间单位:秒 35 | * 默认时间:7 x 24 x 60 x 60 = 604800 = 7 天 36 | */ 37 | static int expireTime = 604800; 38 | 39 | /* 40 | * 计算签名用的加密密钥,获取步骤如下: 41 | * 42 | * step1. 进入腾讯云实时音视频[控制台](https://console.cloud.tencent.com/trtc ),如果还没有应用就创建一个, 43 | * step2. 单击“应用配置”进入基础配置页面,并进一步找到“帐号体系集成”部分。 44 | * step3. 点击“查看密钥”按钮,就可以看到计算 UserSig 使用的加密的密钥了,请将其拷贝并复制到如下的变量中 45 | * 46 | * 注意:该方案仅适用于调试Demo,正式上线前请将 UserSig 计算代码和密钥迁移到您的后台服务器上,以避免加密密钥泄露导致的流量盗用。 47 | * 文档:https://cloud.tencent.com/document/product/647/17275#Server 48 | */ 49 | static String secretKey = ''; 50 | 51 | ///生成UserSig 52 | static genTestSig(String userId) { 53 | int currTime = _getCurrentTime(); 54 | String sig = ''; 55 | Map sigDoc = new Map(); 56 | sigDoc.addAll({ 57 | "TLS.ver": "2.0", 58 | "TLS.identifier": userId, 59 | "TLS.sdkappid": sdkAppId, 60 | "TLS.expire": expireTime, 61 | "TLS.time": currTime, 62 | }); 63 | 64 | sig = _hmacsha256( 65 | identifier: userId, 66 | currTime: currTime, 67 | expire: expireTime, 68 | ); 69 | sigDoc['TLS.sig'] = sig; 70 | String jsonStr = json.encode(sigDoc); 71 | List compress = zlib.encode(utf8.encode(jsonStr)); 72 | return _escape(content: base64.encode(compress)); 73 | } 74 | 75 | static int _getCurrentTime() { 76 | return (new DateTime.now().millisecondsSinceEpoch / 1000).floor(); 77 | } 78 | 79 | static String _hmacsha256({ 80 | required String identifier, 81 | required int currTime, 82 | required int expire, 83 | }) { 84 | int sdkappid = sdkAppId; 85 | String contentToBeSigned = 86 | "TLS.identifier:$identifier\nTLS.sdkappid:$sdkappid\nTLS.time:$currTime\nTLS.expire:$expire\n"; 87 | Hmac hmacSha256 = new Hmac(sha256, utf8.encode(secretKey)); 88 | Digest hmacSha256Digest = 89 | hmacSha256.convert(utf8.encode(contentToBeSigned)); 90 | return base64.encode(hmacSha256Digest.bytes); 91 | } 92 | 93 | static String _escape({ 94 | required String content, 95 | }) { 96 | return content 97 | .replaceAll('\+', '*') 98 | .replaceAll('\/', '-') 99 | .replaceAll('=', '_'); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /lib/TRTCMeetingDemo/model/TRTCMeetingDelegate.dart: -------------------------------------------------------------------------------- 1 | /// TRTCMeetingDelegate回调事件 2 | enum TRTCMeetingDelegate { 3 | /// 错误回调,表示 SDK 不可恢复的错误,一定要监听,并分情况给用户适当的界面提示 4 | /// 5 | /// 参数param: 6 | /// 7 | /// errCode:错误码 8 | /// 9 | /// errMsg:错误信息 10 | /// 11 | /// extraInfo:扩展信息字段,个别错误码可能会带额外的信息帮助定位问题 12 | onError, 13 | 14 | /// 警告回调,用于告知您一些非严重性问题,例如出现卡顿或者可恢复的解码失败 15 | /// 16 | /// 参数param: 17 | /// 18 | /// warningCode:错误码 19 | /// 20 | /// warningMsg:警告信息 21 | /// 22 | /// extraInfo:扩展信息字段,个别警告码可能会带额外的信息帮助定位问题 23 | onWarning, 24 | 25 | /// 其他用户登录了同一账号,被踢下线 26 | onKickedOffline, 27 | 28 | /// 会议房间被销毁的回调。主持人退房时,房间内的所有用户都会收到此通知 29 | /// 30 | /// 参数param: 31 | /// 32 | /// roomId:会议房间ID 33 | onRoomDestroy, 34 | 35 | /// 网络状态回调 36 | /// 37 | /// 参数param: 38 | /// 39 | /// localQuality:上行网络质量 40 | /// 41 | /// remoteQuality:下行网络质量 42 | onNetworkQuality, 43 | 44 | /// 用户通话音量回调 45 | /// 46 | /// 参数param: 47 | /// 48 | /// userVolumes:所有正在说话的房间成员的音量,取值范围0 - 100 49 | /// 50 | /// totalVolume:所有远端成员的总音量, 取值范围0 - 100 51 | onUserVolumeUpdate, 52 | 53 | /// 本地进会回调 54 | /// 55 | /// 调用 TRTCCloud 中的 enterRoom() 接口执行进房操作后,会收到来自 SDK 的 onEnterRoom(result) 回调 56 | /// 57 | /// 如果加入成功,result 会是一个正数(result > 0),代表加入会议的时间消耗,单位是毫秒(ms) 58 | /// 59 | /// 如果加入失败,result 会是一个负数(result < 0),代表进会失败的错误码 60 | /// 61 | /// 参数param: 62 | /// 63 | /// result:大于0时为进会耗时(ms),小于0时为进会错误码 64 | onEnterRoom, 65 | 66 | /// 本地退会回调 67 | /// 68 | /// 调用 TRTCCloud 中的 exitRoom() 接口会执行退出房间的相关逻辑,例如释放音视频设备资源和编解码器资源等。 待资源释放完毕,SDK 会通过 onExitRoom() 回调通知到您 69 | /// 70 | /// 如果您要再次调用 enterRoom() 或者切换到其他的音视频 SDK,请等待 onExitRoom() 回调到来之后再执行相关操作。 否则可能会遇到音频设备被占用等各种异常问题 71 | /// 72 | /// 参数param: 73 | /// 74 | /// reason:离开会议原因,0:主动调用 leaveMeeting 退会;1:被服务器踢出当前会议;2:当前会议整个被解散 75 | onLeaveRoom, 76 | 77 | /// 新成员进会回调 78 | /// 79 | /// 参数param: 80 | /// 81 | /// userId:新进会成员的用户ID 82 | onUserEnterRoom, 83 | 84 | /// 成员退会回调 85 | /// 86 | /// 参数param: 87 | /// 88 | /// userId:退会成员的用户ID 89 | onUserLeaveRoom, 90 | 91 | /// 成员开启/关闭麦克风的回调 92 | /// 93 | /// 参数param: 94 | /// 95 | /// userId:用户ID 96 | /// 97 | /// available:true:用户打开麦克风;false:用户关闭麦克风 98 | onUserAudioAvailable, 99 | 100 | /// 成员开启/关闭摄像头的回调 101 | /// 102 | /// 参数param: 103 | /// 104 | /// userId:用户ID 105 | /// 106 | /// available:true:用户打开摄像头;false:用户关闭摄像头 107 | onUserVideoAvailable, 108 | 109 | /// 成员开启/关闭辅路画面(一般用于屏幕分享)的回调 110 | /// 111 | /// 参数param: 112 | /// 113 | /// userId:用户ID 114 | /// 115 | /// available:true:用户打开屏幕分享;false:用户关闭屏幕分享 116 | onUserSubStreamAvailable, 117 | 118 | /// 收到文本消息的回调 119 | /// 120 | /// 参数param: 121 | /// 122 | /// message:文本消息 123 | /// 124 | /// sendId:发送者用户Id 125 | /// 126 | /// userAvatar:发送者用户头像 127 | /// 128 | /// userName:发送者用户昵称 129 | onRecvRoomTextMsg, 130 | 131 | /// 收到自定义消息的回调 132 | /// 133 | /// 参数param: 134 | /// 135 | /// command:命令字,由开发者自定义,主要用于区分不同消息类型 136 | /// 137 | /// message:文本消息 138 | /// 139 | /// sendId:发送者用户Id 140 | /// 141 | /// userAvatar:发送者用户头像 142 | /// 143 | /// userName:发送者用户昵称 144 | onRecvRoomCustomMsg, 145 | 146 | /// 录屏开始回调 147 | onScreenCaptureStarted, 148 | 149 | /// 录屏暂停回调 150 | onScreenCapturePaused, 151 | 152 | /// 录屏恢复回调 153 | onScreenCaptureResumed, 154 | 155 | /// 录屏停止回调 156 | /// 157 | /// 参数param: 158 | /// 159 | /// reason:停止原因,0:用户主动停止;1:屏幕窗口关闭导致停止 160 | onScreenCaptureStoped, 161 | } 162 | -------------------------------------------------------------------------------- /lib/utils/TxUtils.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:fluttertoast/fluttertoast.dart'; 3 | import 'package:flutter_styled_toast/flutter_styled_toast.dart' as StyledToast; 4 | import 'package:shared_preferences/shared_preferences.dart'; 5 | import './constants.dart' as constants; 6 | import 'dart:math'; 7 | 8 | class TxUtils { 9 | static String _loginUserId = ''; 10 | static() { 11 | if (_loginUserId == '') { 12 | getStorageByKey(constants.USERID_KEY).then((value) { 13 | _loginUserId = value; 14 | }); 15 | } 16 | } 17 | 18 | static showErrorToast(text, context) { 19 | Fluttertoast.showToast( 20 | msg: text, 21 | toastLength: Toast.LENGTH_SHORT, 22 | gravity: ToastGravity.BOTTOM, 23 | timeInSecForIosWeb: 3, 24 | backgroundColor: Colors.grey, 25 | textColor: Colors.white, 26 | fontSize: 16.0, 27 | ); 28 | } 29 | 30 | static getRandomNumber() { 31 | Random rng = new Random(); 32 | //2147483647 33 | String numStr = ''; 34 | for (var i = 0; i < 9; i++) { 35 | numStr += rng.nextInt(9).toString(); 36 | } 37 | return int.tryParse(numStr); 38 | } 39 | 40 | static List _defaltUrlList = [ 41 | 'https://imgcache.qq.com/operation/dianshi/other/7.157d962fa53be4107d6258af6e6d83f33d45fba4.png', 42 | 'https://imgcache.qq.com/operation/dianshi/other/5.ca48acfebc4dfb68c6c463c9f33e60cb8d7c9565.png', 43 | 'https://imgcache.qq.com/operation/dianshi/other/1.724142271f4e811457eee00763e63f454af52d13.png', 44 | 'https://imgcache.qq.com/operation/dianshi/other/4.67f22bd6d283d942d06e69c6b8a2c819c0e11af5.png', 45 | 'https://imgcache.qq.com/operation/dianshi/other/6.1b984e741cc2275cda3451fa44515e018cc49cb5.png', 46 | //先不用这种图片,或者和白色字体不搭配 47 | //'https://imgcache.qq.com/operation/dianshi/other/2.4c958e11852b2caa75da6c2726f9248108d6ec8a.png', 48 | ]; 49 | static getRandoAvatarUrl() { 50 | Random rng = new Random(); 51 | return _defaltUrlList[rng.nextInt(_defaltUrlList.length)]; 52 | } 53 | 54 | static getDefaltAvatarUrl() { 55 | return _defaltUrlList[0]; 56 | } 57 | 58 | static showToast(String text, context) { 59 | Fluttertoast.cancel(); 60 | Fluttertoast.showToast( 61 | msg: text, 62 | toastLength: Toast.LENGTH_SHORT, 63 | gravity: ToastGravity.BOTTOM, 64 | timeInSecForIosWeb: 3, 65 | backgroundColor: Color.fromRGBO(192, 192, 192, 0.3), 66 | textColor: Colors.black, 67 | fontSize: 16.0, 68 | ); 69 | } 70 | 71 | static showStyledToast(String text, BuildContext context) { 72 | StyledToast.showToast( 73 | text, 74 | context: context, 75 | position: StyledToast.StyledToastPosition.center, 76 | ); 77 | } 78 | 79 | static setStorageByKey(key, value) async { 80 | if (key == constants.USERID_KEY) { 81 | _loginUserId = value; 82 | } 83 | SharedPreferences sharedPreferences = await SharedPreferences.getInstance(); 84 | sharedPreferences.setString(key, value); 85 | } 86 | 87 | static Future getStorageByKey(key) async { 88 | SharedPreferences sharedPreferences = await SharedPreferences.getInstance(); 89 | String? rStr = sharedPreferences.getString(key); 90 | return rStr == null ? Future.value('') : Future.value(rStr); 91 | } 92 | 93 | static Future getLoginUserId() { 94 | if (_loginUserId == '') { 95 | return getStorageByKey(constants.USERID_KEY); 96 | } 97 | return Future.value(_loginUserId); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 29 | 33 | 37 | 42 | 46 | 47 | 48 | 49 | 50 | 51 | 54 | 56 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /lib/TRTCChatSalonDemo/ui/widget/RoomTopMsg.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class RoomTopMessage extends StatefulWidget { 5 | RoomTopMessage({ 6 | Key? key, 7 | this.message = '', 8 | this.visible = false, 9 | this.isShowBtn = false, 10 | this.okTitle, 11 | this.cancelTitle, 12 | this.onOkTab, 13 | this.onCancelTab, 14 | }) : super(key: key); 15 | final String message; 16 | final bool visible; 17 | final String? okTitle; 18 | final String? cancelTitle; 19 | final Function? onOkTab; 20 | final Function? onCancelTab; 21 | final bool isShowBtn; 22 | @override 23 | State createState() => _RoomTopMessageState(); 24 | } 25 | 26 | class _RoomTopMessageState extends State { 27 | Widget buildBtnList(BuildContext context) { 28 | return widget.isShowBtn 29 | ? Row( 30 | mainAxisAlignment: MainAxisAlignment.center, 31 | children: [ 32 | Container( 33 | margin: EdgeInsets.fromLTRB(0, 0, 30, 10), 34 | height: 36, 35 | // ignore: deprecated_member_use 36 | child: FlatButton( 37 | color: Color.fromRGBO(15, 169, 104, 1.0), 38 | child: Text( 39 | widget.okTitle!, 40 | style: TextStyle(color: Colors.white), 41 | ), 42 | onPressed: () { 43 | widget.onOkTab!(); 44 | }, 45 | ), 46 | ), 47 | Container( 48 | decoration: BoxDecoration( 49 | border: Border.all( 50 | color: Color.fromRGBO(235, 244, 255, 1.0), 51 | width: 1, 52 | ), //边框 53 | borderRadius: BorderRadius.all( 54 | Radius.circular(3.0), 55 | ), 56 | ), 57 | margin: EdgeInsets.fromLTRB(30, 0, 0, 10), 58 | height: 36, 59 | child: FlatButton( 60 | child: Text( 61 | widget.cancelTitle!, 62 | style: TextStyle(color: Colors.white), 63 | ), 64 | onPressed: () { 65 | widget.onCancelTab!(); 66 | }, 67 | ), 68 | ), 69 | ], 70 | ) 71 | : Container( 72 | height: 0, 73 | ); 74 | } 75 | 76 | @override 77 | Widget build(BuildContext context) { 78 | return Container( 79 | width: widget.visible ? MediaQuery.of(context).size.width : 0, 80 | color: Color.fromRGBO(0, 98, 227, 1.0), 81 | child: Column( 82 | children: [ 83 | Row( 84 | children: [ 85 | Container( 86 | height: widget.visible ? 38 : 0, 87 | constraints: BoxConstraints( 88 | maxWidth: MediaQuery.of(context).size.width - 10), 89 | padding: EdgeInsets.fromLTRB(20, 10, 0, 10), 90 | child: Text( 91 | widget.message, 92 | overflow: TextOverflow.ellipsis, 93 | style: TextStyle( 94 | fontSize: 14, 95 | color: Colors.white, 96 | ), 97 | ), 98 | ), 99 | ], 100 | ), 101 | buildBtnList(context), 102 | ], 103 | ), 104 | ); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: trtc_scenes_demo 2 | description: Trtc场景化demo for Flutter. 3 | 4 | # The following line prevents the package from being accidentally published to 5 | # pub.dev using `pub publish`. This is preferred for private packages. 6 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 7 | 8 | # The following defines the version and build number for your application. 9 | # A version number is three numbers separated by dots, like 1.2.43 10 | # followed by an optional build number separated by a +. 11 | # Both the version and the builder number may be overridden in flutter 12 | # build by specifying --build-name and --build-number, respectively. 13 | # In Android, build-name is used as versionName while build-number used as versionCode. 14 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 15 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 16 | # Read more about iOS versioning at 17 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 18 | version: 1.0.0+1 19 | 20 | environment: 21 | sdk: '>=2.12.0 <3.0.0' 22 | 23 | dependencies: 24 | tencent_trtc_cloud: 2.2.4 25 | tencent_im_sdk_plugin: 3.9.0 26 | shared_preferences: ^2.0.5 27 | provider: ^5.0.0 28 | crypto: ^3.0.1 29 | dio: ^4.0.0 30 | badges: ^2.0.1 31 | permission_handler: ^7.1.0 32 | fluttertoast: ^8.0.6 33 | url_launcher: ^6.0.3 34 | flutter_easyrefresh: ^2.1.8 35 | replay_kit_launcher: ^0.3.0 36 | flutter_styled_toast: 2.0.0 37 | # intl: ^0.16.1 38 | flutter: 39 | sdk: flutter 40 | flutter_localizations: 41 | sdk: flutter 42 | 43 | # dependency_overrides: 44 | # intl: any 45 | 46 | # The following adds the Cupertino Icons font to your application. 47 | # Use with the CupertinoIcons class for iOS style icons. 48 | # cupertino_icons: ^1.0.1 49 | 50 | dev_dependencies: 51 | # intl_translation: any 52 | 53 | # For information on the generic Dart part of this file, see the 54 | # following page: https://dart.dev/tools/pub/pubspec 55 | 56 | # The following section is specific to Flutter. 57 | flutter: 58 | 59 | # The following line ensures that the Material Icons font is 60 | # included with your application, so that you can use the icons in 61 | # the material Icons class. 62 | uses-material-design: true 63 | 64 | # To add assets to your application, add an assets section, like this: 65 | assets: 66 | - assets/images/ 67 | - assets/images/callingDemo/ 68 | - assets/images/liveRoom/ 69 | - assets/images/liveRoom/music/ 70 | 71 | 72 | # An image asset can refer to one or more resolution-specific "variants", see 73 | # https://flutter.dev/assets-and-images/#resolution-aware. 74 | 75 | # For details regarding adding assets from package dependencies, see 76 | # https://flutter.dev/assets-and-images/#from-packages 77 | 78 | # To add custom fonts to your application, add a fonts section here, 79 | # in this "flutter" section. Each entry in this list should have a 80 | # "family" key with the font family name, and a "fonts" key with a 81 | # list giving the asset and other descriptors for the font. For 82 | # example: 83 | # fonts: 84 | # - family: Schyler 85 | # fonts: 86 | # - asset: fonts/Schyler-Regular.ttf 87 | # - asset: fonts/Schyler-Italic.ttf 88 | # style: italic 89 | # - family: Trajan Pro 90 | # fonts: 91 | # - asset: fonts/TrajanPro.ttf 92 | # - asset: fonts/TrajanPro_Bold.ttf 93 | # weight: 700 94 | # 95 | # For details regarding fonts from package dependencies, 96 | # see https://flutter.dev/custom-fonts/#from-packages 97 | -------------------------------------------------------------------------------- /lib/TRTCLiveRoomDemo/ui/base/PKUserList.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:trtc_scenes_demo/TRTCLiveRoomDemo/model/TRTCLiveRoomDef.dart'; 4 | import 'package:trtc_scenes_demo/utils/TxUtils.dart'; 5 | 6 | import 'LiveTextButton.dart'; 7 | 8 | class PKUserList extends StatefulWidget { 9 | const PKUserList({Key? key, this.roomList, required this.onRequestRoomPK}) 10 | : super(key: key); 11 | final List? roomList; 12 | final Function(int roomId, String userId) onRequestRoomPK; 13 | @override 14 | _PKUserListState createState() => _PKUserListState(); 15 | } 16 | 17 | class _PKUserListState extends State { 18 | @override 19 | Widget build(BuildContext context) { 20 | return Container( 21 | color: Colors.white, 22 | child: CustomScrollView( 23 | slivers: [ 24 | SliverAppBar( 25 | leading: Text(''), 26 | pinned: true, 27 | backgroundColor: Colors.white, 28 | title: Text( 29 | "PK列表", 30 | style: TextStyle(color: Colors.black), 31 | ), 32 | ), 33 | SliverFixedExtentList( 34 | itemExtent: 75.0, 35 | delegate: SliverChildBuilderDelegate( 36 | (BuildContext context, int index) { 37 | //创建列表项 38 | RoomInfo roomInfo = widget.roomList![index]; 39 | return Container( 40 | alignment: Alignment.centerLeft, 41 | child: Row( 42 | crossAxisAlignment: CrossAxisAlignment.center, 43 | children: [ 44 | Expanded( 45 | flex: 0, 46 | child: Padding( 47 | padding: EdgeInsets.fromLTRB(20, 0, 0, 0), 48 | child: ClipRRect( 49 | borderRadius: BorderRadius.circular(44), 50 | child: Image.network( 51 | TxUtils.getRandoAvatarUrl(), 52 | height: 44, 53 | fit: BoxFit.fitHeight, 54 | ), 55 | )), 56 | ), 57 | Expanded( 58 | flex: 1, 59 | child: Padding( 60 | padding: EdgeInsets.fromLTRB(20, 0, 0, 0), 61 | child: Text( 62 | // ignore: unrelated_type_equality_checks 63 | roomInfo.roomName != Null 64 | ? roomInfo.roomName! 65 | : '--', 66 | style: TextStyle( 67 | color: Colors.black, 68 | fontSize: 16, 69 | ), 70 | ), 71 | ), 72 | ), 73 | Expanded( 74 | flex: 0, 75 | child: Padding( 76 | padding: EdgeInsets.only(right: 15), 77 | child: LiveTextButton( 78 | onPressed: () { 79 | widget.onRequestRoomPK( 80 | roomInfo.roomId, roomInfo.ownerId); 81 | }, 82 | text: "邀请", 83 | ), 84 | ), 85 | ), 86 | ], 87 | ), 88 | ); 89 | }, 90 | childCount: widget.roomList!.length, 91 | ), 92 | ), 93 | ], 94 | ), 95 | ); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /lib/TRTCCallingDemo/model/TRTCCallingDelegate.dart: -------------------------------------------------------------------------------- 1 | /// TRTCCallingDelegate回调事件 2 | enum TRTCCallingDelegate { 3 | /// 错误回调,表示 SDK 不可恢复的错误,一定要监听并分情况给用户适当的界面提示 4 | /// 5 | /// 参数param: 6 | /// 7 | /// errCode 错误码 8 | /// 9 | /// errMsg 错误信息 10 | /// 11 | /// extraInfo 扩展信息字段,个别错误码可能会带额外的信息帮助定位问题 12 | onError, 13 | 14 | /// 警告回调,用于告知您一些非严重性问题,例如出现卡顿或者可恢复的解码失败。 15 | /// 16 | /// 参数param: 17 | /// 18 | /// warningCode 错误码 19 | /// 20 | /// warningMsg 警告信息 21 | /// 22 | /// extraInfo 扩展信息字段,个别警告码可能会带额外的信息帮助定位问题 23 | onWarning, 24 | 25 | ///本地进房 26 | /// 27 | /// 如果加入成功,result 会是一个正数(result > 0),代表加入房间的时间消耗,单位是毫秒(ms)。 28 | /// 29 | /// 如果加入失败,result 会是一个负数(result < 0),代表进房失败的错误码。 30 | /// 31 | /// 参数param: 32 | /// 33 | /// result > 0 时为进房耗时(ms),result < 0 时为进房错误码 34 | onEnterRoom, 35 | 36 | /// 有用户加入当前房间。 37 | /// 38 | /// 参数param: 39 | /// 40 | /// userId 用户标识 41 | onUserEnter, 42 | 43 | /// 有用户离开当前房间。 44 | /// 45 | /// 参数param: 46 | /// 47 | /// userId 用户标识 48 | /// 49 | /// reason 离开原因,0表示用户主动退出房间,1表示用户超时退出,2表示被踢出房间。 50 | onUserLeave, 51 | 52 | /* 53 | * 正在IM群组通话时,如果其他与会者邀请他人,会收到此回调 54 | * 例如 A-B-C 正在IM群组中,A邀请[D、E]进入通话,B、C会收到[D、E]的回调 55 | * 如果此时 A 再邀请 F 进入群聊,那么B、C会收到[D、E、F]的回调 56 | * @param userIdList 邀请群组 57 | */ 58 | onGroupCallInviteeListUpdate, 59 | 60 | /* 61 | * 被邀请通话回调 62 | * @param sponsor 邀请者 63 | * @param userIdList 同时还被邀请的人 64 | * @param isFromGroup 是否IM群组邀请 65 | * @param callType 邀请类型 1-语音通话,2-视频通话 66 | */ 67 | onInvited, 68 | 69 | /* 70 | * 1. 在C2C通话中,只有发起方会收到拒绝回调 71 | * 例如 A 邀请 B、C 进入通话,B拒绝,A可以收到该回调,但C不行 72 | * 73 | * 2. 在IM群组通话中,所有被邀请人均能收到该回调 74 | * 例如 A 邀请 B、C 进入通话,B拒绝,A、C均能收到该回调 75 | * @param userId 拒绝通话的用户 76 | */ 77 | onReject, 78 | 79 | /* 80 | * 1. 在C2C通话中,只有发起方会收到无人应答的回调 81 | * 例如 A 邀请 B、C 进入通话,B不应答,A可以收到该回调,但C不行 82 | * 83 | * 2. 在IM群组通话中,所有被邀请人均能收到该回调 84 | * 例如 A 邀请 B、C 进入通话,B不应答,A、C均能收到该回调 85 | * @param userId 86 | */ 87 | onNoResp, 88 | 89 | /* 90 | * 邀请方忙线 91 | * @param userId 忙线用户 92 | */ 93 | onLineBusy, 94 | 95 | /* 96 | * 作为被邀请方会收到,收到该回调说明本次通话被取消了 97 | */ 98 | onCallingCancel, 99 | 100 | /* 101 | * 作为被邀请方会收到,收到该回调说明本次通话超时未应答 102 | */ 103 | onCallingTimeout, 104 | 105 | /* 106 | * 收到该回调说明本次通话结束了 107 | */ 108 | onCallEnd, 109 | 110 | /// 远端用户是否存在可播放的主路画面(一般用于摄像头) 111 | /// 112 | /// 当您收到 onUserVideoAvailable(userId, true) 通知时,表示该路画面已经有可用的视频数据帧到达。 此时,您需要调用 startRemoteView(userid) 接口加载该用户的远程画面。 然后,您会收到名为 onFirstVideoFrame(userid) 的首帧画面渲染回调。 113 | /// 114 | /// 当您收到 onUserVideoAvailable(userId, false) 通知时,表示该路远程画面已经被关闭,可能由于该用户调用了 muteLocalVideo() 或 stopLocalPreview()。 115 | /// 116 | /// 参数param: 117 | /// 118 | /// userId 用户标识 119 | /// 120 | /// available 画面是否开启 121 | onUserVideoAvailable, 122 | 123 | /// 远端用户是否存在可播放的主路画面(一般用于摄像头) 124 | /// 125 | /// 当您收到 onUserVideoAvailable(userId, true) 通知时,表示该路画面已经有可用的视频数据帧到达。 此时,您需要调用 startRemoteView(userid) 接口加载该用户的远程画面。 然后,您会收到名为 onFirstVideoFrame(userid) 的首帧画面渲染回调。 126 | /// 127 | /// 当您收到 onUserVideoAvailable(userId, false) 通知时,表示该路远程画面已经被关闭,可能由于该用户调用了 muteLocalVideo() 或 stopLocalPreview()。 128 | /// 129 | /// 参数param: 130 | /// 131 | /// userId 用户标识 132 | /// 133 | /// available 画面是否开启 134 | onUserAudioAvailable, 135 | 136 | /// 用于提示音量大小的回调,包括每个 userId 的音量和远端总音量。 137 | /// 138 | /// 您可以通过调用 TRTCCloud 中的 enableAudioVolumeEvaluation 接口来开关这个回调或者设置它的触发间隔。 需要注意的是,调用 enableAudioVolumeEvaluation 开启音量回调后,无论频道内是否有人说话,都会按设置的时间间隔调用这个回调; 如果没有人说话,则 userVolumes 为空,totalVolume 为0。 139 | /// 140 | /// 注意:userId 为本地用户 ID 时表示自己的音量,userVolumes 内仅包含正在说话(音量不为0)的用户音量信息。 141 | /// 142 | /// 参数param: 143 | /// 144 | /// userVolumes 所有正在说话的房间成员的音量,取值范围0 - 100。 145 | /// 146 | /// totalVolume 所有远端成员的总音量, 取值范围0 - 100。 147 | onUserVoiceVolume, 148 | 149 | //其他用户登录了同一账号,被踢下线 150 | onKickedOffline 151 | } 152 | -------------------------------------------------------------------------------- /lib/TRTCLiveRoomDemo/model/TRTCLiveRoomDelegate.dart: -------------------------------------------------------------------------------- 1 | /// TRTCLiveRoomDelegate回调事件 2 | enum TRTCLiveRoomDelegate { 3 | /// 错误回调,表示 SDK 不可恢复的错误,一定要监听并分情况给用户适当的界面提示 4 | /// 5 | /// 参数param: 6 | /// 7 | /// errCode 错误码 8 | /// 9 | /// errMsg 错误信息 10 | /// 11 | /// extraInfo 扩展信息字段,个别错误码可能会带额外的信息帮助定位问题 12 | onError, 13 | 14 | /// 警告回调,用于告知您一些非严重性问题,例如出现卡顿或者可恢复的解码失败。 15 | /// 16 | /// 参数param: 17 | /// 18 | /// warningCode 错误码 19 | /// 20 | /// warningMsg 警告信息 21 | /// 22 | /// extraInfo 扩展信息字段,个别警告码可能会带额外的信息帮助定位问题 23 | onWarning, 24 | 25 | ///本地进房 26 | /// 27 | /// 如果加入成功,result 会是一个正数(result > 0),代表加入房间的时间消耗,单位是毫秒(ms)。 28 | /// 29 | /// 如果加入失败,result 会是一个负数(result < 0),代表进房失败的错误码。 30 | /// 31 | /// 参数param: 32 | /// 33 | /// result > 0 时为进房耗时(ms),result < 0 时为进房错误码 34 | onEnterRoom, 35 | 36 | /// 远端用户是否存在可播放的主路画面(一般用于摄像头) 37 | /// 38 | /// 参数param: 39 | /// 40 | /// userId:用户标识 41 | /// 42 | /// available:画面是否开启 43 | onUserVideoAvailable, 44 | 45 | /// 收到新主播进房通知。连麦观众和跨房 PK 主播进房后观众会收到新主播的进房事件,您可以调用 TRTCLiveRoom 的 startPlay() 显示该主播的视频画面。 46 | /// 47 | /// 参数param: 48 | /// 49 | /// userId 进房用户ID 50 | onAnchorEnter, 51 | 52 | /// 收到主播退房通知。房间内的主播(和连麦中的观众)会收到新主播的退房事件,您可以调用 TRTCLiveRoom 的 stopPlay() 关闭该主播的视频画面。 53 | /// 参数param: 54 | /// userId 退房用户ID 55 | onAnchorExit, 56 | 57 | /// 主播收到观众连麦请求时的回调。 58 | /// 59 | /// 参数param: 60 | /// 61 | /// userId:请求连麦的观众用户id 62 | /// userName:用户昵称 63 | /// userAvatar:用户头像 64 | onRequestJoinAnchor, 65 | 66 | /// 连麦观众收到被踢出连麦的通知。连麦观众收到被主播踢除连麦的消息,您需要调用 TRTCLiveRoom 的 stopPublish() 退出连麦。 67 | /// 68 | /// 参数param: 69 | /// 70 | /// userId:主播的用户id 71 | /// userName:用户昵称 72 | /// userAvatar:用户头像 73 | onKickoutJoinAnchor, 74 | 75 | /// 主播同意观众的连麦请求 76 | /// 77 | /// 参数param: 78 | /// 79 | /// userId:主播的用户id 80 | onAnchorAccepted, 81 | 82 | // 主播拒绝观众的连麦请求 83 | /// 84 | /// 参数param: 85 | /// 86 | /// userId:主播的用户id 87 | onAnchorRejected, 88 | 89 | // 邀请超时,未响应 90 | onInvitationTimeout, 91 | 92 | ///收到请求跨房 PK 通知 93 | /// 94 | /// 参数param: 95 | /// 96 | /// userId:请求跨房PK主播的用户id 97 | /// userName:用户昵称 98 | /// userAvatar:用户头像 99 | onRequestRoomPK, 100 | 101 | ///主播接受跨房Pk请求 102 | /// 103 | /// 参数param: 104 | /// 105 | /// userId:接收跨房PK的用户id 106 | onRoomPKAccepted, 107 | 108 | ///主播拒绝跨房Pk请求 109 | /// 110 | /// 参数param: 111 | /// 112 | /// userId:拒绝跨房PK的用户id 113 | onRoomPKRejected, 114 | 115 | ///收到断开跨房 PK 通知 116 | /// 117 | /// 参数param: 118 | /// 119 | /// userId:接收跨房PK的用户id 120 | onQuitRoomPK, 121 | 122 | /// 房间被销毁,当主播调用destroyRoom后,成员会收到该回调 123 | onRoomDestroy, 124 | 125 | /// 观众进入房间 126 | /// 127 | /// 参数: 128 | /// 129 | /// userId:用户id 130 | /// 131 | /// userName:用户昵称 132 | /// 133 | /// userAvatar:用户头像地址 134 | onAudienceEnter, 135 | 136 | /// 观众离开房间 137 | /// 138 | /// 参数: 139 | /// 140 | /// userId: 用户id 141 | onAudienceExit, 142 | 143 | /// 用于提示音量大小的回调,包括每个 userId 的音量和远端总音量。 144 | /// 145 | /// 您可以通过调用 TRTCCloud 中的 enableAudioVolumeEvaluation 接口来开关这个回调或者设置它的触发间隔。 需要注意的是,调用 enableAudioVolumeEvaluation 开启音量回调后,无论频道内是否有人说话,都会按设置的时间间隔调用这个回调; 如果没有人说话,则 userVolumes 为空,totalVolume 为0。 146 | /// 147 | /// 注意:userId 为本地用户 ID 时表示自己的音量,userVolumes 内仅包含正在说话(音量不为0)的用户音量信息。 148 | /// 149 | /// 参数param: 150 | /// 151 | /// userVolumes 所有正在说话的房间成员的音量,取值范围0 - 100。 152 | /// 153 | /// totalVolume 所有远端成员的总音量, 取值范围0 - 100。 154 | onUserVolumeUpdate, 155 | 156 | /// 收到群文本消息,可以用作文本聊天室 157 | /// 158 | /// 参数: 159 | /// 160 | /// message:文本消息 161 | /// 162 | /// sendId:发送者id 163 | /// 164 | /// userAvatar:发送者头像 165 | /// 166 | /// userName:发送者用户昵称 167 | onRecvRoomTextMsg, 168 | 169 | /// 收到自定义消息。 170 | /// 171 | /// 参数: 172 | /// 173 | /// cmd: 174 | /// 175 | /// sendId:发送者id 176 | /// 177 | /// userAvatar:发送者头像 178 | /// 179 | /// userName:发送者用户昵称 180 | onRecvRoomCustomMsg, 181 | 182 | //其他用户登录了同一账号,被踢下线 183 | onKickedOffline 184 | } 185 | -------------------------------------------------------------------------------- /lib/TRTCLiveRoomDemo/ui/base/SubVideoList.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:tencent_trtc_cloud/trtc_cloud_def.dart'; 3 | import 'package:tencent_trtc_cloud/trtc_cloud_video_view.dart'; 4 | 5 | class SubVideoList extends StatefulWidget { 6 | const SubVideoList( 7 | {Key? key, 8 | required this.userList, 9 | required this.onViewCreate, 10 | required this.onClose, 11 | this.isShowClose = false}) 12 | : super(key: key); 13 | final List userList; 14 | final bool isShowClose; 15 | final Function(String, int) onViewCreate; 16 | final Function(String) onClose; 17 | @override 18 | _SubVideoListState createState() => _SubVideoListState(); 19 | } 20 | 21 | class _SubVideoListState extends State { 22 | @override 23 | Widget build(BuildContext context) { 24 | return Positioned( 25 | right: 0, 26 | bottom: 80, 27 | child: Container( 28 | constraints: BoxConstraints( 29 | minHeight: 395, minWidth: 210, maxHeight: 395, maxWidth: 210), 30 | child: Stack( 31 | children: widget.userList.map((e) { 32 | int index = widget.userList.indexOf(e); 33 | int totalCout = widget.userList.length; 34 | double containerWidth = 100; 35 | double containerHeight = 120; 36 | double containerRight = 0; 37 | double containerBottom = (containerHeight + 5.0) * index + 5; 38 | if (totalCout <= 2) { 39 | containerWidth = 160; 40 | containerHeight = 190; 41 | containerBottom = (containerHeight + 5.0) * index + 5; 42 | } else if (totalCout > 3 && index >= 3 && index < 6) { 43 | containerRight = 110; 44 | containerBottom = (containerHeight + 5.0) * (index - 3) + 5; 45 | } else if (index > 6) { 46 | //多于六个不显示 47 | // return Positioned( 48 | // right: containerRight, 49 | // bottom: containerBottom, 50 | // width: containerWidth, 51 | // height: containerHeight, 52 | // child: Text(e), 53 | // ); 54 | } 55 | 56 | return Positioned( 57 | right: containerRight, 58 | bottom: containerBottom, 59 | width: containerWidth, 60 | height: containerHeight, 61 | child: SizedBox( 62 | height: containerHeight, 63 | width: containerWidth, 64 | child: Column( 65 | mainAxisSize: MainAxisSize.max, 66 | crossAxisAlignment: CrossAxisAlignment.start, 67 | children: [ 68 | SizedBox( 69 | height: 24, 70 | child: Row( 71 | mainAxisAlignment: MainAxisAlignment.center, 72 | crossAxisAlignment: CrossAxisAlignment.center, 73 | children: [ 74 | Expanded( 75 | flex: 2, 76 | child: Text(e), 77 | ), 78 | widget.isShowClose 79 | ? IconButton( 80 | onPressed: () { 81 | widget.onClose(e); 82 | }, 83 | iconSize: 16, 84 | icon: Icon(Icons.close_sharp), 85 | ) 86 | : Container(), 87 | ], 88 | ), 89 | ), 90 | SizedBox( 91 | height: containerHeight - 25, //95, 92 | // child: Container( 93 | // color: Colors.red, 94 | // ), 95 | child: TRTCCloudVideoView( 96 | key: ValueKey("Sub_VideoViewId_" + e), 97 | viewType: TRTCCloudDef.TRTC_VideoView_TextureView, 98 | onViewCreated: (viewId) async { 99 | widget.onViewCreate(e, viewId); 100 | }, 101 | ), 102 | ), 103 | ], 104 | ), 105 | ), 106 | ); 107 | }).toList(), 108 | ), 109 | )); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /lib/TRTCCallingDemo/model/TRTCCalling.dart: -------------------------------------------------------------------------------- 1 | import 'TRTCCallingDef.dart'; 2 | import 'impl/TRTCCallingImpl.dart'; 3 | 4 | abstract class TRTCCalling { 5 | static int typeUnknow = 0; 6 | static int typeAudioCall = 1; //纯音频通话 7 | static int typeVideoCall = 2; //视频通话 8 | 9 | /* 10 | * 获取 TRTCCalling 单例对象 11 | * 12 | * @return TRTCCalling 实例 13 | * @note 可以调用 {@link TRTCCalling.destroySharedInstance()} 销毁单例对象 14 | */ 15 | static Future sharedInstance() async { 16 | return TRTCCallingImpl.sharedInstance(); 17 | } 18 | 19 | /* 20 | * 销毁 TRTCCalling 单例对象 21 | * 22 | * @note 销毁实例后,外部缓存的 TRTCCalling 实例不能再使用,需要重新调用 {@link TRTCCalling.sharedInstance()} 获取新实例 23 | */ 24 | static void destroySharedInstance() async { 25 | TRTCCallingImpl.destroySharedInstance(); 26 | } 27 | 28 | /// 销毁函数,如果不需要再运行该实例,请调用该接口 29 | void destroy(); 30 | 31 | ////////////////////////////////////////////////////////// 32 | // 33 | // 基础接口 34 | // 35 | ////////////////////////////////////////////////////////// 36 | /* 37 | * 设置组件事件监听接口 38 | * 39 | * 您可以通过 registerListener 获得 TRTCCalling 的各种状态通知 40 | * 41 | * @param VoiceListenerFunc func 回调接口 42 | */ 43 | void registerListener(VoiceListenerFunc func); 44 | 45 | /* 46 | * 移除组件事件监听接口 47 | */ 48 | void unRegisterListener(VoiceListenerFunc func); 49 | 50 | /* 51 | * 登录 52 | * 53 | * @param sdkAppId 您可以在实时音视频控制台 >【[应用管理](https://console.cloud.tencent.com/trtc/app)】> 应用信息中查看 SDKAppID 54 | * @param userId 当前用户的 ID,字符串类型,只允许包含英文字母(a-z 和 A-Z)、数字(0-9)、连词符(-)和下划线(\_) 55 | * @param userSig 腾讯云设计的一种安全保护签名,获取方式请参考 [如何计算 UserSig](https://cloud.tencent.com/document/product/647/17275)。 56 | * @param 返回值:成功时 code 为0 57 | */ 58 | Future login(int sdkAppId, String userId, String userSig); 59 | 60 | /* 61 | * 退出登录 62 | */ 63 | Future logout(); 64 | 65 | /* 66 | * C2C邀请通话,被邀请方会收到 {@link TRTCCallingDelegate#onInvited } 的回调 67 | * 如果当前处于通话中,可以调用该函数以邀请第三方进入通话 68 | * 69 | * @param userId 被邀请方 70 | * @param type 1-语音通话,2-视频通话 71 | */ 72 | Future call(String userId, int type); 73 | 74 | /* 75 | * IM群组邀请通话,被邀请方会收到 {@link TRTCCallingDelegate#onInvited } 的回调 76 | * 如果当前处于通话中,可以继续调用该函数继续邀请他人进入通话,同时正在通话的用户会收到 {@link TRTCCallingDelegate#onGroupCallInviteeListUpdate(List)} 的回调 77 | * 78 | * @param userIdList 邀请列表 79 | * @param type 1-语音通话,2-视频通话 80 | * @param groupId IM群组ID,选填。如果填写该参数,那么通话请求消息是通过群消息系统广播出去的,这种消息广播方式比较简单可靠。如果不填写,那么 TRTCCalling 组件会采用单发消息逐一通知。 81 | */ 82 | Future groupCall( 83 | List userIdList, int type, String? groupId); 84 | 85 | /* 86 | * 当您作为被邀请方收到 {@link TRTCCallingDelegate#onInvited } 的回调时,可以调用该函数接听来电 87 | */ 88 | Future accept(); 89 | 90 | /* 91 | * 当您作为被邀请方收到 {@link TRTCCallingDelegate#onInvited } 的回调时,可以调用该函数拒绝来电 92 | */ 93 | Future reject(); 94 | 95 | /* 96 | * 当您处于通话中,可以调用该函数结束通话 97 | */ 98 | Future hangup(); 99 | 100 | /* 101 | * 当您收到 onUserVideoAvailable 回调时,可以调用该函数将远端用户的摄像头数据渲染到指定的TRTCCloudVideoView中 102 | * 103 | * @param userId 远端用户id 104 | * @param viewId 远端用户数据将渲染到该view中 105 | */ 106 | Future startRemoteView(String userId, int streamType, int viewId); 107 | 108 | /* 109 | * 当您收到 onUserVideoAvailable 回调为false时,可以停止渲染数据 110 | * 111 | * @param userId 远端用户id 112 | */ 113 | Future stopRemoteView(String userId, int streamType); 114 | 115 | /* 116 | * 更新远端视频画面的窗口 117 | * 118 | * @param userId 远端用户id 119 | * @param viewId 远端用户数据将渲染到该view中 120 | */ 121 | Future updateRemoteView(String userId, int streamType, int viewId); 122 | /* 123 | * 您可以调用该函数开启摄像头,并渲染在指定的TRTCCloudVideoView中 124 | * 处于通话中的用户会收到 {@link TRTCCallingDelegate#onUserVideoAvailable(java.lang.String, boolean)} 回调 125 | * 126 | * @param isFrontCamera 是否开启前置摄像头 127 | * @param viewId TRTCCloudVideoView生成的viewId 128 | */ 129 | Future openCamera(bool isFrontCamera, int viewId); 130 | 131 | /// 更新本地视频预览画面的窗口 132 | /// 133 | /// 参数: 134 | /// 135 | /// viewId 承载视频画面的控件 136 | Future updateLocalView(int viewId); 137 | 138 | /* 139 | * 您可以调用该函数关闭摄像头 140 | * 处于通话中的用户会收到 {@link TRTCCallingDelegate#onUserVideoAvailable(java.lang.String, boolean)} 回调 141 | */ 142 | Future closeCamera(); 143 | 144 | /* 145 | * 您可以调用该函数切换前后摄像头 146 | * 147 | * @param isFrontCamera true:切换前置摄像头 false:切换后置摄像头 148 | */ 149 | Future switchCamera(bool isFrontCamera); 150 | 151 | /* 152 | * 是否静音mic 153 | * 154 | * @param isMute true:麦克风关闭 false:麦克风打开 155 | */ 156 | Future setMicMute(bool isMute); 157 | 158 | /* 159 | * 是否开启免提 160 | * 161 | * @param isHandsFree true:开启免提 false:关闭免提 162 | */ 163 | Future setHandsFree(bool isHandsFree); 164 | } 165 | -------------------------------------------------------------------------------- /lib/i10n/messages_zh_CN.dart: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT. This is code generated via package:intl/generate_localized.dart 2 | // This is a library that provides messages for a zh_CN locale. All the 3 | // messages from the main program should be duplicated here with the same 4 | // function name. 5 | 6 | // Ignore issues from commonly used lints in this file. 7 | // ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new 8 | // ignore_for_file:prefer_single_quotes,comment_references, directives_ordering 9 | // ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases 10 | // ignore_for_file:unused_import, file_names 11 | 12 | import 'package:intl/intl.dart'; 13 | import 'package:intl/message_lookup_by_library.dart'; 14 | 15 | final messages = new MessageLookup(); 16 | 17 | typedef String MessageIfAbsent(String messageStr, List args); 18 | 19 | class MessageLookup extends MessageLookupByLibrary { 20 | String get localeName => 'zh_CN'; 21 | 22 | static m0(userName) => "${userName}的主题"; 23 | 24 | static m1(memberCount) => "${memberCount}人在线"; 25 | 26 | static m2(userName) => "${userName}申请成为主播"; 27 | 28 | final messages = _notInlinedMessages(_notInlinedMessages); 29 | static _notInlinedMessages(_) => { 30 | "adminLeaveRoomTips" : MessageLookupByLibrary.simpleMessage("离开会解散房间,确定离开吗?"), 31 | "anchor" : MessageLookupByLibrary.simpleMessage("主播"), 32 | "audience" : MessageLookupByLibrary.simpleMessage("听众"), 33 | "cancelText" : MessageLookupByLibrary.simpleMessage("取消"), 34 | "createSalonTooltip" : MessageLookupByLibrary.simpleMessage("创建语音沙龙"), 35 | "defaultChatTitle" : m0, 36 | "errorMeetTitle" : MessageLookupByLibrary.simpleMessage("请输入房间主题"), 37 | "errorMeetTitleLength" : MessageLookupByLibrary.simpleMessage("房间主题过长,请输入合法的房间主题"), 38 | "errorMicrophonePermission" : MessageLookupByLibrary.simpleMessage("需要获取音视频权限才能进入"), 39 | "errorOpenUrl" : MessageLookupByLibrary.simpleMessage("打开地址失败"), 40 | "errorSecretKey" : MessageLookupByLibrary.simpleMessage("请填写密钥"), 41 | "errorUserIDInput" : MessageLookupByLibrary.simpleMessage("请输入用户ID"), 42 | "errorUserIDNumber" : MessageLookupByLibrary.simpleMessage("用户ID必须为数字"), 43 | "errorUserName" : MessageLookupByLibrary.simpleMessage("请输入用户名"), 44 | "errorUserNameLength" : MessageLookupByLibrary.simpleMessage("用户名过长,请输入合法的用户名"), 45 | "errorsdkAppId" : MessageLookupByLibrary.simpleMessage("请填写SDKAPPID"), 46 | "failEnterRoom" : MessageLookupByLibrary.simpleMessage("进房失败"), 47 | "failKickedOffline" : MessageLookupByLibrary.simpleMessage("已在其他地方登陆,请重新登录"), 48 | "failRefuseToSpeak" : MessageLookupByLibrary.simpleMessage("抱歉,管理员没有同意您上麦"), 49 | "failRoomDestroy" : MessageLookupByLibrary.simpleMessage("沙龙已结束。"), 50 | "hadKickMic" : MessageLookupByLibrary.simpleMessage("你已被主播踢下麦"), 51 | "helpTooltip" : MessageLookupByLibrary.simpleMessage("查看说明文档"), 52 | "iSure" : MessageLookupByLibrary.simpleMessage("我确定"), 53 | "ignore" : MessageLookupByLibrary.simpleMessage("忽略"), 54 | "kickMic" : MessageLookupByLibrary.simpleMessage("要求下麦"), 55 | "leaveRoomTips" : MessageLookupByLibrary.simpleMessage("确定离开房间吗?"), 56 | "leaveTips" : MessageLookupByLibrary.simpleMessage("安静离开~"), 57 | "login" : MessageLookupByLibrary.simpleMessage("登录"), 58 | "logout" : MessageLookupByLibrary.simpleMessage("退出"), 59 | "logoutContent" : MessageLookupByLibrary.simpleMessage("确定退出登录吗?"), 60 | "meetTitleHintText" : MessageLookupByLibrary.simpleMessage("请输入房间名称"), 61 | "meetTitleLabel" : MessageLookupByLibrary.simpleMessage("主题"), 62 | "noHadSalon" : MessageLookupByLibrary.simpleMessage("暂无语音沙龙"), 63 | "okText" : MessageLookupByLibrary.simpleMessage("确定"), 64 | "onLineCount" : m1, 65 | "raiseUpList" : MessageLookupByLibrary.simpleMessage("举手列表"), 66 | "refreshReadyText" : MessageLookupByLibrary.simpleMessage("准备刷新数据"), 67 | "refreshText" : MessageLookupByLibrary.simpleMessage("下拉刷新"), 68 | "refreshedText" : MessageLookupByLibrary.simpleMessage("刷新完成"), 69 | "refreshingText" : MessageLookupByLibrary.simpleMessage("正在刷新中..."), 70 | "salonTitle" : MessageLookupByLibrary.simpleMessage("语音沙龙"), 71 | "startSalon" : MessageLookupByLibrary.simpleMessage("开始交谈"), 72 | "successAdminEnterRoom" : MessageLookupByLibrary.simpleMessage("房主占座成功。"), 73 | "successCreateRoom" : MessageLookupByLibrary.simpleMessage("房间创建成功。"), 74 | "successEnterRoom" : MessageLookupByLibrary.simpleMessage("进房成功"), 75 | "successLogin" : MessageLookupByLibrary.simpleMessage("登录成功"), 76 | "successRaiseHand" : MessageLookupByLibrary.simpleMessage("举手成功!等待管理员通过~"), 77 | "tencentTRTC" : MessageLookupByLibrary.simpleMessage("腾讯云TRTC"), 78 | "tipsText" : MessageLookupByLibrary.simpleMessage("提示"), 79 | "titleTRTC" : MessageLookupByLibrary.simpleMessage("TRTC"), 80 | "trtc" : MessageLookupByLibrary.simpleMessage("TRTC"), 81 | "userIDHintText" : MessageLookupByLibrary.simpleMessage("请输入登录的UserID"), 82 | "userIDLabel" : MessageLookupByLibrary.simpleMessage("用户ID"), 83 | "userNameHintText" : MessageLookupByLibrary.simpleMessage("请输入用户名"), 84 | "userNameLabel" : MessageLookupByLibrary.simpleMessage("用户名"), 85 | "userRaiseHand" : m2, 86 | "waitTips" : MessageLookupByLibrary.simpleMessage("再等等"), 87 | "welcome" : MessageLookupByLibrary.simpleMessage("欢迎") 88 | }; 89 | } 90 | -------------------------------------------------------------------------------- /lib/i10n/messages_messages.dart: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT. This is code generated via package:intl/generate_localized.dart 2 | // This is a library that provides messages for a messages locale. All the 3 | // messages from the main program should be duplicated here with the same 4 | // function name. 5 | 6 | // Ignore issues from commonly used lints in this file. 7 | // ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new 8 | // ignore_for_file:prefer_single_quotes,comment_references, directives_ordering 9 | // ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases 10 | // ignore_for_file:unused_import, file_names 11 | 12 | import 'package:intl/intl.dart'; 13 | import 'package:intl/message_lookup_by_library.dart'; 14 | 15 | final messages = new MessageLookup(); 16 | 17 | typedef String MessageIfAbsent(String messageStr, List args); 18 | 19 | class MessageLookup extends MessageLookupByLibrary { 20 | String get localeName => 'messages'; 21 | 22 | static m0(userName) => "${userName}的主题"; 23 | 24 | static m1(memberCount) => "${memberCount}人在线"; 25 | 26 | static m2(userName) => "${userName}申请成为主播"; 27 | 28 | final messages = _notInlinedMessages(_notInlinedMessages); 29 | static _notInlinedMessages(_) => { 30 | "adminLeaveRoomTips" : MessageLookupByLibrary.simpleMessage("离开会解散房间,确定离开吗?"), 31 | "anchor" : MessageLookupByLibrary.simpleMessage("主播"), 32 | "audience" : MessageLookupByLibrary.simpleMessage("听众"), 33 | "cancelText" : MessageLookupByLibrary.simpleMessage("取消"), 34 | "createSalonTooltip" : MessageLookupByLibrary.simpleMessage("创建语音沙龙"), 35 | "defaultChatTitle" : m0, 36 | "errorMeetTitle" : MessageLookupByLibrary.simpleMessage("请输入房间主题"), 37 | "errorMeetTitleLength" : MessageLookupByLibrary.simpleMessage("房间主题过长,请输入合法的房间主题"), 38 | "errorMicrophonePermission" : MessageLookupByLibrary.simpleMessage("需要获取音视频权限才能进入"), 39 | "errorOpenUrl" : MessageLookupByLibrary.simpleMessage("打开地址失败"), 40 | "errorSecretKey" : MessageLookupByLibrary.simpleMessage("请填写密钥"), 41 | "errorUserIDInput" : MessageLookupByLibrary.simpleMessage("请输入用户ID"), 42 | "errorUserIDNumber" : MessageLookupByLibrary.simpleMessage("用户ID必须为数字"), 43 | "errorUserName" : MessageLookupByLibrary.simpleMessage("请输入用户名"), 44 | "errorUserNameLength" : MessageLookupByLibrary.simpleMessage("用户名过长,请输入合法的用户名"), 45 | "errorsdkAppId" : MessageLookupByLibrary.simpleMessage("请填写SDKAPPID"), 46 | "failEnterRoom" : MessageLookupByLibrary.simpleMessage("进房失败"), 47 | "failKickedOffline" : MessageLookupByLibrary.simpleMessage("已在其他地方登陆,请重新登录"), 48 | "failRefuseToSpeak" : MessageLookupByLibrary.simpleMessage("抱歉,管理员没有同意您上麦"), 49 | "failRoomDestroy" : MessageLookupByLibrary.simpleMessage("沙龙已结束。"), 50 | "hadKickMic" : MessageLookupByLibrary.simpleMessage("你已被主播踢下麦"), 51 | "helpTooltip" : MessageLookupByLibrary.simpleMessage("查看说明文档"), 52 | "iSure" : MessageLookupByLibrary.simpleMessage("我确定"), 53 | "ignore" : MessageLookupByLibrary.simpleMessage("忽略"), 54 | "kickMic" : MessageLookupByLibrary.simpleMessage("要求下麦"), 55 | "leaveRoomTips" : MessageLookupByLibrary.simpleMessage("确定离开房间吗?"), 56 | "leaveTips" : MessageLookupByLibrary.simpleMessage("安静离开~"), 57 | "login" : MessageLookupByLibrary.simpleMessage("登录"), 58 | "logout" : MessageLookupByLibrary.simpleMessage("退出"), 59 | "logoutContent" : MessageLookupByLibrary.simpleMessage("确定退出登录吗?"), 60 | "meetTitleHintText" : MessageLookupByLibrary.simpleMessage("请输入房间名称"), 61 | "meetTitleLabel" : MessageLookupByLibrary.simpleMessage("主题"), 62 | "noHadSalon" : MessageLookupByLibrary.simpleMessage("暂无语音沙龙"), 63 | "okText" : MessageLookupByLibrary.simpleMessage("确定"), 64 | "onLineCount" : m1, 65 | "raiseUpList" : MessageLookupByLibrary.simpleMessage("举手列表"), 66 | "refreshReadyText" : MessageLookupByLibrary.simpleMessage("准备刷新数据"), 67 | "refreshText" : MessageLookupByLibrary.simpleMessage("下拉刷新"), 68 | "refreshedText" : MessageLookupByLibrary.simpleMessage("刷新完成"), 69 | "refreshingText" : MessageLookupByLibrary.simpleMessage("正在刷新中..."), 70 | "salonTitle" : MessageLookupByLibrary.simpleMessage("语音沙龙"), 71 | "startSalon" : MessageLookupByLibrary.simpleMessage("开始交谈"), 72 | "successAdminEnterRoom" : MessageLookupByLibrary.simpleMessage("房主占座成功。"), 73 | "successCreateRoom" : MessageLookupByLibrary.simpleMessage("房间创建成功。"), 74 | "successEnterRoom" : MessageLookupByLibrary.simpleMessage("进房成功"), 75 | "successLogin" : MessageLookupByLibrary.simpleMessage("登录成功"), 76 | "successRaiseHand" : MessageLookupByLibrary.simpleMessage("举手成功!等待管理员通过~"), 77 | "tencentTRTC" : MessageLookupByLibrary.simpleMessage("腾讯云TRTC"), 78 | "tipsText" : MessageLookupByLibrary.simpleMessage("提示"), 79 | "titleTRTC" : MessageLookupByLibrary.simpleMessage("TRTC"), 80 | "trtc" : MessageLookupByLibrary.simpleMessage("TRTC"), 81 | "userIDHintText" : MessageLookupByLibrary.simpleMessage("请输入登录的UserID"), 82 | "userIDLabel" : MessageLookupByLibrary.simpleMessage("用户ID"), 83 | "userNameHintText" : MessageLookupByLibrary.simpleMessage("请输入用户名"), 84 | "userNameLabel" : MessageLookupByLibrary.simpleMessage("用户名"), 85 | "userRaiseHand" : m2, 86 | "waitTips" : MessageLookupByLibrary.simpleMessage("再等等"), 87 | "welcome" : MessageLookupByLibrary.simpleMessage("欢迎") 88 | }; 89 | } 90 | -------------------------------------------------------------------------------- /lib/login/LoginPage.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:permission_handler/permission_handler.dart'; 4 | import '../utils/TxUtils.dart'; 5 | import '../utils/constants.dart' as constants; 6 | import '../debug/GenerateTestUserSig.dart'; 7 | import '../TRTCChatSalonDemo/model/TRTCChatSalon.dart'; 8 | import '../TRTCChatSalonDemo/model/TRTCChatSalonDef.dart'; 9 | import '../i10n/localization_intl.dart'; 10 | 11 | /* 12 | * 登录界面 13 | */ 14 | class LoginPage extends StatefulWidget { 15 | LoginPage({Key? key}) : super(key: key); 16 | 17 | @override 18 | State createState() => LoginPageState(); 19 | } 20 | 21 | class LoginPageState extends State { 22 | late TRTCChatSalon trtcVoiceRoom; 23 | 24 | final userFocusNode = FocusNode(); 25 | 26 | /// 用户id 27 | String userId = ''; 28 | 29 | login(context) async { 30 | if ((await Permission.camera.request().isGranted && 31 | await Permission.microphone.request().isGranted)) { 32 | } else { 33 | TxUtils.showErrorToast('需要获取音视频权限才能进入', context); 34 | return; 35 | } 36 | if (userId == '') { 37 | TxUtils.showErrorToast(Languages.of(context)!.errorUserIDInput, context); 38 | return; 39 | } 40 | if (double.tryParse(userId) == null) { 41 | TxUtils.showErrorToast(Languages.of(context)!.errorUserIDNumber, context); 42 | return; 43 | } 44 | trtcVoiceRoom = await TRTCChatSalon.sharedInstance(); 45 | ActionCallback resValue = await trtcVoiceRoom.login( 46 | GenerateTestUserSig.sdkAppId, 47 | userId, 48 | GenerateTestUserSig.genTestSig(userId), 49 | ); 50 | 51 | await trtcVoiceRoom.setSelfProfile( 52 | 'ID:' + userId, constants.DEFAULT_ROOM_IMAGE); 53 | if (resValue.code == 0) { 54 | TxUtils.showToast(Languages.of(context)!.successLogin, context); 55 | TxUtils.setStorageByKey(constants.USERID_KEY, userId); 56 | Navigator.pushNamed(context, "/index"); 57 | } else { 58 | TxUtils.showErrorToast('setSelfProfile:' + resValue.desc, context); 59 | } 60 | } 61 | 62 | // 隐藏底部输入框 63 | unFocus() { 64 | if (userFocusNode.hasFocus) { 65 | userFocusNode.unfocus(); 66 | } 67 | } 68 | 69 | @override 70 | dispose() { 71 | super.dispose(); 72 | unFocus(); 73 | } 74 | 75 | @override 76 | Widget build(BuildContext context) { 77 | return Scaffold( 78 | resizeToAvoidBottomInset: false, 79 | appBar: AppBar( 80 | automaticallyImplyLeading: false, 81 | title: Text(Languages.of(context)!.tencentTRTC), 82 | centerTitle: true, 83 | elevation: 0, 84 | // automaticallyImplyLeading: false, 85 | backgroundColor: Color.fromRGBO(14, 25, 44, 1), 86 | ), 87 | body: GestureDetector( 88 | behavior: HitTestBehavior.translucent, 89 | onTap: () { 90 | if (userFocusNode.hasFocus) { 91 | userFocusNode.unfocus(); 92 | } 93 | }, 94 | child: Container( 95 | color: Color.fromRGBO(14, 25, 44, 1), 96 | padding: const EdgeInsets.symmetric(horizontal: 20.0), 97 | child: Column( 98 | children: [ 99 | Container( 100 | color: Color.fromRGBO(13, 44, 91, 1), 101 | margin: const EdgeInsets.only(top: 60.0), 102 | padding: const EdgeInsets.only(left: 10.0, right: 10.0), 103 | child: Column( 104 | children: [ 105 | TextField( 106 | style: TextStyle(color: Colors.white), 107 | autofocus: true, 108 | focusNode: userFocusNode, 109 | decoration: InputDecoration( 110 | labelText: Languages.of(context)!.userIDLabel, 111 | hintText: Languages.of(context)!.userIDHintText, 112 | labelStyle: TextStyle(color: Colors.white), 113 | hintStyle: TextStyle( 114 | color: Color.fromRGBO(255, 255, 255, 0.5)), 115 | enabledBorder: UnderlineInputBorder( 116 | borderSide: BorderSide(color: Colors.white), 117 | ), 118 | ), 119 | keyboardType: TextInputType.number, 120 | onChanged: (value) => this.userId = value), 121 | ], 122 | ), 123 | ), 124 | Padding( 125 | padding: const EdgeInsets.only(top: 30.0), 126 | child: Row( 127 | children: [ 128 | Expanded( 129 | child: RaisedButton( 130 | padding: EdgeInsets.all(15.0), 131 | child: Text(Languages.of(context)!.login), 132 | color: Theme.of(context).primaryColor, 133 | textColor: Colors.white, 134 | onPressed: () => login(context), 135 | ), 136 | ), 137 | ], 138 | ), 139 | ) 140 | ], 141 | ), 142 | ), 143 | ), 144 | ); 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /lib/TRTCLiveRoomDemo/model/TRTCLiveRoom.dart: -------------------------------------------------------------------------------- 1 | import 'impl/TRTCLiveRoomImpl.dart'; 2 | import './TRTCLiveRoomDef.dart'; 3 | 4 | // 视频互动直播组件 5 | abstract class TRTCLiveRoom { 6 | /* 7 | * 获取 TRTCLiveRoom 单例对象 8 | * 9 | * @return TRTCLiveRoom 实例 10 | * @note 可以调用 {@link TRTCLiveRoom.destroySharedInstance()} 销毁单例对象 11 | */ 12 | static Future sharedInstance() async { 13 | return TRTCLiveRoomImpl.sharedInstance(); 14 | } 15 | 16 | /* 17 | * 销毁 TRTCLiveRoom 单例对象 18 | * 19 | * @note 销毁实例后,外部缓存的 TRTCLiveRoom 实例不能再使用,需要重新调用 {@link TRTCLiveRoom.sharedInstance()} 获取新实例 20 | */ 21 | static void destroySharedInstance() async { 22 | TRTCLiveRoomImpl.destroySharedInstance(); 23 | } 24 | 25 | ////////////////////////////////////////////////////////// 26 | // 27 | // 基础接口 28 | // 29 | ////////////////////////////////////////////////////////// 30 | /* 31 | * 设置组件事件监听接口 32 | * 33 | * 您可以通过 registerListener 获得 TRTCCalling 的各种状态通知 34 | * 35 | * @param VoiceListenerFunc func 回调接口 36 | */ 37 | void registerListener(VoiceListenerFunc func); 38 | 39 | /* 40 | * 移除组件事件监听接口 41 | */ 42 | void unRegisterListener(VoiceListenerFunc func); 43 | 44 | /* 45 | * 登录 46 | * 47 | * @param sdkAppId 您可以在实时音视频控制台 >【[应用管理](https://console.cloud.tencent.com/trtc/app)】> 应用信息中查看 SDKAppID 48 | * @param userId 当前用户的 ID,字符串类型,只允许包含英文字母(a-z 和 A-Z)、数字(0-9)、连词符(-)和下划线(\_) 49 | * @param userSig 腾讯云设计的一种安全保护签名,获取方式请参考 [如何计算 UserSig](https://cloud.tencent.com/document/product/647/17275)。 50 | * @param 返回值:成功时 code 为0 51 | */ 52 | Future login( 53 | int sdkAppId, String userId, String userSig, TRTCLiveRoomConfig config); 54 | 55 | /* 56 | * 退出登录 57 | */ 58 | Future logout(); 59 | 60 | /* 61 | * 设置用户信息,您设置的用户信息会被存储于腾讯云 IM 云服务中。 62 | * 63 | * @param userName 用户昵称 64 | * @param avatarURL 用户头像 65 | */ 66 | Future setSelfProfile(String userName, String avatarURL); 67 | 68 | ////////////////////////////////////////////////////////// 69 | // 70 | // 房间管理接口 71 | // 72 | ////////////////////////////////////////////////////////// 73 | 74 | /* 75 | * 创建房间(房间创建者调用) 76 | * 77 | * @param roomId 房间标识,需要由您分配并进行统一管理。 78 | * @param roomParam 房间信息,用于房间描述的信息,例如房间名称,封面信息等。如果房间列表和房间信息都由您的服务器自行管理,可忽略该参数。 79 | * @param callback 创建房间的结果回调,成功时 code 为0. 80 | */ 81 | Future createRoom(int roomId, RoomParam roomParam); 82 | 83 | /* 84 | * 销毁房间(房间创建者调用) 85 | * 86 | * 主播在创建房间后,可以调用这个函数来销毁房间。 87 | */ 88 | Future destroyRoom(); 89 | 90 | /* 91 | * 进入房间(观众调用) 92 | * 93 | * @param roomId 房间标识 94 | */ 95 | Future enterRoom(int roomId); 96 | 97 | /* 98 | * 退出房间(观众调用) 99 | * 100 | */ 101 | Future exitRoom(); 102 | 103 | /* 104 | * 获取房间列表的详细信息 105 | * 106 | * 其中的信息是主播在创建 createRoom() 时通过 roomInfo 设置进来的,如果房间列表和房间信息都由您的服务器自行管理,此函数您可以不用关心。 107 | * 108 | * @param roomIdList 房间id列表 109 | */ 110 | Future getRoomInfos(List roomIdList); 111 | 112 | // 获取房间内所有的主播列表,enterRoom() 成功后调用才有效。 113 | Future getAnchorList(); 114 | 115 | // 获取群成员列表。 116 | Future getRoomMemberList(int nextSeq); 117 | 118 | // 开启本地视频的预览画面。 119 | Future startCameraPreview(bool isFrontCamera, int viewId); 120 | 121 | //更新本地视频预览画面的窗口,仅仅ios有效 122 | Future updateLocalView(int viewId); 123 | 124 | // 停止本地视频采集及预览。 125 | Future stopCameraPreview(); 126 | 127 | // 开始直播(推流),适用于以下场景: 128 | // 主播开播的时候调用 129 | // 观众开始连麦时调用 130 | Future startPublish(String? streamId); 131 | 132 | // 停止直播(推流)。 133 | Future stopPublish(); 134 | 135 | // 播放远端视频画面,可以在普通观看和连麦场景中调用。 136 | Future startPlay(String userId, int viewId); 137 | 138 | //更新远端视频画面的窗口,仅仅ios有效 139 | Future updateRemoteView(String userId, int viewId); 140 | 141 | // 停止渲染远端视频画面。 142 | Future stopPlay(String userId); 143 | 144 | // 观众请求连麦。 145 | Future requestJoinAnchor(); 146 | 147 | // 主播处理连麦请求。 148 | Future responseJoinAnchor( 149 | String userId, bool agreee, String callId); 150 | 151 | // 主播踢除连麦观众。 152 | Future kickoutJoinAnchor(String userId); 153 | 154 | // 主播请求跨房 PK。 155 | Future requestRoomPK(int roomId, String userId); 156 | 157 | // 主播响应跨房 PK 请求。 158 | Future responseRoomPK(String userId, bool agree); 159 | 160 | // 退出跨房 PK。 161 | Future quitRoomPK(); 162 | 163 | /* 164 | * 切换前后摄像头。 165 | * 166 | * @param isFrontCamera true:切换前置摄像头 false:切换后置摄像头 167 | */ 168 | Future switchCamera(bool isFrontCamera); 169 | 170 | // 设置是否镜像展示。 171 | Future setMirror(bool isMirror); 172 | 173 | /* 174 | * 开启本地静音。 175 | * @param mute 是否静音 176 | */ 177 | Future muteLocalAudio(bool mute); 178 | 179 | /* 180 | * 静音远端音频。 181 | * @param userId 远端用户id 182 | * @param mute 是否静音 183 | */ 184 | Future muteRemoteAudio(String userId, bool mute); 185 | 186 | /* 187 | * 静音所有远端音频。 188 | * @param mute 是否静音 189 | */ 190 | Future muteAllRemoteAudio(bool mute); 191 | 192 | // 获取背景音乐音效管理对象 TXAudioEffectManager。 193 | getAudioEffectManager(); 194 | 195 | // 获取美颜管理对象 TXBeautyManager。 196 | getBeautyManager(); 197 | 198 | /* 199 | * 在房间中广播文本消息,一般用于弹幕聊天 200 | * @param message 文本消息 201 | */ 202 | Future sendRoomTextMsg(String message); 203 | 204 | /* 205 | * 发送自定义文本消息。 206 | * @param cmd 命令字,由开发者自定义,主要用于区分不同消息类型。 207 | * @param message 文本消息 208 | */ 209 | Future sendRoomCustomMsg(String cmd, String message); 210 | } 211 | -------------------------------------------------------------------------------- /lib/i10n/messages_en_US.dart: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT. This is code generated via package:intl/generate_localized.dart 2 | // This is a library that provides messages for a en_US locale. All the 3 | // messages from the main program should be duplicated here with the same 4 | // function name. 5 | 6 | // Ignore issues from commonly used lints in this file. 7 | // ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new 8 | // ignore_for_file:prefer_single_quotes,comment_references, directives_ordering 9 | // ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases 10 | // ignore_for_file:unused_import, file_names 11 | 12 | import 'package:intl/intl.dart'; 13 | import 'package:intl/message_lookup_by_library.dart'; 14 | 15 | final messages = new MessageLookup(); 16 | 17 | typedef String MessageIfAbsent(String messageStr, List args); 18 | 19 | class MessageLookup extends MessageLookupByLibrary { 20 | String get localeName => 'en_US'; 21 | 22 | static m0(userName) => "the topic of ${userName}s"; 23 | 24 | static m1(memberCount) => "${memberCount} watching"; 25 | 26 | static m2(userName) => "${userName} applies to become a speaker"; 27 | 28 | final messages = _notInlinedMessages(_notInlinedMessages); 29 | static _notInlinedMessages(_) => { 30 | "adminLeaveRoomTips" : MessageLookupByLibrary.simpleMessage("you want to end the room?"), 31 | "anchor" : MessageLookupByLibrary.simpleMessage("Speakers"), 32 | "audience" : MessageLookupByLibrary.simpleMessage("Audiences"), 33 | "cancelText" : MessageLookupByLibrary.simpleMessage("Cancel"), 34 | "createSalonTooltip" : MessageLookupByLibrary.simpleMessage("Create a chat salon room"), 35 | "defaultChatTitle" : m0, 36 | "errorMeetTitle" : MessageLookupByLibrary.simpleMessage("Topic is empty"), 37 | "errorMeetTitleLength" : MessageLookupByLibrary.simpleMessage("Topic is too long"), 38 | "errorMicrophonePermission" : MessageLookupByLibrary.simpleMessage("Need to obtain audio permissions to enter"), 39 | "errorOpenUrl" : MessageLookupByLibrary.simpleMessage("Failed to open address"), 40 | "errorSecretKey" : MessageLookupByLibrary.simpleMessage("Invalid secretKey "), 41 | "errorUserIDInput" : MessageLookupByLibrary.simpleMessage("User ID is empty"), 42 | "errorUserIDNumber" : MessageLookupByLibrary.simpleMessage("User ID must be number"), 43 | "errorUserName" : MessageLookupByLibrary.simpleMessage("Nickname or user name is empty"), 44 | "errorUserNameLength" : MessageLookupByLibrary.simpleMessage("Nickname or user name is too long"), 45 | "errorsdkAppId" : MessageLookupByLibrary.simpleMessage("Invalid appid"), 46 | "failEnterRoom" : MessageLookupByLibrary.simpleMessage("Enter room failed"), 47 | "failKickedOffline" : MessageLookupByLibrary.simpleMessage("Already logged in elsewhere, please log in again"), 48 | "failRefuseToSpeak" : MessageLookupByLibrary.simpleMessage("Sorry, the administrator did not agree"), 49 | "failRoomDestroy" : MessageLookupByLibrary.simpleMessage("The host has closed the room"), 50 | "hadKickMic" : MessageLookupByLibrary.simpleMessage("You have been kicked off by the administrator"), 51 | "helpTooltip" : MessageLookupByLibrary.simpleMessage("View documentation"), 52 | "iSure" : MessageLookupByLibrary.simpleMessage("Confirm"), 53 | "ignore" : MessageLookupByLibrary.simpleMessage("Dismiss"), 54 | "kickMic" : MessageLookupByLibrary.simpleMessage("Move to the audience"), 55 | "leaveRoomTips" : MessageLookupByLibrary.simpleMessage("You want to leave the room?"), 56 | "leaveTips" : MessageLookupByLibrary.simpleMessage("Leave quietly "), 57 | "login" : MessageLookupByLibrary.simpleMessage("Login"), 58 | "logout" : MessageLookupByLibrary.simpleMessage("Logout"), 59 | "logoutContent" : MessageLookupByLibrary.simpleMessage("Are you sure to log out?"), 60 | "meetTitleHintText" : MessageLookupByLibrary.simpleMessage("Please input topic"), 61 | "meetTitleLabel" : MessageLookupByLibrary.simpleMessage("Topic"), 62 | "noHadSalon" : MessageLookupByLibrary.simpleMessage("No content yet~"), 63 | "okText" : MessageLookupByLibrary.simpleMessage("Confirm"), 64 | "onLineCount" : m1, 65 | "raiseUpList" : MessageLookupByLibrary.simpleMessage("Raised hands"), 66 | "refreshReadyText" : MessageLookupByLibrary.simpleMessage("Start refresh"), 67 | "refreshText" : MessageLookupByLibrary.simpleMessage("Pull down to refresh"), 68 | "refreshedText" : MessageLookupByLibrary.simpleMessage("Refresh complete"), 69 | "refreshingText" : MessageLookupByLibrary.simpleMessage("loading…"), 70 | "salonTitle" : MessageLookupByLibrary.simpleMessage("Chat Salon"), 71 | "startSalon" : MessageLookupByLibrary.simpleMessage("Let’s go"), 72 | "successAdminEnterRoom" : MessageLookupByLibrary.simpleMessage("Host succeeded in occupying the seat"), 73 | "successCreateRoom" : MessageLookupByLibrary.simpleMessage("Create room success"), 74 | "successEnterRoom" : MessageLookupByLibrary.simpleMessage("Enter room success"), 75 | "successLogin" : MessageLookupByLibrary.simpleMessage("Login success"), 76 | "successRaiseHand" : MessageLookupByLibrary.simpleMessage("You raised your hand! We\'ll let the speakers know you want to talk~"), 77 | "tencentTRTC" : MessageLookupByLibrary.simpleMessage("Tencent TRTC"), 78 | "tipsText" : MessageLookupByLibrary.simpleMessage("Tips"), 79 | "titleTRTC" : MessageLookupByLibrary.simpleMessage("TRTC"), 80 | "trtc" : MessageLookupByLibrary.simpleMessage("TRTC"), 81 | "userIDHintText" : MessageLookupByLibrary.simpleMessage("Please input user ID"), 82 | "userIDLabel" : MessageLookupByLibrary.simpleMessage("User ID"), 83 | "userNameHintText" : MessageLookupByLibrary.simpleMessage("Please input user ID"), 84 | "userNameLabel" : MessageLookupByLibrary.simpleMessage("User ID"), 85 | "userRaiseHand" : m2, 86 | "waitTips" : MessageLookupByLibrary.simpleMessage("Wait a bit"), 87 | "welcome" : MessageLookupByLibrary.simpleMessage("Welcome") 88 | }; 89 | } 90 | -------------------------------------------------------------------------------- /TRTCCallingAudio.md: -------------------------------------------------------------------------------- 1 | ## 实时语音通话(Flutter) 2 | 3 | 如需快速实现语音通话功能,您可以直接基于我们提供的 Demo 进行修改适配,也可以使用我们提供的 TRTCCalling 组件并实现自定义 UI 界面。 4 | 5 | ## 复用 Demo 的 UI 界面 6 | 7 | ### 步骤1:创建新的应用 8 | 1. 登录实时音视频控制台,选择【开发辅助】>【[快速跑通Demo](https://console.cloud.tencent.com/trtc/quickstart)】。 9 | 2. 输入应用名称,例如 `TestAudioCall` ,单击【创建】。 10 | 11 | >!本功能同时使用了腾讯云 [实时音视频 TRTC](https://cloud.tencent.com/document/product/647/16788) 和 [即时通信 IM](https://cloud.tencent.com/document/product/269) 两个基础 PaaS 服务,开通实时音视频后会同步开通即时通信 IM 服务。 即时通信 IM 属于增值服务,详细计费规则请参见 [即时通信 IM 价格说明](https://cloud.tencent.com/document/product/269/11673)。 12 | 13 | 14 | [](id:ui.step2) 15 | ### 步骤2:下载 SDK 和 Demo 源码 16 | 1. 根据实际业务需求下载 SDK 及配套的 Demo 源码。 17 | 2. 下载完成后,单击【已下载,下一步】。 18 | ![](https://main.qcloudimg.com/raw/3b115019ddfd0866108ed1add30810d8.png) 19 | 20 | [](id:ui.step3) 21 | ### 步骤3:配置 Demo 工程文件 22 | 1. 进入修改配置页,根据您下载的源码包,选择相应的开发环境。 23 | 2. 找到并打开 `/lib/debug/GenerateTestUserSig.dart` 文件。 24 | 3. 设置 `GenerateTestUserSig.dart` 文件中的相关参数: 25 |

  • SDKAPPID:默认为0,请设置为实际的 SDKAppID。 26 |
  • SECRETKEY:默认为空字符串,请设置为实际的密钥信息。
27 | 28 | 4. 粘贴完成后,单击【已复制粘贴,下一步】即创建成功。 29 | 5. 编译完成后,单击【回到控制台概览】即可。 30 | 31 | >! 32 | >- 本文提到的生成 UserSig 的方案是在客户端代码中配置 SECRETKEY,该方法中 SECRETKEY 很容易被反编译逆向破解,一旦您的密钥泄露,攻击者就可以盗用您的腾讯云流量,因此**该方法仅适合本地跑通 Demo 和功能调试**。 33 | >- 正确的 UserSig 签发方式是将 UserSig 的计算代码集成到您的服务端,并提供面向 App 的接口,在需要 UserSig 时由您的 App 向业务服务器发起请求获取动态 UserSig。更多详情请参见 [服务端生成 UserSig](https://cloud.tencent.com/document/product/647/17275#Server)。 34 | 35 | [](id:ui.step4) 36 | 37 | ### 步骤4:运行 Demo 38 | >! 安卓需要在真机下运行,不支持模拟器调试。 39 | 40 | 1. 执行 `flutter pub get`。 41 | 2. 编译运行调试: 42 | 43 | ::: Android\s端 44 | 1. 执行 `flutter run`。 45 | 2. 使用 Android Studio(3.5及以上的版本)打开源码工程,单击【运行】即可。 46 | ::: 47 | ::: iOS\s端 48 | 1. 使用 XCode(11.0及以上的版本)打开源码目录下的 `/ios工程`。 49 | 2. 编译并运行 Demo 工程即可。 50 | ::: 51 | 52 | 53 | 54 | [](id:ui.step5) 55 | 56 | ### 步骤5:修改 Demo 源代码 57 | 58 | 源码文件夹 `TRTCCallingDemo` 中包含两个子文件夹 ui 和 model,其中 ui 文件夹中均为界面代码: 59 | 60 | | 文件或文件夹 | 功能描述 | 61 | | -------------------------------- | ------------------------------------------------------------ | 62 | | TRTCCallingVideo.dart |展示音视频通话的主界面,通话的接听和拒绝就是在这个界面中完成的。 | 63 | | TRTCCallingContact.dart | 用于展示选择联系人的界面,可以通过此界面搜索已注册用户,发起通话。 | 64 | 65 | [](id:model) 66 | 67 | ## 实现自定义 UI 界面 68 | 69 | [源码](https://github.com/tencentyun/TRTCFlutterScenesDemo) 文件夹 `TRTCCallingDemo` 中包含两个子文件夹 ui 和 model,其中 model 文件夹中包含了我们实现的可重用开源组件 TRTCCalling,您可以在 `TRTCCalling.dart` 文件中看到该组件提供的接口函数。 70 | ![](https://main.qcloudimg.com/raw/36220937e8689dac4499ce9f2f187889.png) 71 | 72 | 您可以使用开源组件 TRTCCalling 实现自己的 UI 界面,即只复用 model 部分,自行实现 UI 部分。 73 | 74 | [](id:model.step1) 75 | 76 | ### 步骤1:集成 SDK 77 | 音视频通话组件 TRTCCalling 依赖 [TRTC SDK](https://pub.dev/packages/tencent_trtc_cloud) 和 [IM SDK](https://pub.dev/packages/tencent_im_sdk_plugin),您可以通过配置 `pubspec.yaml` 自动下载更新。 78 | 1. 在项目的 `pubspec.yaml` 中写如下依赖: 79 | ``` 80 | dependencies: 81 | tencent_trtc_cloud: 最新版本号 82 | tencent_im_sdk_plugin: 最新版本号 83 | ``` 84 | 85 | [](id:model.step2) 86 | ### 步骤2:配置权限及混淆规则 87 | 88 | ::: iOS端 89 | 1. 需要在 `Info.plist` 中加入对相机和麦克风的权限申请: 90 | ``` 91 | NSMicrophoneUsageDescription 92 | 授权麦克风权限才能正常语音通话 93 | ``` 94 | ::: 95 | ::: Android端 96 | 1. 打开 `/android/app/src/main/AndroidManifest.xml` 文件。 97 | 2. 将 `xmlns:tools="http://schemas.android.com/tools"` 加入到 manifest 中。 98 | 3. 将 `tools:replace="android:label"` 加入到 application 中。 99 | >? 若不执行此步,会出现 [Android Manifest merge failed 编译失败](https://cloud.tencent.com/document/product/647/51623#que6) 问题。 100 | 101 | 102 | ![图示](https://main.qcloudimg.com/raw/7a37917112831488423c1744f370c883.png) 103 | ::: 104 | 105 | 106 | 107 | [](id:model.step3) 108 | 109 | ### 步骤3:导入 TRTCCalling 组件 110 | 111 | 拷贝以下目录中的所有文件到您的项目中: 112 | 113 | ``` 114 | /lib/TRTCCallingDemo/model 115 | ``` 116 | 117 | [](id:model.step4) 118 | 119 | ### 步骤4:初始化并登录组件 120 | 121 | 1. 调用 `TRTCCalling.sharedInstance()` 获取组件实例。 122 | 2. 调用 `login(SDKAppID, userId, userSig)` 完成组件的登录,其中几个关键参数的填写请参考下表: 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 |
参数名作用
SDKAppID您可以在 实时音视频控制台 中查看 SDKAppID。
userId当前用户的 ID,字符串类型,只允许包含英文字母(a-z 和 A-Z)、数字(0-9)、连词符(-)和下划线(_)。
userSig腾讯云设计的一种安全保护签名,计算方式请参考 如何计算 UserSig
135 | 136 | ::: java 137 | // 初始化 138 | sCall = await TRTCCalling.sharedInstance(); 139 | sCall.login(1400000123, "userA", "xxxx"); 140 | ::: 141 | 142 | 143 | [](id:model.step5) 144 | 145 | ### 步骤5:实现 1v1 语音通话 146 | 147 | 1. 发起方:调用 `TRTCCalling` 的 `call()` 方法发起通话的请求, 并传入用户 ID(userid)和通话类型(type),通话类型参数传入`TRTCCalling.typeAudioCall`。 148 | 2. 接收方:当接收方处于已登录状态时,会收到名为 `onInvited()` 的事件通知,回调中 `callType` 的参数是发起方填写的通话类型,您可以通过此参数启动相应的界面。 149 | 3. 接收方:如果希望接听电话,接收方可以调用 `accept()` 函数,并同时调用 `openCamera()` 函数打开自己本地的摄像头。接收方也可以调用 `reject()` 拒绝此次通话。 150 | 4. 当双方的音视频通道建立完成后,通话的双方都会接收到名为 `onUserVideoAvailable()` 的事件通知,表示对方的视频画面已经拿到。此时双方用户均可以调用`startRemoteView()` 展示远端的视频画面。远端的声音默认是自动播放的。 151 | 152 | [](id:model.offline) 153 | 154 | ### 步骤6:实现离线接听 155 | 离线接听暂不支持,计划在6月中旬支持 156 | 157 | [](id:api) 158 | 159 | ## 组件 API 列表 160 | 161 | TRTCCalling 组件的 API 接口列表如下: 162 | 163 | | 接口函数 | 接口功能 | 164 | | --------------- | --------------------------------------------------------- | 165 | | registerListener | 增加 TRTCCalling 监听器,用户可以通过该监听器获取状态通知 | 166 | | unRegisterListener | 移除监听器 | 167 | | destroy | 销毁实例 | 168 | | login | 登录 IM,所有功能需要先进行登录后才能使用 | 169 | | logout | 登出 IM,登出后无法再进行拨打操作 | 170 | | call | C2C 邀请通话,被邀请方会收到 onInvited 的事件通知 | 171 | | accept | 作为被邀请方接听来电 | 172 | | reject | 作为被邀请方拒绝来电 | 173 | | hangup | 结束通话 | 174 | | setMicMute | 是否静音 mic | 175 | | setHandsFree | 是否开启免提 | 176 | 177 | -------------------------------------------------------------------------------- /TRTCCallingVideo.md: -------------------------------------------------------------------------------- 1 | ## 实时视频通话(Flutter) 2 | 3 | 如需快速实现视频通话功能,您可以直接基于我们提供的 Demo 进行修改适配,也可以使用我们提供的 TRTCCalling 组件并实现自定义 UI 界面。 4 | 5 | ## 复用 Demo 的 UI 界面 6 | 7 | ### 步骤1:创建新的应用 8 | 1. 登录实时音视频控制台,选择【开发辅助】>【[快速跑通Demo](https://console.cloud.tencent.com/trtc/quickstart)】。 9 | 2. 输入应用名称,例如 `TestVideoCall` ,单击【创建】。 10 | 11 | >!本功能同时使用了腾讯云 [实时音视频 TRTC](https://cloud.tencent.com/document/product/647/16788) 和 [即时通信 IM](https://cloud.tencent.com/document/product/269) 两个基础 PaaS 服务,开通实时音视频后会同步开通即时通信 IM 服务。 即时通信 IM 属于增值服务,详细计费规则请参见 [即时通信 IM 价格说明](https://cloud.tencent.com/document/product/269/11673)。 12 | 13 | 14 | [](id:ui.step2) 15 | ### 步骤2:下载 SDK 和 Demo 源码 16 | 1. 根据实际业务需求下载 SDK 及配套的 Demo 源码。 17 | 2. 下载完成后,单击【已下载,下一步】。 18 | ![](https://main.qcloudimg.com/raw/3b115019ddfd0866108ed1add30810d8.png) 19 | 20 | [](id:ui.step3) 21 | ### 步骤3:配置 Demo 工程文件 22 | 1. 进入修改配置页,根据您下载的源码包,选择相应的开发环境。 23 | 2. 找到并打开 `/lib/debug/GenerateTestUserSig.dart` 文件。 24 | 3. 设置 `GenerateTestUserSig.dart` 文件中的相关参数: 25 |
  • SDKAPPID:默认为0,请设置为实际的 SDKAppID。 26 |
  • SECRETKEY:默认为空字符串,请设置为实际的密钥信息。
27 | 28 | 4. 粘贴完成后,单击【已复制粘贴,下一步】即创建成功。 29 | 5. 编译完成后,单击【回到控制台概览】即可。 30 | 31 | >! 32 | >- 本文提到的生成 UserSig 的方案是在客户端代码中配置 SECRETKEY,该方法中 SECRETKEY 很容易被反编译逆向破解,一旦您的密钥泄露,攻击者就可以盗用您的腾讯云流量,因此**该方法仅适合本地跑通 Demo 和功能调试**。 33 | >- 正确的 UserSig 签发方式是将 UserSig 的计算代码集成到您的服务端,并提供面向 App 的接口,在需要 UserSig 时由您的 App 向业务服务器发起请求获取动态 UserSig。更多详情请参见 [服务端生成 UserSig](https://cloud.tencent.com/document/product/647/17275#Server)。 34 | 35 | [](id:ui.step4) 36 | 37 | ### 步骤4:运行 Demo 38 | >! 安卓需要在真机下运行,不支持模拟器调试。 39 | 40 | 1. 执行 `flutter pub get`。 41 | 2. 编译运行调试: 42 | 43 | ::: Android\s端 44 | 1. 执行 `flutter run`。 45 | 2. 使用 Android Studio(3.5及以上的版本)打开源码工程,单击【运行】即可。 46 | ::: 47 | ::: iOS\s端 48 | 1. 使用 XCode(11.0及以上的版本)打开源码目录下的 `/ios工程`。 49 | 2. 编译并运行 Demo 工程即可。 50 | ::: 51 | 52 | 53 | 54 | [](id:ui.step5) 55 | 56 | ### 步骤5:修改 Demo 源代码 57 | 58 | 源码文件夹 `TRTCCallingDemo` 中包含两个子文件夹 ui 和 model,其中 ui 文件夹中均为界面代码: 59 | 60 | | 文件或文件夹 | 功能描述 | 61 | | -------------------------------- | ------------------------------------------------------------ | 62 | | TRTCCallingVideo.dart |展示音视频通话的主界面,通话的接听和拒绝就是在这个界面中完成的。 | 63 | | TRTCCallingContact.dart | 用于展示选择联系人的界面,可以通过此界面搜索已注册用户,发起通话。 | 64 | 65 | [](id:model) 66 | 67 | ## 实现自定义 UI 界面 68 | 69 | [源码](https://github.com/tencentyun/TRTCFlutterScenesDemo) 文件夹 `TRTCCallingDemo` 中包含两个子文件夹 ui 和 model,其中 model 文件夹中包含了我们实现的可重用开源组件 TRTCCalling,您可以在 `TRTCCalling.dart` 文件中看到该组件提供的接口函数。 70 | ![](https://main.qcloudimg.com/raw/36220937e8689dac4499ce9f2f187889.png) 71 | 72 | 您可以使用开源组件 TRTCCalling 实现自己的 UI 界面,即只复用 model 部分,自行实现 UI 部分。 73 | 74 | [](id:model.step1) 75 | 76 | ### 步骤1:集成 SDK 77 | 音视频通话组件 TRTCCalling 依赖 [TRTC SDK](https://pub.dev/packages/tencent_trtc_cloud) 和 [IM SDK](https://pub.dev/packages/tencent_im_sdk_plugin),您可以通过配置 `pubspec.yaml` 自动下载更新。 78 | 1. 在项目的 `pubspec.yaml` 中写如下依赖: 79 | ``` 80 | dependencies: 81 | tencent_trtc_cloud: 最新版本号 82 | tencent_im_sdk_plugin: 最新版本号 83 | ``` 84 | 85 | [](id:model.step2) 86 | ### 步骤2:配置权限及混淆规则 87 | 88 | ::: iOS端 89 | 1. 需要在 `Info.plist` 中加入对相机和麦克风的权限申请: 90 | ``` 91 | NSMicrophoneUsageDescription 92 | 授权麦克风权限才能正常语音通话 93 | ``` 94 | ::: 95 | ::: Android端 96 | 1. 打开 `/android/app/src/main/AndroidManifest.xml` 文件。 97 | 2. 将 `xmlns:tools="http://schemas.android.com/tools"` 加入到 manifest 中。 98 | 3. 将 `tools:replace="android:label"` 加入到 application 中。 99 | >? 若不执行此步,会出现 [Android Manifest merge failed 编译失败](https://cloud.tencent.com/document/product/647/51623#que6) 问题。 100 | 101 | 102 | ![图示](https://main.qcloudimg.com/raw/7a37917112831488423c1744f370c883.png) 103 | ::: 104 | 105 | 106 | 107 | [](id:model.step3) 108 | 109 | ### 步骤3:导入 TRTCCalling 组件 110 | 111 | 拷贝以下目录中的所有文件到您的项目中: 112 | 113 | ``` 114 | /lib/TRTCCallingDemo/model 115 | ``` 116 | 117 | [](id:model.step4) 118 | 119 | ### 步骤4:初始化并登录组件 120 | 121 | 1. 调用 `TRTCCalling.sharedInstance()` 获取组件实例。 122 | 2. 调用 `login(SDKAppID, userId, userSig)` 完成组件的登录,其中几个关键参数的填写请参考下表: 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 |
参数名作用
SDKAppID您可以在 实时音视频控制台 中查看 SDKAppID。
userId当前用户的 ID,字符串类型,只允许包含英文字母(a-z 和 A-Z)、数字(0-9)、连词符(-)和下划线(_)。
userSig腾讯云设计的一种安全保护签名,计算方式请参考 如何计算 UserSig
135 | 136 | ::: java 137 | // 初始化 138 | sCall = await TRTCCalling.sharedInstance(); 139 | sCall.login(1400000123, "userA", "xxxx"); 140 | ::: 141 | 142 | 143 | [](id:model.step5) 144 | 145 | ### 步骤5:实现 1v1 视频通话 146 | 147 | 1. 发起方:调用 `TRTCCalling` 的 `call()` 方法发起通话的请求, 并传入用户 ID(userid)和通话类型(type),通话类型参数传入`TRTCCalling.typeVideoCall`。 148 | 2. 接收方:当接收方处于已登录状态时,会收到名为 `onInvited()` 的事件通知,回调中 `callType` 的参数是发起方填写的通话类型,您可以通过此参数启动相应的界面。 149 | 3. 接收方:如果希望接听电话,接收方可以调用 `accept()` 函数,并同时调用 `openCamera()` 函数打开自己本地的摄像头。接收方也可以调用 `reject()` 拒绝此次通话。 150 | 4. 当双方的音视频通道建立完成后,通话的双方都会接收到名为 `onUserVideoAvailable()` 的事件通知,表示对方的视频画面已经拿到。此时双方用户均可以调用`startRemoteView()` 展示远端的视频画面。远端的声音默认是自动播放的。 151 | 152 | [](id:model.offline) 153 | 154 | ### 步骤6:实现离线接听 155 | 离线接听暂不支持,计划在6月中旬支持 156 | 157 | [](id:api) 158 | 159 | ## 组件 API 列表 160 | 161 | TRTCCalling 组件的 API 接口列表如下: 162 | 163 | | 接口函数 | 接口功能 | 164 | | --------------- | --------------------------------------------------------- | 165 | | registerListener | 增加 TRTCCalling 监听器,用户可以通过该监听器获取状态通知 | 166 | | unRegisterListener | 移除监听器 | 167 | | destroy | 销毁实例 | 168 | | login | 登录 IM,所有功能需要先进行登录后才能使用 | 169 | | logout | 登出 IM,登出后无法再进行拨打操作 | 170 | | call | C2C 邀请通话,被邀请方会收到 onInvited 的事件通知 | 171 | | accept | 作为被邀请方接听来电 | 172 | | reject | 作为被邀请方拒绝来电 | 173 | | hangup | 结束通话 | 174 | | startRemoteView | 将远端用户的摄像头数据渲染到指定的 TXCloudVideoView 中 | 175 | | stopRemoteView | 停止渲染某个远端用户的摄像头数据 | 176 | | openCamera | 开启摄像头,并渲染在指定的 TXCloudVideoView 中 | 177 | | closeCamera | 关闭摄像头 | 178 | | switchCamera | 切换前后摄像头 | 179 | | setMicMute | 是否静音 mic | 180 | | setHandsFree | 是否开启免提 | 181 | 182 | -------------------------------------------------------------------------------- /lib/index.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import './utils/TxUtils.dart'; 4 | import 'utils/constants.dart' as constants; 5 | import './debug/GenerateTestUserSig.dart'; 6 | import './TRTCChatSalonDemo/model/TRTCChatSalon.dart'; 7 | import './i10n/localization_intl.dart'; 8 | 9 | class IndexPage extends StatefulWidget { 10 | IndexPage({Key? key}) : super(key: key); 11 | 12 | @override 13 | State createState() => IndexPageState(); 14 | } 15 | 16 | class IndexPageState extends State { 17 | late TRTCChatSalon trtcVoiceRoom; 18 | @override 19 | void initState() { 20 | super.initState(); 21 | this.initSDK(); 22 | } 23 | 24 | initSDK() async { 25 | trtcVoiceRoom = await TRTCChatSalon.sharedInstance(); 26 | String userId = await TxUtils.getStorageByKey(constants.USERID_KEY); 27 | if (userId == '') { 28 | await Navigator.popAndPushNamed( 29 | context, 30 | "/login", 31 | ); 32 | } else { 33 | TxUtils.setStorageByKey(constants.USERID_KEY, userId); 34 | 35 | await trtcVoiceRoom.login( 36 | GenerateTestUserSig.sdkAppId, 37 | userId, 38 | GenerateTestUserSig.genTestSig(userId), 39 | ); 40 | } 41 | } 42 | 43 | Future? logout() { 44 | var showDialog2 = showDialog( 45 | context: context, 46 | builder: (context) { 47 | return AlertDialog( 48 | title: Text(Languages.of(context)!.tipsText), 49 | content: Text(Languages.of(context)!.logoutContent), 50 | actions: [ 51 | // ignore: deprecated_member_use 52 | FlatButton( 53 | child: Text(Languages.of(context)!.cancelText), 54 | onPressed: () => Navigator.of(context).pop(), // 关闭对话框 55 | ), 56 | // ignore: deprecated_member_use 57 | FlatButton( 58 | child: Text(Languages.of(context)!.okText), 59 | onPressed: () { 60 | //关闭对话框并返回true 61 | trtcVoiceRoom.logout(); 62 | TxUtils.setStorageByKey(constants.USERID_KEY, ''); 63 | Navigator.popAndPushNamed( 64 | context, 65 | "/login", 66 | ); 67 | }, 68 | ), 69 | ], 70 | ); 71 | }, 72 | ); 73 | return showDialog2; 74 | } 75 | 76 | goVoiceRoomDemo() { 77 | Navigator.pushReplacementNamed( 78 | context, 79 | "/chatSalon/list", 80 | ); 81 | } 82 | 83 | goCallingDemo(isVideo) { 84 | Navigator.pushReplacementNamed( 85 | context, 86 | isVideo ? "/calling/videoContact" : "/calling/audioContact", 87 | ); 88 | } 89 | 90 | goLiveRoomDemo() { 91 | Navigator.pushReplacementNamed( 92 | context, 93 | "/liveRoom/list", 94 | ); 95 | } 96 | 97 | goMeetingDemo() { 98 | Navigator.pushReplacementNamed( 99 | context, 100 | "/meeting/meetingIndex", 101 | ); 102 | } 103 | 104 | Widget getTitleItem(String title, String imgUrl, Function onTap) { 105 | var titleItem = Container( 106 | height: 80.0, 107 | color: Color.fromRGBO(30, 57, 103, 1), 108 | width: double.infinity, 109 | child: Row( 110 | children: [ 111 | Expanded( 112 | flex: 1, 113 | child: InkWell( 114 | onTap: () { 115 | onTap(); 116 | }, 117 | child: Column( 118 | mainAxisAlignment: MainAxisAlignment.center, 119 | crossAxisAlignment: CrossAxisAlignment.center, 120 | children: [ 121 | Image.asset( 122 | imgUrl, 123 | height: 44, 124 | width: 44, 125 | ), 126 | Container( 127 | margin: EdgeInsets.only(top: 20), 128 | child: Text( 129 | title, 130 | style: TextStyle( 131 | color: Colors.white, 132 | fontSize: 18.0, 133 | fontWeight: FontWeight.bold, 134 | ), 135 | ), 136 | ), 137 | ], 138 | ), 139 | )), 140 | ], 141 | ), 142 | ); 143 | return titleItem; 144 | } 145 | 146 | @override 147 | Widget build(BuildContext context) { 148 | return Scaffold( 149 | appBar: AppBar( 150 | leading: IconButton( 151 | icon: Icon(Icons.person), 152 | tooltip: Languages.of(context)!.logout, 153 | onPressed: () async { 154 | await logout(); 155 | }, 156 | ), 157 | title: Text(Languages.of(context)!.trtc), 158 | centerTitle: true, 159 | elevation: 0, 160 | backgroundColor: Color.fromRGBO(14, 25, 44, 1), 161 | ), 162 | body: Container( 163 | decoration: BoxDecoration( 164 | image: new DecorationImage( 165 | image: new AssetImage( 166 | "assets/images/bg_main_title.png", 167 | ), 168 | alignment: Alignment.topCenter, 169 | ), 170 | gradient: LinearGradient( 171 | begin: Alignment.topRight, 172 | end: Alignment.bottomLeft, 173 | stops: [0.0, 1.0], 174 | colors: [ 175 | Color.fromRGBO(19, 41, 75, 1), 176 | Color.fromRGBO(0, 0, 0, 1), 177 | ], 178 | ), 179 | ), 180 | padding: EdgeInsets.only(top: 180, left: 20, right: 20), 181 | child: GridView( 182 | padding: EdgeInsets.only(bottom: 20), 183 | gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( 184 | crossAxisCount: 2, mainAxisSpacing: 30, crossAxisSpacing: 30), 185 | children: [ 186 | this.getTitleItem( 187 | Languages.of(context)!.salonTitle, 188 | "assets/images/ChatSalon.png", 189 | () { 190 | goVoiceRoomDemo(); 191 | }, 192 | ), 193 | this.getTitleItem( 194 | "视频通话", 195 | "assets/images/callingDemo/videoCall.png", 196 | () { 197 | goCallingDemo(true); 198 | }, 199 | ), 200 | this.getTitleItem( 201 | "语音通话", 202 | "assets/images/callingDemo/audioCall.png", 203 | () { 204 | goCallingDemo(false); 205 | }, 206 | ), 207 | this.getTitleItem( 208 | "视频互动", 209 | "assets/images/callingDemo/videoCall.png", 210 | () { 211 | goLiveRoomDemo(); 212 | }, 213 | ), 214 | this.getTitleItem( 215 | Languages.of(context)!.meetingCallTitle, 216 | "assets/images/callingDemo/meetingCall.png", 217 | () { 218 | goMeetingDemo(); 219 | }, 220 | ), 221 | ], 222 | ), 223 | ), 224 | ); 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /i10n-arb/intl_zh_CN.arb: -------------------------------------------------------------------------------- 1 | { 2 | "@@last_modified": "2021-03-12T16:39:52.953569", 3 | "trtc": "TRTC", 4 | "@trtc": { 5 | "type": "text", 6 | "placeholders": {} 7 | }, 8 | "logout": "退出", 9 | "@logout": { 10 | "type": "text", 11 | "placeholders": {} 12 | }, 13 | "salonTitle": "语音沙龙", 14 | "@salonTitle": { 15 | "type": "text", 16 | "placeholders": {} 17 | }, 18 | "titleTRTC": "TRTC", 19 | "@titleTRTC": { 20 | "type": "text", 21 | "placeholders": {} 22 | }, 23 | "login": "登录", 24 | "@login": { 25 | "type": "text", 26 | "placeholders": {} 27 | }, 28 | "okText": "确定", 29 | "@okText": { 30 | "type": "text", 31 | "placeholders": {} 32 | }, 33 | "cancelText": "取消", 34 | "@cancelText": { 35 | "type": "text", 36 | "placeholders": {} 37 | }, 38 | "tipsText": "提示", 39 | "@tipsText": { 40 | "type": "text", 41 | "placeholders": {} 42 | }, 43 | "logoutContent": "确定退出登录吗?", 44 | "@logoutContent": { 45 | "type": "text", 46 | "placeholders": {} 47 | }, 48 | "errorUserIDInput": "请输入用户ID", 49 | "@errorUserIDInput": { 50 | "type": "text", 51 | "placeholders": {} 52 | }, 53 | "errorUserIDNumber": "用户ID必须为数字", 54 | "@errorUserIDNumber": { 55 | "type": "text", 56 | "placeholders": {} 57 | }, 58 | "successLogin": "登录成功", 59 | "@successLogin": { 60 | "type": "text", 61 | "placeholders": {} 62 | }, 63 | "tencentTRTC": "腾讯云TRTC", 64 | "@tencentTRTC": { 65 | "type": "text", 66 | "placeholders": {} 67 | }, 68 | "userIDLabel": "用户ID", 69 | "@userIDLabel": { 70 | "type": "text", 71 | "placeholders": {} 72 | }, 73 | "userIDHintText": "请输入登录的UserID", 74 | "@userIDHintText": { 75 | "type": "text", 76 | "placeholders": {} 77 | }, 78 | "errorOpenUrl": "打开地址失败", 79 | "@errorOpenUrl": { 80 | "type": "text", 81 | "placeholders": {} 82 | }, 83 | "helpTooltip": "查看说明文档", 84 | "@helpTooltip": { 85 | "type": "text", 86 | "placeholders": {} 87 | }, 88 | "refreshText": "下拉刷新", 89 | "@refreshText": { 90 | "type": "text", 91 | "placeholders": {} 92 | }, 93 | "refreshReadyText": "准备刷新数据", 94 | "@refreshReadyText": { 95 | "type": "text", 96 | "placeholders": {} 97 | }, 98 | "refreshingText": "正在刷新中...", 99 | "@refreshingText": { 100 | "type": "text", 101 | "placeholders": {} 102 | }, 103 | "refreshedText": "刷新完成", 104 | "@refreshedText": { 105 | "type": "text", 106 | "placeholders": {} 107 | }, 108 | "noHadSalon": "暂无语音沙龙", 109 | "@noHadSalon": { 110 | "type": "text", 111 | "placeholders": {} 112 | }, 113 | "onLineCount": "{memberCount}人在线", 114 | "@onLineCount": { 115 | "type": "text", 116 | "placeholders": { 117 | "memberCount": {} 118 | } 119 | }, 120 | "defaultChatTitle": "{userName}的主题", 121 | "@defaultChatTitle": { 122 | "type": "text", 123 | "placeholders": { 124 | "userName": {} 125 | } 126 | }, 127 | "errorsdkAppId": "请填写SDKAPPID", 128 | "@errorsdkAppId": { 129 | "type": "text", 130 | "placeholders": {} 131 | }, 132 | "errorSecretKey": "请填写密钥", 133 | "@errorSecretKey": { 134 | "type": "text", 135 | "placeholders": {} 136 | }, 137 | "errorMeetTitle": "请输入房间主题", 138 | "@errorMeetTitle": { 139 | "type": "text", 140 | "placeholders": {} 141 | }, 142 | "errorMeetTitleLength": "房间主题过长,请输入合法的房间主题", 143 | "@errorMeetTitleLength": { 144 | "type": "text", 145 | "placeholders": {} 146 | }, 147 | "errorUserName": "请输入用户名", 148 | "@errorUserName": { 149 | "type": "text", 150 | "placeholders": {} 151 | }, 152 | "errorUserNameLength": "用户名过长,请输入合法的用户名", 153 | "@errorUserNameLength": { 154 | "type": "text", 155 | "placeholders": {} 156 | }, 157 | "errorMicrophonePermission": "需要获取音视频权限才能进入", 158 | "@errorMicrophonePermission": { 159 | "type": "text", 160 | "placeholders": {} 161 | }, 162 | "createSalonTooltip": "创建语音沙龙", 163 | "@createSalonTooltip": { 164 | "type": "text", 165 | "placeholders": {} 166 | }, 167 | "meetTitleLabel": "主题", 168 | "@meetTitleLabel": { 169 | "type": "text", 170 | "placeholders": {} 171 | }, 172 | "meetTitleHintText": "请输入房间名称", 173 | "@meetTitleHintText": { 174 | "type": "text", 175 | "placeholders": {} 176 | }, 177 | "userNameLabel": "用户名", 178 | "@userNameLabel": { 179 | "type": "text", 180 | "placeholders": {} 181 | }, 182 | "userNameHintText": "请输入用户名", 183 | "@userNameHintText": { 184 | "type": "text", 185 | "placeholders": {} 186 | }, 187 | "startSalon": "开始交谈", 188 | "@startSalon": { 189 | "type": "text", 190 | "placeholders": {} 191 | }, 192 | "failEnterRoom": "进房失败", 193 | "@failEnterRoom": { 194 | "type": "text", 195 | "placeholders": {} 196 | }, 197 | "failKickedOffline": "已在其他地方登陆,请重新登录", 198 | "@failKickedOffline": { 199 | "type": "text", 200 | "placeholders": {} 201 | }, 202 | "failRoomDestroy": "沙龙已结束。", 203 | "@failRoomDestroy": { 204 | "type": "text", 205 | "placeholders": {} 206 | }, 207 | "failRefuseToSpeak": "抱歉,管理员没有同意您上麦", 208 | "@failRefuseToSpeak": { 209 | "type": "text", 210 | "placeholders": {} 211 | }, 212 | "userRaiseHand": "{userName}申请成为主播", 213 | "@userRaiseHand": { 214 | "type": "text", 215 | "placeholders": { 216 | "userName": {} 217 | } 218 | }, 219 | "hadKickMic": "你已被主播踢下麦", 220 | "@hadKickMic": { 221 | "type": "text", 222 | "placeholders": {} 223 | }, 224 | "successCreateRoom": "房间创建成功。", 225 | "@successCreateRoom": { 226 | "type": "text", 227 | "placeholders": {} 228 | }, 229 | "successEnterRoom": "进房成功", 230 | "@successEnterRoom": { 231 | "type": "text", 232 | "placeholders": {} 233 | }, 234 | "successAdminEnterRoom": "房主占座成功。", 235 | "@successAdminEnterRoom": { 236 | "type": "text", 237 | "placeholders": {} 238 | }, 239 | "successRaiseHand": "举手成功!等待管理员通过~", 240 | "@successRaiseHand": { 241 | "type": "text", 242 | "placeholders": {} 243 | }, 244 | "adminLeaveRoomTips": "离开会解散房间,确定离开吗?", 245 | "@adminLeaveRoomTips": { 246 | "type": "text", 247 | "placeholders": {} 248 | }, 249 | "leaveRoomTips": "确定离开房间吗?", 250 | "@leaveRoomTips": { 251 | "type": "text", 252 | "placeholders": {} 253 | }, 254 | "waitTips": "再等等", 255 | "@waitTips": { 256 | "type": "text", 257 | "placeholders": {} 258 | }, 259 | "iSure": "我确定", 260 | "@iSure": { 261 | "type": "text", 262 | "placeholders": {} 263 | }, 264 | "welcome": "欢迎", 265 | "@welcome": { 266 | "type": "text", 267 | "placeholders": {} 268 | }, 269 | "ignore": "忽略", 270 | "@ignore": { 271 | "type": "text", 272 | "placeholders": {} 273 | }, 274 | "anchor": "主播", 275 | "@anchor": { 276 | "type": "text", 277 | "placeholders": {} 278 | }, 279 | "audience": "听众", 280 | "@audience": { 281 | "type": "text", 282 | "placeholders": {} 283 | }, 284 | "kickMic": "要求下麦", 285 | "@kickMic": { 286 | "type": "text", 287 | "placeholders": {} 288 | }, 289 | "raiseUpList": "举手列表", 290 | "@raiseUpList": { 291 | "type": "text", 292 | "placeholders": {} 293 | }, 294 | "leaveTips": "安静离开~", 295 | "@leaveTips": { 296 | "type": "text", 297 | "placeholders": {} 298 | } 299 | } -------------------------------------------------------------------------------- /i10n-arb/intl_messages.arb: -------------------------------------------------------------------------------- 1 | { 2 | "@@last_modified": "2021-03-12T16:39:52.953569", 3 | "trtc": "TRTC", 4 | "@trtc": { 5 | "type": "text", 6 | "placeholders": {} 7 | }, 8 | "logout": "退出", 9 | "@logout": { 10 | "type": "text", 11 | "placeholders": {} 12 | }, 13 | "salonTitle": "语音沙龙", 14 | "@salonTitle": { 15 | "type": "text", 16 | "placeholders": {} 17 | }, 18 | "titleTRTC": "TRTC", 19 | "@titleTRTC": { 20 | "type": "text", 21 | "placeholders": {} 22 | }, 23 | "login": "登录", 24 | "@login": { 25 | "type": "text", 26 | "placeholders": {} 27 | }, 28 | "okText": "确定", 29 | "@okText": { 30 | "type": "text", 31 | "placeholders": {} 32 | }, 33 | "cancelText": "取消", 34 | "@cancelText": { 35 | "type": "text", 36 | "placeholders": {} 37 | }, 38 | "tipsText": "提示", 39 | "@tipsText": { 40 | "type": "text", 41 | "placeholders": {} 42 | }, 43 | "logoutContent": "确定退出登录吗?", 44 | "@logoutContent": { 45 | "type": "text", 46 | "placeholders": {} 47 | }, 48 | "errorUserIDInput": "请输入用户ID", 49 | "@errorUserIDInput": { 50 | "type": "text", 51 | "placeholders": {} 52 | }, 53 | "errorUserIDNumber": "用户ID必须为数字", 54 | "@errorUserIDNumber": { 55 | "type": "text", 56 | "placeholders": {} 57 | }, 58 | "successLogin": "登录成功", 59 | "@successLogin": { 60 | "type": "text", 61 | "placeholders": {} 62 | }, 63 | "tencentTRTC": "腾讯云TRTC", 64 | "@tencentTRTC": { 65 | "type": "text", 66 | "placeholders": {} 67 | }, 68 | "userIDLabel": "用户ID", 69 | "@userIDLabel": { 70 | "type": "text", 71 | "placeholders": {} 72 | }, 73 | "userIDHintText": "请输入登录的UserID", 74 | "@userIDHintText": { 75 | "type": "text", 76 | "placeholders": {} 77 | }, 78 | "errorOpenUrl": "打开地址失败", 79 | "@errorOpenUrl": { 80 | "type": "text", 81 | "placeholders": {} 82 | }, 83 | "helpTooltip": "查看说明文档", 84 | "@helpTooltip": { 85 | "type": "text", 86 | "placeholders": {} 87 | }, 88 | "refreshText": "下拉刷新", 89 | "@refreshText": { 90 | "type": "text", 91 | "placeholders": {} 92 | }, 93 | "refreshReadyText": "准备刷新数据", 94 | "@refreshReadyText": { 95 | "type": "text", 96 | "placeholders": {} 97 | }, 98 | "refreshingText": "正在刷新中...", 99 | "@refreshingText": { 100 | "type": "text", 101 | "placeholders": {} 102 | }, 103 | "refreshedText": "刷新完成", 104 | "@refreshedText": { 105 | "type": "text", 106 | "placeholders": {} 107 | }, 108 | "noHadSalon": "暂无语音沙龙", 109 | "@noHadSalon": { 110 | "type": "text", 111 | "placeholders": {} 112 | }, 113 | "onLineCount": "{memberCount}人在线", 114 | "@onLineCount": { 115 | "type": "text", 116 | "placeholders": { 117 | "memberCount": {} 118 | } 119 | }, 120 | "defaultChatTitle": "{userName}的主题", 121 | "@defaultChatTitle": { 122 | "type": "text", 123 | "placeholders": { 124 | "userName": {} 125 | } 126 | }, 127 | "errorsdkAppId": "请填写SDKAPPID", 128 | "@errorsdkAppId": { 129 | "type": "text", 130 | "placeholders": {} 131 | }, 132 | "errorSecretKey": "请填写密钥", 133 | "@errorSecretKey": { 134 | "type": "text", 135 | "placeholders": {} 136 | }, 137 | "errorMeetTitle": "请输入房间主题", 138 | "@errorMeetTitle": { 139 | "type": "text", 140 | "placeholders": {} 141 | }, 142 | "errorMeetTitleLength": "房间主题过长,请输入合法的房间主题", 143 | "@errorMeetTitleLength": { 144 | "type": "text", 145 | "placeholders": {} 146 | }, 147 | "errorUserName": "请输入用户名", 148 | "@errorUserName": { 149 | "type": "text", 150 | "placeholders": {} 151 | }, 152 | "errorUserNameLength": "用户名过长,请输入合法的用户名", 153 | "@errorUserNameLength": { 154 | "type": "text", 155 | "placeholders": {} 156 | }, 157 | "errorMicrophonePermission": "需要获取音视频权限才能进入", 158 | "@errorMicrophonePermission": { 159 | "type": "text", 160 | "placeholders": {} 161 | }, 162 | "createSalonTooltip": "创建语音沙龙", 163 | "@createSalonTooltip": { 164 | "type": "text", 165 | "placeholders": {} 166 | }, 167 | "meetTitleLabel": "主题", 168 | "@meetTitleLabel": { 169 | "type": "text", 170 | "placeholders": {} 171 | }, 172 | "meetTitleHintText": "请输入房间名称", 173 | "@meetTitleHintText": { 174 | "type": "text", 175 | "placeholders": {} 176 | }, 177 | "userNameLabel": "用户名", 178 | "@userNameLabel": { 179 | "type": "text", 180 | "placeholders": {} 181 | }, 182 | "userNameHintText": "请输入用户名", 183 | "@userNameHintText": { 184 | "type": "text", 185 | "placeholders": {} 186 | }, 187 | "startSalon": "开始交谈", 188 | "@startSalon": { 189 | "type": "text", 190 | "placeholders": {} 191 | }, 192 | "failEnterRoom": "进房失败", 193 | "@failEnterRoom": { 194 | "type": "text", 195 | "placeholders": {} 196 | }, 197 | "failKickedOffline": "已在其他地方登陆,请重新登录", 198 | "@failKickedOffline": { 199 | "type": "text", 200 | "placeholders": {} 201 | }, 202 | "failRoomDestroy": "沙龙已结束。", 203 | "@failRoomDestroy": { 204 | "type": "text", 205 | "placeholders": {} 206 | }, 207 | "failRefuseToSpeak": "抱歉,管理员没有同意您上麦", 208 | "@failRefuseToSpeak": { 209 | "type": "text", 210 | "placeholders": {} 211 | }, 212 | "userRaiseHand": "{userName}申请成为主播", 213 | "@userRaiseHand": { 214 | "type": "text", 215 | "placeholders": { 216 | "userName": {} 217 | } 218 | }, 219 | "hadKickMic": "你已被主播踢下麦", 220 | "@hadKickMic": { 221 | "type": "text", 222 | "placeholders": {} 223 | }, 224 | "successCreateRoom": "房间创建成功。", 225 | "@successCreateRoom": { 226 | "type": "text", 227 | "placeholders": {} 228 | }, 229 | "successEnterRoom": "进房成功", 230 | "@successEnterRoom": { 231 | "type": "text", 232 | "placeholders": {} 233 | }, 234 | "successAdminEnterRoom": "房主占座成功。", 235 | "@successAdminEnterRoom": { 236 | "type": "text", 237 | "placeholders": {} 238 | }, 239 | "successRaiseHand": "举手成功!等待管理员通过~", 240 | "@successRaiseHand": { 241 | "type": "text", 242 | "placeholders": {} 243 | }, 244 | "adminLeaveRoomTips": "离开会解散房间,确定离开吗?", 245 | "@adminLeaveRoomTips": { 246 | "type": "text", 247 | "placeholders": {} 248 | }, 249 | "leaveRoomTips": "确定离开房间吗?", 250 | "@leaveRoomTips": { 251 | "type": "text", 252 | "placeholders": {} 253 | }, 254 | "waitTips": "再等等", 255 | "@waitTips": { 256 | "type": "text", 257 | "placeholders": {} 258 | }, 259 | "iSure": "我确定", 260 | "@iSure": { 261 | "type": "text", 262 | "placeholders": {} 263 | }, 264 | "welcome": "欢迎", 265 | "@welcome": { 266 | "type": "text", 267 | "placeholders": {} 268 | }, 269 | "ignore": "忽略", 270 | "@ignore": { 271 | "type": "text", 272 | "placeholders": {} 273 | }, 274 | "anchor": "主播", 275 | "@anchor": { 276 | "type": "text", 277 | "placeholders": {} 278 | }, 279 | "audience": "听众", 280 | "@audience": { 281 | "type": "text", 282 | "placeholders": {} 283 | }, 284 | "kickMic": "要求下麦", 285 | "@kickMic": { 286 | "type": "text", 287 | "placeholders": {} 288 | }, 289 | "raiseUpList": "举手列表", 290 | "@raiseUpList": { 291 | "type": "text", 292 | "placeholders": {} 293 | }, 294 | "leaveTips": "安静离开~", 295 | "@leaveTips": { 296 | "type": "text", 297 | "placeholders": {} 298 | } 299 | } -------------------------------------------------------------------------------- /lib/TRTCChatSalonDemo/model/TRTCChatSalon.dart: -------------------------------------------------------------------------------- 1 | import 'package:tencent_trtc_cloud/tx_audio_effect_manager.dart'; 2 | import 'impl/TRTCChatSalonImpl.dart'; 3 | import 'TRTCChatSalonDef.dart'; 4 | 5 | abstract class TRTCChatSalon { 6 | /* 7 | * 获取 TRTCChatSalon 单例对象 8 | * 9 | * @return TRTCChatSalon 实例 10 | * @note 可以调用 {@link TRTCChatSalon.destroySharedInstance()} 销毁单例对象 11 | */ 12 | static Future sharedInstance() async { 13 | return TRTCChatSalonImpl.sharedInstance(); 14 | } 15 | 16 | /* 17 | * 销毁 TRTCChatSalon 单例对象 18 | * 19 | * @note 销毁实例后,外部缓存的 TRTCChatSalon 实例不能再使用,需要重新调用 {@link TRTCChatSalon.sharedInstance()} 获取新实例 20 | */ 21 | static void destroySharedInstance() async { 22 | TRTCChatSalonImpl.destroySharedInstance(); 23 | } 24 | 25 | ////////////////////////////////////////////////////////// 26 | // 27 | // 基础接口 28 | // 29 | ////////////////////////////////////////////////////////// 30 | /* 31 | * 设置组件事件监听接口 32 | * 33 | * 您可以通过 registerListener 获得 TRTCChatSalon 的各种状态通知 34 | * 35 | * @param VoiceListenerFunc func 回调接口 36 | */ 37 | void registerListener(VoiceListenerFunc func); 38 | 39 | /* 40 | * 移除组件事件监听接口 41 | */ 42 | void unRegisterListener(VoiceListenerFunc func); 43 | 44 | /* 45 | * 登录 46 | * 47 | * @param sdkAppId 您可以在实时音视频控制台 >【[应用管理](https://console.cloud.tencent.com/trtc/app)】> 应用信息中查看 SDKAppID 48 | * @param userId 当前用户的 ID,字符串类型,只允许包含英文字母(a-z 和 A-Z)、数字(0-9)、连词符(-)和下划线(\_) 49 | * @param userSig 腾讯云设计的一种安全保护签名,获取方式请参考 [如何计算 UserSig](https://cloud.tencent.com/document/product/647/17275)。 50 | * @param 返回值:成功时 code 为0 51 | */ 52 | Future login(int sdkAppId, String userId, String userSig); 53 | 54 | /* 55 | * 退出登录 56 | */ 57 | Future logout(); 58 | 59 | /* 60 | * 设置用户信息,您设置的用户信息会被存储于腾讯云 IM 云服务中。 61 | * 62 | * @param userName 用户昵称 63 | * @param avatarURL 用户头像 64 | */ 65 | Future setSelfProfile(String userName, String avatarURL); 66 | 67 | ////////////////////////////////////////////////////////// 68 | // 69 | // 房间管理接口 70 | // 71 | ////////////////////////////////////////////////////////// 72 | 73 | /* 74 | * 创建房间(房间创建者调用) 75 | * 76 | * @param roomId 房间标识,需要由您分配并进行统一管理。 77 | * @param roomParam 房间信息,用于房间描述的信息,例如房间名称,封面信息等。如果房间列表和房间信息都由您的服务器自行管理,可忽略该参数。 78 | * @param callback 创建房间的结果回调,成功时 code 为0. 79 | */ 80 | Future createRoom(int roomId, RoomParam roomParam); 81 | 82 | /* 83 | * 销毁房间(房间创建者调用) 84 | * 85 | * 主播在创建房间后,可以调用这个函数来销毁房间。 86 | */ 87 | Future destroyRoom(); 88 | 89 | /* 90 | * 进入房间(观众调用) 91 | * 92 | * @param roomId 房间标识 93 | */ 94 | Future enterRoom(int roomId); 95 | 96 | /* 97 | * 退出房间(观众调用) 98 | * 99 | */ 100 | Future exitRoom(); 101 | 102 | /* 103 | * 获取房间列表的详细信息 104 | * 105 | * 其中的信息是主播在创建 createRoom() 时通过 roomInfo 设置进来的,如果房间列表和房间信息都由您的服务器自行管理,此函数您可以不用关心。 106 | * 107 | * @param roomIdList 房间id列表 108 | */ 109 | Future getRoomInfoList(List roomIdList); 110 | 111 | /* 112 | * 获取指定userId的用户信息 113 | * @param userIdList 用户id列表 114 | */ 115 | Future getUserInfoList(List userIdList); 116 | 117 | // 获取房间内主播列表 118 | Future getArchorInfoList(); 119 | 120 | /* 121 | * 拉取房间内所有成员列表 122 | * @param nextSeq 分页拉取标志,第一次拉取填0,回调成功如果 nextSeq 不为零,需要分页,传入再次拉取,直至为0。 123 | */ 124 | Future getRoomMemberList(int nextSeq); 125 | 126 | /* 127 | * 拉取房间内所有在线成员总数 128 | */ 129 | Future getRoomOnlineMemberCount(); 130 | 131 | ////////////////////////////////////////////////////////// 132 | // 133 | // 麦位管理接口 134 | // 135 | ////////////////////////////////////////////////////////// 136 | 137 | /* 138 | * 观众申请上麦 139 | * 140 | * 上麦成功后,房间内所有成员会收到`onAnchorListChange`和`onAnchorEnterMic`的事件通知。 141 | */ 142 | void raiseHand(); 143 | 144 | /* 145 | * 群主同意上麦 146 | * 147 | * @param userId 148 | */ 149 | Future agreeToSpeak(String userId); 150 | 151 | /* 152 | * 群主拒绝上麦 153 | * 154 | * @param userId 155 | */ 156 | Future refuseToSpeak(String userId); 157 | 158 | /* 159 | * 上麦 160 | * 161 | * 上麦成功后,房间内所有成员会收到`onAnchorListChange`和`onAnchorEnterMic`的事件通知。 162 | */ 163 | Future enterMic(); 164 | 165 | /* 166 | * 主动下麦 167 | * 168 | * 下麦成功后,房间内所有成员会收到`onAnchorListChange`和`onAnchorLeaveMic`的事件通知。 169 | */ 170 | Future leaveMic(); 171 | 172 | /* 173 | * 静音/解除静音某个麦位(主播调用)。 174 | * 175 | * 改变麦位的状态后,房间内所有成员会收到`onAnchorListChange`和`onMicMute`的事件通知。 176 | * 177 | * @param mute: true:静音;false:取消静音 178 | */ 179 | Future muteMic(bool mute); 180 | 181 | /* 182 | * 踢人下麦(群主调用) 183 | * 184 | * 群主踢人下麦,房间内所有成员会收到`onAnchorListChange`和`onAnchorLeaveMic`的事件通知。 185 | * 186 | * @param userId 需要踢下麦的用户id 187 | */ 188 | Future kickMic(String userId); 189 | 190 | ////////////////////////////////////////////////////////// 191 | // 192 | // 本地音频操作接口 193 | // 194 | ////////////////////////////////////////////////////////// 195 | /* 196 | * 开启麦克风采集 197 | * 198 | * @param quality 声音音质 199 | * 200 | * TRTCCloudDef.TRTC_AUDIO_QUALITY_SPEECH, 流畅:采样率:16k;单声道;音频裸码率:16kbps;适合语音通话为主的场景,比如在线会议,语音通话。 201 | * TRTCCloudDef.TRTC_AUDIO_QUALITY_DEFAULT,默认:采样率:48k;单声道;音频裸码率:50kbps;SDK 默认的音频质量,如无特殊需求推荐选择之。 202 | * TRTCCloudDef.TRTC_AUDIO_QUALITY_MUSIC,高音质:采样率:48k;双声道 + 全频带;音频裸码率:128kbps;适合需要高保真传输音乐的场景,比如K歌、音乐直播等。 203 | */ 204 | void startMicrophone(int quality); 205 | 206 | /* 207 | * 停止麦克风采集 208 | */ 209 | void stopMicrophone(); 210 | 211 | /* 212 | * 开启本地静音 213 | * @param mute 是否静音 214 | */ 215 | void muteLocalAudio(bool mute); 216 | 217 | /* 218 | * 设置开启扬声器 219 | * @param useSpeaker true:扬声器 false:听筒 220 | */ 221 | void setSpeaker(bool useSpeaker); 222 | 223 | /* 224 | * 设置麦克风采集音量 225 | * @param volume 采集音量 0-100 226 | */ 227 | void setAudioCaptureVolume(int volume); 228 | 229 | /* 230 | * 设置播放音量 231 | * @param volume 播放音量 0-100 232 | */ 233 | void setAudioPlayoutVolume(int volume); 234 | 235 | ////////////////////////////////////////////////////////// 236 | // 237 | // 远端用户接口 238 | // 239 | ////////////////////////////////////////////////////////// 240 | /* 241 | * 静音某一个用户的声音 242 | * 243 | * @param userId 用户id 244 | * @param mute true:静音 false:解除静音 245 | */ 246 | void muteRemoteAudio(String userId, bool mute); 247 | 248 | /* 249 | * 静音所有用户的声音 250 | * 251 | * @param mute true:静音 false:解除静音 252 | */ 253 | void muteAllRemoteAudio(bool mute); 254 | 255 | ////////////////////////////////////////////////////////// 256 | // 257 | // 背景音乐音效相关接口函数 258 | // 259 | ////////////////////////////////////////////////////////// 260 | 261 | /* 262 | * 音效控制相关 263 | */ 264 | TXAudioEffectManager getAudioEffectManager(); 265 | 266 | ////////////////////////////////////////////////////////// 267 | // 268 | // 消息发送接口 269 | // 270 | ////////////////////////////////////////////////////////// 271 | 272 | /* 273 | * 在房间中广播文本消息,一般用于弹幕聊天 274 | * @param message 文本消息 275 | */ 276 | Future sendRoomTextMsg(String message); 277 | } 278 | --------------------------------------------------------------------------------