Flutter VoIP通信插件siprix_voip_sdk的使用

Flutter VoIP通信插件siprix_voip_sdk的使用

Siprix VoIP SDK 是一个用于在 Flutter 应用中嵌入基于 SIP/RTP 协议的语音和视频通话的插件。它支持多个平台,包括 Android、iOS、MacOS、Windows 和 Linux,并提供了一个统一的 API。

使用方法

1. 在 pubspec.yaml 中添加依赖
dependencies:
  siprix_voip_sdk: ^1.0.3
  provider: ^6.1.1
2. 添加导入
import 'package:provider/provider.dart';

import 'package:siprix_voip_sdk/accounts_model.dart';
import 'package:siprix_voip_sdk/network_model.dart';
import 'package:siprix_voip_sdk/calls_model.dart';
import 'package:siprix_voip_sdk/cdrs_model.dart';
import 'package:siprix_voip_sdk/devices_model.dart';
import 'package:siprix_voip_sdk/logs_model.dart';
import 'package:siprix_voip_sdk/siprix_voip_sdk.dart';
3. 准备模型
void main() async {
  AccountsModel accountsModel = AccountsModel();
  CallsModel callsModel = CallsModel(accountsModel);
  runApp(
    MultiProvider(providers:[
      ChangeNotifierProvider(create: (context) => accountsModel),
      ChangeNotifierProvider(create: (context) => callsModel),
    ],
    child: const MyApp(),
  ));
}
4. 初始化 SDK
class _MyAppState extends State<MyApp> {
  [@override](/user/override)
  void initState() {
    super.initState();
    _initializeSiprix();
  }

  void _initializeSiprix([LogsModel? logsModel]) async {
    InitData iniData = InitData();
    iniData.license  = "...license-credentials..."; // 替换为实际的许可证信息
    iniData.logLevelFile = LogLevel.info;
    //iniData.enableCallKit = true; <- 如果需要的话取消注释
    SiprixVoipSdk().initialize(iniData, logsModel);
  }
5. 构建 UI,添加账户/通话
Widget buildBody() {
    final accounts = context.watch<AccountsModel>();
    final calls = context.watch<CallsModel>();
    return Column(children: [
      ListView.separated(shrinkWrap: true,
        itemCount: accounts.length,
        separatorBuilder: (BuildContext context, int index) => const Divider(height: 1),
        itemBuilder: (BuildContext context, int index) {
          AccountModel acc = accounts[index];
          return 
            ListTile(title: Text(acc.uri, style: Theme.of(context).textTheme.titleSmall),
                subtitle: Text(acc.regText),
                tileColor: Colors.blue
            );
        },
      ),
      ElevatedButton(onPressed: _addAccount, child: const Icon(Icons.add_card)),
      ElevatedButton(onPressed: _addCall, child: const Icon(Icons.add_call)),
      // 其他UI组件
    ]);
}

void _addAccount() {
    AccountModel account = AccountModel();
    account.sipServer = "192.168.0.122";
    account.sipExtension = "1016";
    account.sipPassword = "12345";
    account.expireTime = 300;
    context.read<AccountsModel>().addAccount(account)
      .catchError(showSnackBar);
}

void _addCall() {
    final accounts = context.read<AccountsModel>();
    if(accounts.selAccountId==null) return;

    CallDestination dest = CallDestination("1012", accounts.selAccountId!, false);

    context.read<CallsModel>().invite(dest)
      .catchError(showSnackBar);
}
  
void showSnackBar(dynamic err) {
    ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(err)));
}

示例 Demo

以下是完整的示例代码,包含初始化、添加账户和发起通话的功能:

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';

import 'package:siprix_voip_sdk/accounts_model.dart';
import 'package:siprix_voip_sdk/network_model.dart';
import 'package:siprix_voip_sdk/calls_model.dart';
import 'package:siprix_voip_sdk/cdrs_model.dart';
import 'package:siprix_voip_sdk/devices_model.dart';
import 'package:siprix_voip_sdk/logs_model.dart';
import 'package:siprix_voip_sdk/subscriptions_model.dart';
import 'package:siprix_voip_sdk/siprix_voip_sdk.dart';

void main() async {  
  LogsModel logsModel = LogsModel(true); // 设置为false时不会在UI上渲染日志
  CdrsModel cdrsModel = CdrsModel(); // 最近通话记录列表

  DevicesModel devicesModel = DevicesModel(logsModel); // 设备列表
  NetworkModel networkModel = NetworkModel(logsModel); // 网络状态详情
  AccountsModel accountsModel = AccountsModel(logsModel); // 账户列表
  CallsModel callsModel = CallsModel(accountsModel, logsModel, cdrsModel); // 通话列表
  SubscriptionsModel subscrModel = SubscriptionsModel<BlfSubscrModel>(accountsModel, BlfSubscrModel.fromJson, logsModel); // 订阅列表

  // 运行应用
  runApp(
    MultiProvider(providers:[
      ChangeNotifierProvider(create: (context) => accountsModel),
      ChangeNotifierProvider(create: (context) => networkModel),
      ChangeNotifierProvider(create: (context) => devicesModel),
      ChangeNotifierProvider(create: (context) => subscrModel),
      ChangeNotifierProvider(create: (context) => callsModel),
      ChangeNotifierProvider(create: (context) => cdrsModel),
      ChangeNotifierProvider(create: (context) => logsModel),
    ],
    child: const MyApp(),
  ));
}

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

  static String _ringtonePath="";

  [@override](/user/override)
  State<MyApp> createState() => _MyAppState();

  /// 返回设备上保存的铃声路径
  static String getRingtonePath() => _ringtonePath;

  /// 将资产文件写入设备
  void writeRingtoneAsset() async {
    _ringtonePath = await writeAssetAndGetFilePath("ringtone.mp3");
  }

  /// 将资产文件写入设备并返回其路径
  static Future<String> writeAssetAndGetFilePath(String assetsFileName) async {
    var homeFolder = await SiprixVoipSdk().homeFolder();
    var filePath = '$homeFolder$assetsFileName';
    
    var file = File(filePath);
    var exists = file.existsSync();
    debugPrint("writeAsset: '$filePath' exists:$exists");
    if (exists) return filePath;

    final byteData = await rootBundle.load('assets/$assetsFileName');
    await file.create(recursive: true);
    file.writeAsBytes(byteData.buffer.asUint8List(), flush: true);
    return filePath;
  }

  /// 返回应用程序存储录制文件的文件夹路径
  static Future<String> getRecFilePath(String recFileName) async {
    var homeFolder = await SiprixVoipSdk().homeFolder();
    var filePath = '$homeFolder$recFileName';
    return filePath;
  }
}

class _MyAppState extends State<MyApp> {
  [@override](/user/override)
  void initState() {
    super.initState();

    _initializeSiprix(context.read<LogsModel>());
    widget.writeRingtoneAsset(); // 在初始化Siprix之后调用,因为它使用了'homeFolder'
    _readSavedState();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      routes: <String, WidgetBuilder>{
        // 定义路由
      },
      home: const HomePage(),
      title: 'Siprix VoIP app',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo),
        visualDensity: VisualDensity.adaptivePlatformDensity,
        useMaterial3: true,
      ),
    );
  }

  void _initializeSiprix(LogsModel? logsModel) async {
    InitData iniData = InitData();
    iniData.license  = "...license-credentials..."; // 替换为实际的许可证信息
    iniData.logLevelFile = LogLevel.debug;
    iniData.logLevelIde = LogLevel.info;
    //- 取消注释如果需要 -//
    //iniData.listenTelState = true;
    //iniData.singleCallMode = false;
    //iniData.tlsVerifyServer = false;
    //iniData.enableCallKit = true;
    SiprixVoipSdk().initialize(iniData, logsModel);

    // 设置视频参数(如果需要)
    //VideoData vdoData = VideoData();
    //vdoData.noCameraImgPath = await MyApp.writeAssetAndGetFilePath("noCamera.jpg");
    //vdoData.bitrateKbps = 800;
    //SiprixVoipSdk().setVideoParams(vdoData);
  }

  void _readSavedState() {
    SharedPreferences.getInstance().then((prefs) {
      String accJsonStr = prefs.getString('accounts') ?? '';
      String subsJsonStr = prefs.getString('subscriptions') ?? '';
      String cdrsJsonStr = prefs.getString('cdrs') ?? '';
      _loadModels(accJsonStr, cdrsJsonStr, subsJsonStr);
    });
  }

  void _loadModels(String accJsonStr, String cdrsJsonStr, String subsJsonStr) {
    // 账户
    AccountsModel accsModel = context.read<AccountsModel>();
    accsModel.onSaveChanges = _saveAccountChanges;
      
    // 订阅
    SubscriptionsModel subsModel = context.read<SubscriptionsModel>();
    subsModel.onSaveChanges = _saveSubscriptionChanges;

    // 呼叫详情记录
    CdrsModel cdrs = context.read<CdrsModel>();
    cdrs.onSaveChanges = _saveCdrsChanges;

    // 加载账户,然后加载其他模型
    accsModel.loadFromJson(accJsonStr).then((val)  {
      subsModel.loadFromJson(subsJsonStr);
      cdrs.loadFromJson(cdrsJsonStr);
    });

    // 分配联系人名称解析器
    context.read<CallsModel>().onResolveContactName = _resolveContactName;

    // 加载设备
    context.read<DevicesModel>().load();
  }

  void _saveCdrsChanges(String cdrsJsonStr) {
    SharedPreferences.getInstance().then((prefs) {
      prefs.setString('cdrs', cdrsJsonStr);
    });
  }

  void _saveAccountChanges(String accountsJsonStr) {
    SharedPreferences.getInstance().then((prefs) {
      prefs.setString('accounts', accountsJsonStr);
    });
  }

  void _saveSubscriptionChanges(String subscrJsonStr) {
    SharedPreferences.getInstance().then((prefs) {
      prefs.setString('subscriptions', subscrJsonStr);
    });
  }

  String _resolveContactName(String phoneNumber) {
    return ""; //TODO 添加自己的实现
    //if(phoneNumber=="100") { return "MyFriend100"; } else
    //if(phoneNumber=="101") { return "MyFriend101"; } 
    //else                  { return "";        }
  }
}

更多关于Flutter VoIP通信插件siprix_voip_sdk的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter VoIP通信插件siprix_voip_sdk的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter项目中使用siprix_voip_sdk插件进行VoIP通信的代码示例。这个插件允许你通过SIP协议进行音频和视频通话。请注意,在实际应用中,你需要确保你的Flutter环境和相关依赖已经正确配置。

1. 添加依赖

首先,你需要在你的pubspec.yaml文件中添加siprix_voip_sdk依赖:

dependencies:
  flutter:
    sdk: flutter
  siprix_voip_sdk: ^最新版本号  # 请替换为实际可用的最新版本号

然后运行flutter pub get来安装依赖。

2. 配置Android权限

android/app/src/main/AndroidManifest.xml中添加必要的权限:

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>

3. 初始化SDK

在你的Flutter项目的lib/main.dart文件中,初始化并配置siprix_voip_sdk

import 'package:flutter/material.dart';
import 'package:siprix_voip_sdk/siprix_voip_sdk.dart';

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

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  SiprixVoipSdk? siprixVoipSdk;

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

  void initSiprixVoipSdk() async {
    siprixVoipSdk = SiprixVoipSdk();

    // 配置SIP账户
    await siprixVoipSdk?.configureSipAccount(
      sipUsername: 'your_sip_username',
      sipPassword: 'your_sip_password',
      sipDomain: 'your_sip_domain',
      sipPort: 5060, // 默认SIP端口
      transportType: SipTransportType.udp, // 或tcp, ws, wss等
    );

    // 注册SIP账户
    siprixVoipSdk?.registerSipAccount()?.then((registrationResult) {
      if (registrationResult) {
        print('SIP Account Registered Successfully');
      } else {
        print('SIP Account Registration Failed');
      }
    });

    // 监听来电事件
    siprixVoipSdk?.onIncomingCall?.listen((callInfo) {
      print('Incoming Call: ${callInfo.callerId}');
      // 处理来电逻辑,如显示来电界面等
    });

    // 监听挂断事件
    siprixVoipSdk?.onCallEnded?.listen((callInfo) {
      print('Call Ended: ${callInfo.callId}');
      // 处理挂断逻辑,如更新UI等
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter VoIP Demo'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              ElevatedButton(
                onPressed: () async {
                  // 发起呼叫
                  await siprixVoipSdk?.makeCall('callee_sip_address');
                },
                child: Text('Make Call'),
              ),
              ElevatedButton(
                onPressed: () {
                  // 挂断当前呼叫
                  siprixVoipSdk?.endCall();
                },
                child: Text('End Call'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

4. 处理权限请求

在实际应用中,你还需要处理Android和iOS上的权限请求。这通常涉及在运行时检查并请求权限。由于篇幅限制,这里不展开详细说明,但你可以使用permission_handler等Flutter插件来处理权限请求。

注意事项

  1. SIP服务器配置:确保你的SIP服务器地址、用户名和密码等信息正确无误。
  2. 网络配置:检查设备的网络连接,确保能够访问SIP服务器。
  3. 错误处理:在实际应用中,你应该添加更多的错误处理逻辑,以确保用户体验。

以上代码是一个基本的示例,展示了如何使用siprix_voip_sdk进行VoIP通信。根据你的具体需求,你可能需要添加更多的功能和逻辑。

回到顶部