说明:
第一步:依赖替换:
tencent_trtc_cloud: 2.5.2
替换为
agora_rtc_engine: ^6.0.0
在 lib\Base.dart 中定义全局变量:
static TRTCCloud? trtcCloud;
实现了一个销毁 trtc 的方法:
static Future<void> destroyTrtcCloud() async { print('销毁语音插件'); VBase.roomId = 0; VBase.trtcCloud = null; await VBase.trtcCloud?.stopLocalAudio(); await VBase.trtcCloud?.exitRoom(); await TRTCCloud.destroySharedInstance(); }
这里将直播间id清空,trtc设置为null等操作。
在 lib\service.dart 中定义exitRoom操作,和上面 VBase 类一样:
abstract class VRoom { static TRTCCloud? trtcCloud; static bool trtcCloudIsActive = false; static Future<void> exitRoom(String name) async { if (VRoom.trtcCloudIsActive) { // VRoom.trtcCloud.unRegisterListener(onTrtcListener); await VRoom.trtcCloud?.stopLocalAudio(); await VRoom.trtcCloud?.exitRoom(); await TRTCCloud.destroySharedInstance(); print('销毁房间语音信息'); } } }
注意这里VRoom类中定义的 exitRoom 和 destroyTrtcCloud 方法类似,可能重复了。
在 lib\chat\PlayerWidget.dart 中,这里定义了trtcCloud 和 player:
final TXAudioEffectManager player; final TRTCCloud trtcCloud; bool get _isPlaying => _playerState == PlayerState.playing;// 播放中 bool get _isPaused => _playerState == PlayerState.paused; // 暂停
player直播间播放音乐的插件,
//先检测是否有音乐 var isHavData = await VStore.hasData('music'); //有音乐,设置音乐播放列表 if(isHavData){ var data = await VStore.getData('music'); setState(() { _fileList = data['list'] as List<dynamic>; _fileIndex = data['index']; }); // play(_fileIndex); }
player.seekMusicToPosInMS(_musicId, position.round());
设置音量:
player.setAllMusicVolume((_volume * 100).toInt());
播放下一首,先停止,在播放:
_playNextMusic() async { if(tabs[0]['list'].length > 0) { setState(() { if (_fileIndex < tabs[0]['list'].length - 1) { _fileIndex++; }else{ _fileIndex = 0; } _position = const Duration(milliseconds: 0); }); await player.stopPlayMusic(_musicId); print('播放1:${_fileIndex}'); play(_fileIndex); } }
注意,直播时候 trtcCloud 注册音乐播放器监听器 onTrtcListener:
void _initStreams() { trtcCloud?.registerListener(onTrtcListener); }
这个 trtcCloud 在直播间页面调用播放音乐插件时候传入,接下来着重看一下直播间页面。
直播间页面 lib\chat\VoiceChatRoomPage.dart
late TRTCCloud trtcCloud; late bool trtcCloudIsActive = false; // 定义原生方法 MethodChannel _channel = const MethodChannel('trtcCloudChannel');
调用sdk,配置appid等参数,新建一个 trtcCloud 对象:
trtcCloud = (await TRTCCloud.sharedInstance())!;
进入直播间逻辑:
注意在调用 VoiceChatRoomPage 进入直播间会传递参数:
{'room_id': roomId, 'data': result['data']}
一个是直播间id,而 data 参数,在进入直播间之前先调用后台post接口:
var result = await VService.enterRoom( roomId: roomId.toString(), password: message); static Future<Map<String, dynamic>?> enterRoom( {required String roomId, String password = ''}) async { var res = await httpClient.post( API.enterRoom, //'/api/voice/enterRoom'; data: FormData.fromMap({ 'room_id': roomId, 'password': password, }), ); var result = await VService.getRoomStatus(roomId.toString()); static Future<dynamic> getRoomStatus(String roomId) async { var res = await httpClient.post( API.getRoomStatus, // '/api/voice/getRoomStatus'; data: FormData.fromMap({ 'room_id': roomId, }), ); return res.data; }
直播间角色:
? TRTCCloudDef.TRTCRoleAnchor 节目主持人,即主播 : TRTCCloudDef.TRTCRoleAudience; 观众
调用 _fluWakeLock 实例的 enable 方法,用于启用设备的唤醒锁。启用唤醒锁可以防止设备在应用程序处于活动状态时进入睡眠模式,保持设备的唤醒状态,以确保应用程序可以继续运行或执行某些特定的任务。
_fluWakeLock
enable
FluWakeLock _fluWakeLock = FluWakeLock(); _fluWakeLock.enable();
_destroyRoom() async { print('销毁房间'); try { VService.leaveRoom(_roomId.toString()); SocketUtils().sendChatData(RoomMessageType.LEAVE, {'room_id': _roomId}); if (trtcCloudIsActive) { print('销毁语音控件'); trtcCloud?.unRegisterListener(onTrtcListener); await trtcCloud?.stopLocalAudio(); await trtcCloud?.exitRoom(); await TRTCCloud.destroySharedInstance(); } } catch (e) { print('销毁房间错误:$e'); } }
传参后进入 VoiceChatRoomPage 直播间界面,
_connectOtherRoom() { print('开始调用跨房通话1'); var object = new Map(); if (_roomId == _pk['a_room_id']) { object['roomId'] = _pk['b_room_id']; object['userId'] = _pk['b_user_id'].toString(); } else { object['roomId'] = _pk['a_room_id']; object['userId'] = _pk['a_user_id'].toString(); } trtcCloud?.connectOtherRoom(jsonEncode(object)); // trtcCloud?.connectOtherRoom(jsonEncode(object)); // _channel.invokeMethod('connectOtherRoom', { // "param": jsonEncode(object) // }); }
直播推流:
_startPushStream() async { print("开始音频服务"); print('房间号:$_roomId,用户号:${VBase.uid}, sign:$_userSign'); trtcCloud = (await TRTCCloud.sharedInstance())!; _player = trtcCloud.getAudioEffectManager(); _playerWidget = PlayerWidget(_player, trtcCloud); TRTCParams params = TRTCParams(); params.sdkAppId = VBase.sdkAppId; params.strRoomId = _roomId.toString(); params.roomId = _roomId; params.userId = VBase.uid.toString(); // params.roomId = 100000; params.role = _roomDetailData.voicePermission ? TRTCCloudDef.TRTCRoleAnchor : TRTCCloudDef.TRTCRoleAudience; params.userSig = _userSign; params.privateMapKey = _roomDetailData.privilege; // trtcCloud?.setSystemVolumeType(type: TRTCCloudDef.
_handleAudioSetting(bool muteAll) { print("全员禁音:${muteAll.toString()}"); // EasyLoading.showToast(muteAll ? '全员禁音' : '已取消全员禁音'); trtcCloud?.muteAllRemoteAudio(muteAll); // if (!muteAll){ // trtcCloud?.switchRole(TRTCCloudDef.TRTCRoleAnchor); // trtcCloud?.startLocalAudio(TRTCCloudDef.TRTC_AUDIO_QUALITY_MUSIC); // } } _handleMicSetting(bool mute) { print("禁麦:${mute.toString()}"); // EasyLoading.showToast(muteAll ? '全员禁音' : '已取消全员禁音'); _handleLocalAudio(!mute); // if (!muteAll){ // trtcCloud?.switchRole(TRTCCloudDef.TRTCRoleAnchor); // trtcCloud?.startLocalAudio(TRTCCloudDef.TRTC_AUDIO_QUALITY_MUSIC); // } }
_handleVoiceReverb() { showModalBottomSheet( context: context, isDismissible: true, isScrollControlled: true, shape: const RoundedRectangleBorder(borderRadius: BorderRadius.only(topLeft: Radius.circular(15), topRight: Radius.circular(15))), builder: (BuildContext context) { return Container( decoration: const BoxDecoration( color: Colors.white, borderRadius: BorderRadius.only(topLeft: Radius.circular(15), topRight: Radius.circular(15))), height: dp(550), child: Column( children: [ InkWell( onTap: () { trtcCloud.getAudioEffectManager().setVoiceChangerType(0);
腾讯文档:
https://cloud.tencent.com/document/product/647/79628?from_column=20420
声网文档:
https://qifocus.notion.site/e646cf065ddf48cf879959e520f83810
demo项目:
https://git.yoqi.me/lyq/agora_rtc_engine_example
引入包:
agora_rtc_engine: 6.2.0 permission_handler: ^10.2.0
权限检测:
配置appid:
//config/agora.config.dart String get appId { return const String.fromEnvironment('TEST_APP_ID', defaultValue: '<TEST_APP_ID>'); } String get token { return const String.fromEnvironment('TEST_TOKEN', defaultValue: '<TEST_TOKEN>'); } String get channelId { return const String.fromEnvironment( 'TEST_CHANNEL_ID', defaultValue: '<TEST_CHANNEL_ID>', ); }
注意这里的token需要每次在业务系统获取,并全局保存。
token 有效期 24 小时,文档:使用 Token 鉴权 | 文档中心 | 声网 (shengwang.cn)
agora 创建RtcEngine 对象:
RtcEngine createAgoraRtcEngine() { return impl.RtcEngineImpl.create(); } RtcEngineEx createAgoraRtcEngineEx() { return impl.RtcEngineImpl.create(); } Future<void> initialize(RtcEngineContext context);
这个对象在全局保存。
获取用户uid:
Future<UserInfo> getUserInfoByUid(int uid);
获取用户信息:
Future<UserInfo> getUserInfoByUserAccount(String userAccount);
加入频道:
// 加入频道 await _engine.joinChannel( token: token, channelId: channel, options: const ChannelMediaOptions( // 设置用户角色为观众 clientRoleType: ClientRoleType.clientRoleAudience, // 设置低延时级别 audienceLatencyLevel: AudienceLatencyLevelType.audienceLatencyLevelLowLatency), uid: 0, ); //退出直播间 Future<void> leaveChannel({LeaveChannelOptions? options});
设置通话音量:
设置全员静音:
这个月底就和腾讯终止合作,需要在一周左右时间完成声网sdk对接
可以用这个接口测试获取的动态token http://api-test.tinger.net.cn/api/vchat/token uid:4443 channelName:1234
后台服务:
https://doc.shengwang.cn/faq/quality-issues/android-background#%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88
声网语聊房对接
背景
声网方案
说明:
资料
功能和注意事项
Tencent和agora直播逻辑整理
第一步:依赖替换:
替换为
在 lib\Base.dart 中定义全局变量:
实现了一个销毁 trtc 的方法:
这里将直播间id清空,trtc设置为null等操作。
在 lib\service.dart 中定义exitRoom操作,和上面 VBase 类一样:
注意这里VRoom类中定义的 exitRoom 和 destroyTrtcCloud 方法类似,可能重复了。
在 lib\chat\PlayerWidget.dart 中,这里定义了trtcCloud 和 player:
player直播间播放音乐的插件,
设置音量:
播放下一首,先停止,在播放:
注意,直播时候 trtcCloud 注册音乐播放器监听器 onTrtcListener:
这个 trtcCloud 在直播间页面调用播放音乐插件时候传入,接下来着重看一下直播间页面。
直播间页面 lib\chat\VoiceChatRoomPage.dart
调用sdk,配置appid等参数,新建一个 trtcCloud 对象:
进入直播间逻辑:
注意在调用 VoiceChatRoomPage 进入直播间会传递参数:
一个是直播间id,而 data 参数,在进入直播间之前先调用后台post接口:
直播间角色:
调用
_fluWakeLock
实例的enable
方法,用于启用设备的唤醒锁。启用唤醒锁可以防止设备在应用程序处于活动状态时进入睡眠模式,保持设备的唤醒状态,以确保应用程序可以继续运行或执行某些特定的任务。传参后进入 VoiceChatRoomPage 直播间界面,
直播推流:
腾讯文档:
https://cloud.tencent.com/document/product/647/79628?from_column=20420
声网文档:
https://qifocus.notion.site/e646cf065ddf48cf879959e520f83810
demo项目:
https://git.yoqi.me/lyq/agora_rtc_engine_example
声网接入
引入包:
权限检测:
配置appid:
注意这里的token需要每次在业务系统获取,并全局保存。
token 有效期 24 小时,文档:使用 Token 鉴权 | 文档中心 | 声网 (shengwang.cn)
agora 创建RtcEngine 对象:
这个对象在全局保存。
获取用户uid:
获取用户信息:
加入频道:
设置通话音量:
设置全员静音:
这个月底就和腾讯终止合作,需要在一周左右时间完成声网sdk对接
可以用这个接口测试获取的动态token http://api-test.tinger.net.cn/api/vchat/token uid:4443 channelName:1234
后台服务:
https://doc.shengwang.cn/faq/quality-issues/android-background#%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88