rongcloud_call_wrapper_plugin 5.1.15+4 copy "rongcloud_call_wrapper_plugin: ^5.1.15+4" to clipboard
rongcloud_call_wrapper_plugin: ^5.1.15+4 copied to clipboard

outdated

Rongcloud calllib interface wrapper for flutter.

example/lib/main.dart

import 'dart:async';
import 'dart:io';

import 'package:context_holder/context_holder.dart';
import 'package:flutter/material.dart';
import 'package:handy_toast/handy_toast.dart';
import 'package:rongcloud_call_wrapper_plugin/rongcloud_call_wrapper_plugin.dart';
import 'package:rongcloud_im_plugin/rongcloud_im_plugin.dart';

/// 示例说明:本示例需要分别在 iOS 和 android 设备中运行
/// 其中 android 设备会登陆用户 A
/// iOS 设备会登陆用户 B
/// 以下 TODO 参数需要自行配置

/// TODO app key
const String app_key = '';

/// TODO user a token
const String token_a = '';

/// TODO user a id
const String user_a = '';

/// TODO user b token
const String token_b = '';

/// TODO user b id
const String user_b = '';

void main() {
  runApp(MaterialApp(
    navigatorKey: ContextHolder.key,
    home: const MyApp(),
  ));
}

enum AppState {
  disconnected,
  connected,
  ringing,
  calling,
  chatting,
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  void initState() {
    super.initState();
    initPlatformState();
  }

  // Platform messages are asynchronous, so we initialize in an async method.
  Future<void> initPlatformState() async {
    RongIMClient.init(app_key);
    String token = Platform.isAndroid ? token_a : token_b;
    RongIMClient.connect(token, (code, userId) async {
      _state = AppState.connected;
      await _initEngine();
      if (mounted) {
        setState(() {});
      }
    });
  }

  Future<void> _initEngine() async {
    _engine = await RCCallEngine.create();

    RCCallAudioConfig audioConfig = RCCallAudioConfig.create();
    await _engine?.setAudioConfig(audioConfig);

    RCCallVideoConfig videoConfig = RCCallVideoConfig.create(profile: RCCallVideoProfile.profile_1080_1920_high);
    await _engine?.setVideoConfig(videoConfig);

    _engine?.onReceiveCall = (session) {
      setState(() {
        _session = session;
        _state = AppState.ringing;
      });
    };

    _engine?.onConnect = () => _connected();

    _engine?.onRemoteUserDidChangeCameraState = (user, enable) async {
      if (enable) {
        if (_mine) {
          if (_small == null) {
            _small = await RCCallView.create(fit: BoxFit.cover);
            await _engine?.setVideoView(_smallUserId!, _small);
          }
        } else {
          if (_big == null) {
            _big = await RCCallView.create(fit: BoxFit.cover);
            await _engine?.setVideoView(_bigUserId!, _big);
          }
        }
      } else {
        if (_mine) {
          if (_small != null) {
            _small = null;
            await _engine?.setVideoView(_smallUserId!, null);
          }
        } else {
          if (_big != null) {
            _big = null;
            await _engine?.setVideoView(_bigUserId!, null);
          }
        }
      }

      if (mounted) {
        setState(() {});
      }
    };

    _engine?.onDisconnect = (reason) async {
      'Disconnect, reason = $reason'.toast();
      _state = AppState.connected;
      _background = null;
      _big = null;
      _small = null;

      _beauty = false;
      await _engine?.setBeautyFilter(RCCallBeautyFilter.none);
      await _engine?.setBeautyOption(RCCallBeautyOption.create(), false);

      if (mounted) {
        setState(() {});
      }
    };

    _engine?.onCallError = (error) {
      'Call Error, error = $error'.toast();
    };
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('flutter call plugin'),
        ),
        body: _build(),
      ),
    );
  }

  Widget _build() {
    switch (_state) {
      case AppState.disconnected:
        return Center(
          child: CircularProgressIndicator(),
        );
      case AppState.connected:
        return _buildConnectedPage();
      case AppState.ringing:
        return _buildRingingPage();
      case AppState.calling:
        return _buildCallingPage();
      case AppState.chatting:
        return _buildChattingPage();
    }
  }

  Widget _buildConnectedPage() {
    return Center(
      child: TextButton(
        onPressed: () => _call(),
        child: Text(
          '呼叫',
          style: TextStyle(
            color: Colors.green,
            fontSize: 15,
            decoration: TextDecoration.none,
          ),
        ),
      ),
    );
  }

  Widget _buildCallingPage() {
    return Stack(
      children: [
        _background != null ? _background! : Container(),
        Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            Divider(
              height: 150,
              color: Colors.transparent,
            ),
            Text(
              '正在呼叫${_target()}...',
              softWrap: true,
              style: TextStyle(
                color: Colors.black,
                fontSize: 15,
                decoration: TextDecoration.none,
              ),
            ),
            Divider(
              height: 50,
              color: Colors.transparent,
            ),
            Row(
              children: [
                Spacer(),
                TextButton(
                  onPressed: () => _hangup(),
                  child: Text(
                    '挂断',
                    style: TextStyle(
                      color: Colors.red,
                      fontSize: 15,
                      decoration: TextDecoration.none,
                    ),
                  ),
                ),
                Spacer(),
              ],
            )
          ],
        ),
      ],
    );
  }

  Widget _buildRingingPage() {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.center,
      children: [
        Divider(
          height: 150,
          color: Colors.transparent,
        ),
        Text(
          '来自${_caller()}的${_type()}电话',
          softWrap: true,
          textAlign: TextAlign.center,
          style: TextStyle(
            color: Colors.black,
            fontSize: 15,
            decoration: TextDecoration.none,
          ),
        ),
        Divider(
          height: 50,
          color: Colors.transparent,
        ),
        Row(
          children: [
            Spacer(),
            TextButton(
              onPressed: () => _accept(),
              child: Text(
                '接听',
                style: TextStyle(
                  color: Colors.green,
                  fontSize: 15,
                  decoration: TextDecoration.none,
                ),
              ),
            ),
            Spacer(),
            TextButton(
              onPressed: () => _hangup(),
              child: Text(
                '拒绝',
                style: TextStyle(
                  color: Colors.red,
                  fontSize: 15,
                  decoration: TextDecoration.none,
                ),
              ),
            ),
            Spacer(),
          ],
        )
      ],
    );
  }

  void _accept() async {
    int code = await _engine?.accept() ?? -1;
    if (code != 0) {
      'Accept Call Error $code'.toast();
    }
  }

  void _hangup() async {
    int code = await _engine?.hangup() ?? -1;
    if (code != 0) {
      'Hangup Call Error $code'.toast();
    }
    _state = AppState.connected;
    if (mounted) {
      setState(() {});
    }
  }

  String _target() {
    return _session?.targetId ?? 'Unknown';
  }

  String _caller() {
    return _session?.caller?.userId ?? 'Unknown';
  }

  String _type() {
    return _session?.mediaType.toString() ?? 'Unknown';
  }

  Widget _buildChattingPage() {
    return Stack(
      children: [
        _bigView(),
        Align(
          alignment: Alignment.topRight,
          child: Padding(
            padding: EdgeInsets.only(
              right: 10,
              top: 10,
            ),
            child: _smallView(),
          ),
        ),
        Align(
          alignment: Alignment.bottomCenter,
          child: Padding(
            padding: EdgeInsets.only(
              bottom: 200,
            ),
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Row(
                  children: [
                    Spacer(),
                    TextButton(
                      onPressed: () => _cameraSwitch(),
                      child: Text(
                        '${_camera ? '关闭摄像头' : '开启摄像头'}',
                        style: TextStyle(
                          color: Colors.black,
                          fontSize: 15,
                          decoration: TextDecoration.none,
                        ),
                      ),
                    ),
                    Spacer(),
                    TextButton(
                      onPressed: () => _camera ? _switchCamera() : null,
                      child: Text(
                        '切换摄像头',
                        style: TextStyle(
                          color: Colors.black,
                          fontSize: 15,
                          decoration: TextDecoration.none,
                        ),
                      ),
                    ),
                    Spacer(),
                  ],
                ),
                Row(
                  children: [
                    Spacer(),
                    TextButton(
                      onPressed: () => _microphoneSwitch(),
                      child: Text(
                        '${_microphone ? '关闭麦克风' : '开启麦克风'}',
                        style: TextStyle(
                          color: Colors.black,
                          fontSize: 15,
                          decoration: TextDecoration.none,
                        ),
                      ),
                    ),
                    Spacer(),
                    TextButton(
                      onPressed: () => _speakerSwitch(),
                      child: Text(
                        '${_speaker ? '扬声器' : '听筒'}',
                        style: TextStyle(
                          color: Colors.black,
                          fontSize: 15,
                          decoration: TextDecoration.none,
                        ),
                      ),
                    ),
                    Spacer(),
                  ],
                ),
                Row(
                  children: [
                    Spacer(),
                    TextButton(
                      onPressed: () => _beautySwitch(),
                      child: Text(
                        '${_beauty ? '关闭美颜' : '开启美颜'}',
                        style: TextStyle(
                          color: Colors.black,
                          fontSize: 15,
                          decoration: TextDecoration.none,
                        ),
                      ),
                    ),
                    Spacer(),
                  ],
                ),
              ],
            ),
          ),
        ),
        Align(
          alignment: Alignment.bottomCenter,
          child: Padding(
            padding: EdgeInsets.only(
              bottom: 100,
            ),
            child: TextButton(
              onPressed: () => _hangup(),
              child: Text(
                '挂断',
                style: TextStyle(
                  color: Colors.red,
                  fontSize: 15,
                  decoration: TextDecoration.none,
                ),
              ),
            ),
          ),
        ),
      ],
    );
  }

  Widget _bigView() {
    return Container(
      color: Colors.yellow,
      child: Stack(
        children: [
          _big != null ? _big! : Container(),
          Align(
            alignment: Alignment.topLeft,
            child: Padding(
              padding: EdgeInsets.only(
                left: 5,
                top: 5,
              ),
              child: Text(
                '$_bigUserId',
                softWrap: true,
                style: TextStyle(
                  color: Colors.black,
                  fontSize: 15,
                  decoration: TextDecoration.none,
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }

  Widget _smallView() {
    return Container(
      width: 100,
      height: 130,
      color: Colors.blue,
      child: GestureDetector(
        behavior: HitTestBehavior.opaque,
        onTap: () => _switchView(),
        child: Stack(
          children: [
            _small != null ? _small! : Container(),
            Align(
              alignment: Alignment.topLeft,
              child: Padding(
                padding: EdgeInsets.only(
                  left: 5,
                  top: 5,
                ),
                child: Text(
                  '$_smallUserId',
                  softWrap: true,
                  style: TextStyle(
                    color: Colors.black,
                    fontSize: 15,
                    decoration: TextDecoration.none,
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }

  void _switchView() async {
    _mine = !_mine;

    _big = null;
    _small = null;

    if (_bigUserId != null) {
      await _engine?.setVideoView(_bigUserId!, null);
    }
    if (_smallUserId != null) {
      await _engine?.setVideoView(_smallUserId!, null);
    }

    String? temp = _bigUserId;
    _bigUserId = _smallUserId;
    _smallUserId = temp;

    if (_bigUserId != null) {
      _big = await RCCallView.create(fit: BoxFit.cover);
      await _engine?.setVideoView(_bigUserId!, _big);
    }
    if (_smallUserId != null) {
      _small = await RCCallView.create(fit: BoxFit.cover);
      await _engine?.setVideoView(_smallUserId!, _small);
    }

    if (mounted) {
      setState(() {});
    }
  }

  void _call() async {
    String target = Platform.isAndroid ? user_b : user_a;
    _session = await _engine?.startCall(target, RCCallMediaType.audio_video);
    if (_session != null) {
      _state = AppState.calling;
      _background = await RCCallView.create(fit: BoxFit.cover);
      if (mounted) {
        setState(() {});
      }
      await _engine?.setVideoView(_session!.mine.userId, _background);
    }
  }

  void _connected() async {
    _background = null;

    _bigUserId = _session?.mine.userId;
    _session?.users.forEach((user) {
      if (user.userId != _bigUserId) {
        _smallUserId = user.userId;
      }
    });

    _mine = true;
    _camera = true;
    _microphone = true;
    _speaker = false;

    _engine?.enableSpeaker(_speaker);

    _big = await RCCallView.create(fit: BoxFit.cover);
    _small = await RCCallView.create(fit: BoxFit.cover);

    _state = AppState.chatting;

    if (mounted) {
      setState(() {});
    }

    await _engine?.setVideoView(_bigUserId!, _big);
    await _engine?.setVideoView(_smallUserId!, _small);
  }

  void _cameraSwitch() async {
    _camera = !_camera;
    await _engine?.enableCamera(_camera);
    if (_camera) {
      if (_mine) {
        _big = await RCCallView.create(fit: BoxFit.cover);
        await _engine?.setVideoView(_bigUserId!, _big);
      } else {
        _small = await RCCallView.create(fit: BoxFit.cover);
        await _engine?.setVideoView(_smallUserId!, _small);
      }
    } else {
      if (_mine) {
        _big = null;
        await _engine?.setVideoView(_bigUserId!, null);
      } else {
        _small = null;
        await _engine?.setVideoView(_smallUserId!, null);
      }
    }
    setState(() {});
  }

  void _switchCamera() async {
    await _engine?.switchCamera();
  }

  void _microphoneSwitch() async {
    _microphone = !_microphone;
    await _engine?.enableMicrophone(_microphone);
    setState(() {});
  }

  void _speakerSwitch() async {
    _speaker = !_speaker;
    await _engine?.enableSpeaker(_speaker);
    setState(() {});
  }

  void _beautySwitch() async {
    RCCallBeautyOption option = RCCallBeautyOption.create(
      whitenessLevel: 2,
      smoothLevel: 4,
      ruddyLevel: 3,
      brightLevel: 5,
    );

    _beauty = !_beauty;
    if (_beauty) {
      await _engine?.setBeautyOption(option, _beauty);
      await _engine?.setBeautyFilter(RCCallBeautyFilter.romantic);
    } else {
      await _engine?.setBeautyFilter(RCCallBeautyFilter.none);
      await _engine?.setBeautyOption(option, _beauty);
    }

    setState(() {});
  }

  AppState _state = AppState.disconnected;
  RCCallEngine? _engine;
  RCCallSession? _session;
  RCCallView? _background;

  bool _mine = true;
  RCCallView? _big;
  String? _bigUserId;
  RCCallView? _small;
  String? _smallUserId;

  bool _beauty = false;
  bool _camera = true;
  bool _microphone = true;
  bool _speaker = false;
}
0
likes
0
pub points
45%
popularity

Publisher

unverified uploader

Rongcloud calllib interface wrapper for flutter.

Homepage

License

unknown (LICENSE)

Dependencies

flutter, rongcloud_im_plugin

More

Packages that depend on rongcloud_call_wrapper_plugin