123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528 |
- import 'dart:async';
- import 'dart:convert';
- import 'dart:io';
- import 'package:flutter/cupertino.dart';
- import 'package:flutter/material.dart';
- import 'package:flutterappfuyou/code/base/YSNetWorking.dart';
- import 'package:flutterappfuyou/code/base/YSTools.dart';
- import 'package:flutterappfuyou/code/live/view/YSLiveUserView.dart';
- import 'package:live_flutter_plugin/v2_tx_live_def.dart';
- import 'package:live_flutter_plugin/v2_tx_live_pusher.dart';
- import 'package:live_flutter_plugin/v2_tx_live_pusher_observer.dart';
- import 'package:live_flutter_plugin/widget/v2_tx_live_video_widget.dart';
- import 'package:wakelock/wakelock.dart';
- class YSLiveAnchor extends StatefulWidget {
- final int liveId;
- final isSelect;
- const YSLiveAnchor({Key key, this.liveId, this.isSelect = false}) : super(key: key);
- @override
- _YSLiveAnchorState createState() => _YSLiveAnchorState();
- }
- class _YSLiveAnchorState extends State<YSLiveAnchor> {
- String _pushUrl = '';
- WebSocket _socket;
- List _userArray = [];
- int _userCount = 0;
- bool _isMute = false;
- bool _isPause = false;
- bool _isFont = true;
- @override
- void initState() {
- if(widget.isSelect){
- Future.delayed(Duration(seconds: 0)).then((value) {
- _getStartData();
- });
- }
- super.initState();
- }
- _getStartData() async{
- Map dict = await ysRequestHttp(context, requestType.get, 'train/live2/start', {'live_id':widget.liveId});
- if(dict!=null){
- Map data = dict['data'];
- _pushUrl = data['push_url'];
- User().castAvatar = data['cast_avatar'];
- User().castName = data['cast_name'];
- User().stream = data['live_stream']??'';
- User.instance.isAnchor = true;
- setState(() {});
- }
- }
- @override
- Widget build(BuildContext context) {
- return NotificationListener<CustomerValueNotification>(
- onNotification: (notification){
- Map data = notification.value;
- String type = data['type'];
- if(type=='headcount'){
- _userArray = data['value']['users']??[];
- _userCount = data['value']['total']??0;
- setState(() {});
- }else if(type=='mute'){
- _isMute = !_isMute;
- setState(() {});
- }else if(type=='pause'||type=='resume'){
- if(type=='pause'){
- liveKey.currentState._pauseLive();
- }else{
- liveKey.currentState._resumeLive();
- }
- _isPause = type=='pause';
- setState(() {});
- }else if(type=='staff'){
- List users = data['value']['users']??[];
- ysShowBottomAlertView(context, YSUsersAlertView(users: users,),isBarr: true);
- }
- return true;
- },
- child: WillPopScope(
- onWillPop: () async{
- return false;
- },
- child: Scaffold(
- backgroundColor: Colors.black,
- body: Container(
- width: ysWidth(context),
- height: ysHeight(context),
- child: Stack(
- children: [
- _pushUrl.isNotEmpty?YSAnchorLiveView(
- key: liveKey,pushStr: _pushUrl,
- ):Image.asset('lib/images/图.png',fit: BoxFit.fill,width: ysWidth(context),height: ysHeight(context),),
- Container(
- width: ysWidth(context),
- height: ysHeight(context),
- padding: EdgeInsets.only(top: ysTOP(context)+15,left: 10,right: 10,bottom: 10),
- child: Column(
- children: [
- Container(
- height: 40,
- child: Row(
- children: [
- Container(
- width: (ysWidth(context)-20)*0.3,
- decoration: BoxDecoration(
- color: Colors.black,
- borderRadius: BorderRadius.all(Radius.circular(50))
- ),
- child: User().castAvatar!=null?Row(
- children: [
- Container(
- height: 40,
- width: 40,
- decoration: BoxDecoration(
- borderRadius: BorderRadius.all(Radius.circular(50)),
- image: DecorationImage(image: NetworkImage(User().castAvatar))
- ),
- ),
- Container(
- width: (ysWidth(context)-20)*0.3-40,
- padding: EdgeInsets.only(left: 5,right: 5),
- child: Text(User().castName,style: TextStyle(fontSize: 10,color: Colors.white,fontWeight: FontWeight.bold,),
- maxLines: 1,overflow: TextOverflow.ellipsis,),
- )
- ],
- ):Container(),
- ),
- GestureDetector(
- onTap: (){
- if(_socket==null)return;
- _socket.add(jsonEncode({'type':'staff'}));
- // Navigator.of(context).push(
- // CupertinoPageRoute(builder: (context){
- // return YSLiveUser();
- // })
- // );
- },
- behavior: HitTestBehavior.opaque,
- child: Row(
- children: [
- Container(
- width: (ysWidth(context)-20)*0.55,
- padding: EdgeInsets.only(top: 5,bottom: 5,left: 10),
- child: ListView.builder(
- itemBuilder: (context,index){
- Map item = _userArray[index];
- return Container(
- height: 30,
- width: 30,
- decoration: BoxDecoration(
- borderRadius: BorderRadius.all(Radius.circular(50)),
- color: Colors.white,
- image: DecorationImage(image: NetworkImage(item['avatar']),fit: BoxFit.cover)
- ),
- );
- },
- itemCount: _userArray.length,
- scrollDirection: Axis.horizontal,
- ),
- ),
- Container(
- width: (ysWidth(context)-20)*0.15,
- decoration: BoxDecoration(
- color: Colors.black,
- borderRadius: BorderRadius.all(Radius.circular(50))
- ),
- alignment: Alignment.center,
- child: Text('$_userCount',style: TextStyle(fontSize: 12,color: Colors.white),),
- )
- ],
- ),
- )
- ],
- ),
- ),
- Container(
- height: ysHeight(context)-ysTOP(context)-125,
- alignment: Alignment.bottomRight,
- child: _pushUrl.isEmpty&&widget.isSelect==false?Column(
- mainAxisSize: MainAxisSize.min,
- crossAxisAlignment: CrossAxisAlignment.end,
- children: [
- Text('直播尚未开始,您是否需要开始直播?',style: TextStyle(fontSize: 18,color: Colors.white,fontWeight: FontWeight.bold),),
- GestureDetector(
- onTap: () {
- _getStartData();
- },
- child: Container(
- height: 44,
- width: 150,
- decoration: BoxDecoration(
- color: Color(0xFFE36085),
- borderRadius: BorderRadius.all(Radius.circular(5))
- ),
- margin: EdgeInsets.only(top: 30,bottom: 50),
- alignment: Alignment.center,
- child: Text('立即直播',style: TextStyle(fontSize: 18,color: Colors.white),),
- ),
- )
- ],
- ):Container(),
- ),
- _pushUrl.isEmpty?Container(
- height: 60,
- alignment: Alignment.centerRight,
- child: GestureDetector(
- onTap: (){
- Navigator.of(context).pop('');
- Navigator.of(context).pop('');
- Navigator.of(context).pop('');
- },
- child: Image.asset('lib/images/退出.png',height: 20,width: 20,),
- )
- ):Container(
- alignment: Alignment.centerRight,
- height: 60,
- child: Row(
- mainAxisSize: MainAxisSize.min,
- children: [
- GestureDetector(
- child: Image.asset('lib/images/${_isMute?'取消禁言':'禁言'}.png',height: 20,width: 20,color: Colors.white,),
- onTap: (){
- if(_isMute){
- _socket.add(jsonEncode({'type':'mute','mute_time':1}));
- }else{
- _socket.add(jsonEncode({'type':'mute','mute_time':0}));
- }
- },
- ),
- Container(
- margin: EdgeInsets.only(left: 20,right: 20),
- child: GestureDetector(
- onTap: (){
- if(_isPause){
- _socket.add(jsonEncode({'type':'resume'}));
- }else{
- _socket.add(jsonEncode({'type':'pause'}));
- }
- },
- child: Image.asset('lib/images/${_isPause?'取消暂停':'暂停'}.png',height: 20,width: 20,color: Colors.white,),
- )
- ),
- Container(
- margin: EdgeInsets.only(right: 20),
- child: GestureDetector(
- onTap: () async{
- _isFont = !_isFont;
- liveKey.currentState._changeCameraLive(_isFont);
- setState(() {});
- },
- child: Icon(_isFont?Icons.camera_front:Icons.video_camera_back,color: Colors.white,)
- ),
- ),
- GestureDetector(
- onTap: () {
- ysShowCenterAlertView(context, YSTipsAlertView(
- tipsStr: '是否退出直播?',
- valueSetter: (value) async{
- if(value){
- Map dict = await ysRequestHttp(context, requestType.get, 'train/live2/close', {'live_id':widget.liveId});
- if(dict!=null){
- if(_socket!=null){
- _socket.add(jsonEncode({'type':'leave'}));
- }
- liveKey.currentState._stopPush();
- Navigator.of(context).pop('');
- Navigator.of(context).pop('');
- Navigator.of(context).pop('');
- }
- }
- },
- ));
- },
- child: Image.asset('lib/images/退出.png',height: 20,width: 20,color: Colors.white,),
- )
- ],
- ),
- ),
- ],
- ),
- ),
- if(_pushUrl.isNotEmpty)Positioned(
- bottom: 70,
- left: 10,
- child:YSTalkView(
- postSocket: (socket){
- _socket = socket;
- if(_pushUrl.isNotEmpty){
- Future.delayed(Duration(seconds: 2)).then((value) {
- _socket.add(jsonEncode({'type':'enter'}));
- });
- }
- },
- )
- )
- ],
- ),
- ),
- ),
- ),
- );
- }
- }
- class YSTalkView extends StatefulWidget {
- final ValueSetter<WebSocket> postSocket;
- const YSTalkView({Key key, this.postSocket}) : super(key: key);
- @override
- _YSTalkViewState createState() => _YSTalkViewState();
- }
- class _YSTalkViewState extends State<YSTalkView> {
- List _dataArray = [];
- static WebSocket _socket;
- Timer _timer;
- ScrollController _scrollController = ScrollController();
- @override
- void initState() {
- _getSocket();
- super.initState();
- }
- //wss://v2fy.niwoshenghuo.com/websocket
- //ws://101.43.97.222:868
- //ws://114.115.176.164:8686
- _getSocket() async{
- WebSocket.connect('wss://v2fy.niwoshenghuo.com/websocket').then((socket) {
- _socket = socket;
- widget.postSocket(_socket);
- socket.listen(_onData, cancelOnError: false);
- _timer =Timer.periodic(Duration(seconds: 10), (timer) {
- _socket.add('heartbeat');
- });
- }).catchError((e){
- LogUtil.d("Unable to connect: $e");
- _getSocket(); // 连接超时,重新建立连接
- });
- }
- _onData(event) async{
- Map dict = jsonDecode(event);
- LogUtil.d("---onData---$dict");
- if(dict['type']=='connection'){
- Map data = dict['data'];
- _dataArray.add({'type':0,'content':data['content']});
- setState(() {});
- Map message = {};
- message['type'] = 'bind';
- message['live_stream'] = User().stream;
- message['uid'] = data['uid'];
- message['user'] = {'username':User().castName??User().name,'avatar':User().castAvatar??User().avatar,'is_owner':User().isAnchor};
- _socket.add(jsonEncode(message));
- }else if(dict['type']=='message'){
- var data = dict['data'];
- if(data is List){
- _dataArray.add({'type':1,'content':User().content,'name':User().castName??User().name,'avatar':User().castAvatar??User().name});
- }else{
- Map user = data['user'];
- _dataArray.add({'type':1,'content':data['content'],'name':user['username'],'avatar':user['avatar']});
- }
- setState(() {});
- _scrollController.jumpTo(_scrollController.position.maxScrollExtent+50);
- }else if(dict['type']=='headcount'||dict['type']=='staff'||dict['type']=='mute'||dict['type']=='pause'||dict['type']=='resume'||dict['type']=='enter'||dict['type']=='staff'){
- var data = dict['data'];
- CustomerValueNotification({'type':dict['type'],'value':data}).dispatch(context);
- }else if(dict['type']=='leave'){
- CustomerValueNotification({'type':dict['type'],'value':{}}).dispatch(context);
- }else if(dict['type']=='bind'){
- _socket.add(jsonEncode({'type':'headcount'}));
- }else if(dict['type']=='heartbeat'){
- var data = dict['data'];
- CustomerValueNotification({'type':'headcount','value':data}).dispatch(context);
- }
- }
- @override
- void dispose() {
- _socket.close();
- if(_timer!=null){
- if(_timer.isActive)_timer.cancel();
- }
- super.dispose();
- }
- @override
- Widget build(BuildContext context) {
- return Container(
- height: ysHeight(context)*0.4,
- width: ysWidth(context)*0.75,
- child: ListView.separated(
- controller: _scrollController,
- padding: EdgeInsets.only(top: 10,bottom: 10),
- itemBuilder: (context,index){
- Map item = _dataArray[index];
- int type = item['type'];
- return Container(
- padding: EdgeInsets.only(left: 10,right: 10,top: 5,bottom: 5),
- decoration: BoxDecoration(
- color: Colors.black12,
- borderRadius: BorderRadius.all(Radius.circular(3))
- ),
- child: type==0?Text('${item['content']}',style: TextStyle(fontSize: 13,color: Colors.orange),):Row(
- mainAxisSize: MainAxisSize.min,
- crossAxisAlignment: CrossAxisAlignment.center,
- children: [
- Container(
- height: 20,
- width: 20,
- decoration: BoxDecoration(
- color: Colors.white,
- borderRadius: BorderRadius.all(Radius.circular(50)),
- image: DecorationImage(image: NetworkImage(item['avatar']),fit: BoxFit.cover)
- ),
- ),
- Container(
- padding: EdgeInsets.only(left: 5),
- constraints: BoxConstraints(maxWidth: ysWidth(context)*0.75-40),
- child: RichText(
- text: TextSpan(
- text: '${item['name']}:',
- style: TextStyle(fontSize: 13,color: Color(0xFF89DCFF)),
- children: [
- TextSpan(
- text: '${item['content']}',
- style: TextStyle(fontSize: 13,color: Colors.white)
- )
- ]
- ),
- ),
- )
- ],
- ),
- );
- },
- separatorBuilder: (context,index){
- return Container(height: 5,);
- },
- itemCount: _dataArray.length
- ),
- );
- }
- }
- GlobalKey<_YSAnchorLiveViewState> liveKey = GlobalKey();
- class YSAnchorLiveView extends StatefulWidget {
- final String pushStr;
- const YSAnchorLiveView({Key key, this.pushStr = ''}) : super(key: key);
- @override
- _YSAnchorLiveViewState createState() => _YSAnchorLiveViewState();
- }
- class _YSAnchorLiveViewState extends State<YSAnchorLiveView> {
- V2TXLivePusher _livePusher;
- int _localViewId;
- bool _isFont = true;
- _initPusher() async{
- _livePusher = V2TXLivePusher(V2TXLiveMode.v2TXLiveModeRTMP);
- _livePusher.addListener(_onPusherObserver);
- }
- _onPusherObserver(V2TXLivePusherListenerType type, param) {
- debugPrint("==pusher listener type= ${type.toString()}");
- debugPrint("==pusher listener param= $param");
- }
- @override
- void initState() {
- Wakelock.enable();
- _initPusher();
- super.initState();
- }
- @override
- void dispose() async{
- Wakelock.disable();
- _stopPush();
- super.dispose();
- }
- @override
- Widget build(BuildContext context) {
- return V2TXLiveVideoWidget(
- onViewCreated: (viewId) async{
- _localViewId = viewId;
- _livePusher.setRenderViewID(_localViewId);
- _startPush();
- }
- );
- }
- _stopPush() async {
- await _livePusher?.stopMicrophone();
- await _livePusher?.stopCamera();
- await _livePusher?.stopPush();
- _livePusher.destroy();
- }
- _pauseLive(){
- _livePusher.stopCamera();
- _livePusher.stopMicrophone();
- }
- _resumeLive(){
- _livePusher.startCamera(_isFont);
- _livePusher.startMicrophone();
- }
- _changeCameraLive(bool isFont){
- _isFont = isFont;
- _livePusher.getDeviceManager().switchCamera(isFont);
- }
- _startPush() async {
- bool bool1 = await permissionHandler('microphone');
- bool bool2 = await permissionHandler('camera');
- if(bool1&&bool2){
- _livePusher.getBeautyManager().setBeautyLevel(5);
- _livePusher.startCamera(_isFont);
- _livePusher.startMicrophone();
- int result = await _livePusher.startPush(widget.pushStr);
- LogUtil.d('result=========$result');
- }
- }
- }
|