ex_im_flutter_call 0.0.8 copy "ex_im_flutter_call: ^0.0.8" to clipboard
ex_im_flutter_call: ^0.0.8 copied to clipboard

A Flutter plugin for audio/video calling - provides WebRTC-based 1v1 and group calling functionality for ex_im_flutter_chat.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'dart:async';
import 'package:ex_im_flutter_call/ex_im_flutter_call.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

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

class _MyAppState extends State<MyApp> {
  CallState _callState = const CallState();
  MediaState _mediaState = const MediaState();
  StreamSubscription<CallState>? _callStateSub;
  StreamSubscription<MediaState>? _mediaStateSub;
  bool _isInitialized = false;
  String _statusMessage = '未初始化';

  @override
  void initState() {
    super.initState();
    _checkInitStatus();
  }

  void _checkInitStatus() {
    // 检查是否已登录 Chat SDK
    // 实际使用中需要先初始化 ExImChat 并登录
    setState(() {
      _statusMessage = '请先初始化 ExImChat 并登录';
    });
  }

  void _initCallSdk() {
    try {
      ExImCall.instance.init();

      // 监听通话状态
      _callStateSub = ExImCall.instance.callStateStream.listen((state) {
        setState(() {
          _callState = state;
        });
      });

      // 监听媒体状态
      _mediaStateSub = ExImCall.instance.mediaStateStream.listen((state) {
        setState(() {
          _mediaState = state;
        });
      });

      setState(() {
        _isInitialized = true;
        _statusMessage = 'Call SDK 已初始化';
      });
    } catch (e) {
      setState(() {
        _statusMessage = '初始化失败: $e';
      });
    }
  }

  Future<void> _makeCall() async {
    if (!_isInitialized) {
      _showSnackBar('请先初始化 SDK');
      return;
    }

    try {
      // 简化的 API:只需传用户 ID 和通话类型
      // 用户信息由插件内部自动获取
      await ExImCall.instance.call(
        targetUserId: 'test_user_id',
        callType: CallTypeEnum.video,
      );
    } catch (e) {
      _showSnackBar('发起通话失败: $e');
    }
  }

  Future<void> _hangup() async {
    try {
      await ExImCall.instance.hangup();
    } catch (e) {
      _showSnackBar('挂断失败: $e');
    }
  }

  void _showSnackBar(String message) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text(message)),
    );
  }

  @override
  void dispose() {
    _callStateSub?.cancel();
    _mediaStateSub?.cancel();
    if (_isInitialized) {
      ExImCall.instance.dispose();
    }
    super.dispose();
  }

  String _getModeText(RtcServiceMode mode) {
    switch (mode) {
      case RtcServiceMode.idle:
        return '空闲';
      case RtcServiceMode.dial:
        return '拨号中';
      case RtcServiceMode.invite:
        return '来电中';
      case RtcServiceMode.talking:
        return '通话中';
      case RtcServiceMode.connecting:
        return '连接中';
      case RtcServiceMode.reconnecting:
        return '重连中';
      case RtcServiceMode.ended:
        return '已结束';
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('ExIm Call Example'),
        ),
        body: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              // 状态信息
              Card(
                child: Padding(
                  padding: const EdgeInsets.all(16.0),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text('状态: $_statusMessage'),
                      const SizedBox(height: 8),
                      Text('通话模式: ${_getModeText(_callState.mode)}'),
                      if (_callState.roomId.isNotEmpty)
                        Text('房间ID: ${_callState.roomId}'),
                      if (_callState.remoteNickname.isNotEmpty)
                        Text('对方: ${_callState.remoteNickname}'),
                      if (_callState.mode == RtcServiceMode.talking)
                        Text('通话时长: ${_callState.callDuration}秒'),
                    ],
                  ),
                ),
              ),
              const SizedBox(height: 16),

              // 媒体状态
              Card(
                child: Padding(
                  padding: const EdgeInsets.all(16.0),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      const Text('媒体状态', style: TextStyle(fontWeight: FontWeight.bold)),
                      const SizedBox(height: 8),
                      Text('视频: ${_mediaState.isVideoEnabled ? "开启" : "关闭"}'),
                      Text('音频: ${_mediaState.isAudioEnabled ? "开启" : "关闭"}'),
                      Text('扬声器: ${_mediaState.isSpeakerOn ? "开启" : "关闭"}'),
                      Text('摄像头: ${_mediaState.isFrontCamera ? "前置" : "后置"}'),
                    ],
                  ),
                ),
              ),
              const SizedBox(height: 24),

              // 操作按钮
              if (!_isInitialized)
                ElevatedButton(
                  onPressed: _initCallSdk,
                  child: const Text('初始化 Call SDK'),
                ),
              if (_isInitialized) ...[
                Row(
                  children: [
                    ElevatedButton(
                      onPressed: _callState.mode == RtcServiceMode.idle ? _makeCall : null,
                      child: const Text('发起视频通话'),
                    ),
                    const SizedBox(width: 8),
                    ElevatedButton(
                      onPressed: _callState.mode != RtcServiceMode.idle ? _hangup : null,
                      style: ElevatedButton.styleFrom(backgroundColor: Colors.red),
                      child: const Text('挂断', style: TextStyle(color: Colors.white)),
                    ),
                  ],
                ),
                const SizedBox(height: 16),
                // 媒体控制按钮
                if (_callState.mode == RtcServiceMode.talking)
                  Row(
                    children: [
                      IconButton(
                        onPressed: () => ExImCall.instance.toggleVideo(),
                        icon: Icon(_mediaState.isVideoEnabled
                            ? Icons.videocam
                            : Icons.videocam_off),
                      ),
                      IconButton(
                        onPressed: () => ExImCall.instance.toggleAudio(),
                        icon: Icon(_mediaState.isAudioEnabled
                            ? Icons.mic
                            : Icons.mic_off),
                      ),
                      IconButton(
                        onPressed: () => ExImCall.instance.toggleSpeaker(),
                        icon: Icon(_mediaState.isSpeakerOn
                            ? Icons.volume_up
                            : Icons.volume_off),
                      ),
                      IconButton(
                        onPressed: () => ExImCall.instance.switchCamera(),
                        icon: const Icon(Icons.cameraswitch),
                      ),
                    ],
                  ),
              ],
            ],
          ),
        ),
      ),
    );
  }
}
0
likes
145
points
273
downloads

Publisher

unverified uploader

Weekly Downloads

A Flutter plugin for audio/video calling - provides WebRTC-based 1v1 and group calling functionality for ex_im_flutter_chat.

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

audioplayers, cached_network_image, desktop_multi_window, ex_im_flutter_chat, flutter, flutter_screenutil, flutter_webrtc, permission_handler, wakelock_plus, window_manager

More

Packages that depend on ex_im_flutter_call

Packages that implement ex_im_flutter_call