Flutter实时音视频通信插件janus的使用

发布于 1周前 作者 zlyuanteng 来自 Flutter

Flutter实时音视频通信插件janus的使用

特性

Janus 提供了一个简单的 API 来在本地存储中加密持久化模型。

CAPTION: 不支持 Flutter Web

入门指南

使用这个包非常简单。以下示例将展示如何在内存中存储一些偏好设置:

class Preferences extends Janus {

    const Preferences(
        {this.token = '', 
        this.lightTheme = true, 
        this.fontSize = 15.0,
        this.firstLoading = true,
        this.shoppingCartProducts = const []})
         : super(cypher: true);
}

    final String token;
    final bool lightTheme;
    final double fontSize;
    final bool firstLoading;
    final List<String> shoppingCartProducts = [];

    Map<String,dynamic> toMap() => {
        'token': token,
        'lightTheme': lightTheme,
        'fontSize': fontSize,
        'firstLoading': firstLoading,
        'shoppingCartProducts': shoppingCartProducts
    };

    factory Preferences.fromMap(Map<String,dynamic> map) 
        => Preferences(
            token: map['token'],
            lightTheme: map['lightTheme'],
            fontSize: map['fontSize'],
            firstLoading: map['firstLoading'],
            shoppingCartProducts: map['shoppingCartProducts']
        );

void main()async{
    final preferences = Preferences();
    final data = {
        'token': 'TOKEN',
        'lightTheme': false,
        'fontSize': 22.2,
        'firstLoading': false,
        'shoppingCartProducts': ['Uuid1','Uuid2','Uuid3']
    };

    await preferences.save(data);
    final loadedPreferences = Preferences.fromMap(await preferences.load());
}

使用方法

个人建议不要直接扩展 Janus 到你的数据模型中。相反,尝试将数据层分为三个部分:

  • 模型
  • API
  • 仓库

APIs 文件夹将包含提供对 Web 服务或本地存储访问的类。这里可能是可以扩展 Janus 的类。

//apis/user_model.dart

class User {
  final String id;
  final String name;
  final String email;
  User({
    required this.id,
    required this.name,
    required this.email,
  });

  Map<String, dynamic> toMap() {
    return <String, dynamic>{
      'id': id,
      'name': name,
      'email': email,
    };
  }

  factory User.fromMap(Map<String, dynamic> map) {
    return User(
      id: map['id']  ?? '',
      name: map['name'] ?? '',
      email: map['email'] ?? '',
    );
  }
}

//apis/user_storage.dart

class UserStorage extends Janus{
  UserStorage() : super(cypher: true);
}

//repositories/user_storage_repository.dart
class UserRepo {
  final api = UserStorage();

  Future<void> save(User user)async{
    await api.save(user.toMap());
  }

  Future<User> load() async{
    return User.fromMap(await api.load());
  }
}

//现在你可以使用仓库来将用户保存到本地内存中,或者从本地加载它。
final userRepository = UserRepo();
final User user = User(id: 'uuid', name:'name',email: 'myemail@address.com');
await userRepository.save(user);

final loadedUser = await userRepository.load();

额外信息

完整示例代码

以下是完整的示例代码,展示如何使用 janus 插件进行本地数据存储。

示例代码文件结构

example/
├── lib/
   ├── main.dart
   └── apis/
       └── user_model.dart
   └── repositories/
       └── user_storage_repository.dart

示例代码 lib/main.dart

import 'dart:convert';
import 'dart:developer';

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

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() async {
    setState(() {
      _counter++;
    });
    final Counter counter = Counter(number: _counter);
    final counterStorage = CounterStorage();
    await counterStorage.save(counter.toMap());
  }

  void getCounter() async {
    final counterStorage = CounterStorage();
    final counter = Counter.fromMap(await counterStorage.load());
    setState(() {
      _counter = counter.number;
    });
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              '你已经按下了按钮多少次:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: '增加',
        child: const Icon(Icons.add),
      ),
    );
  }
}

class Counter {
  final int number;
  const Counter({
    required this.number,
  });

  Map<String, dynamic> toMap() {
    return <String, dynamic>{
      'number': number,
    };
  }

  factory Counter.fromMap(Map<String, dynamic> map) {
    return Counter(
      number: map['number'] ?? 0,
    );
  }
}

class CounterStorage extends Janus {
  CounterStorage() : super(cypher: true);
}

示例代码 lib/apis/user_model.dart

class User {
  final String id;
  final String name;
  final String email;
  User({
    required this.id,
    required this.name,
    required this.email,
  });

  Map<String, dynamic> toMap() {
    return <String, dynamic>{
      'id': id,
      'name': name,
      'email': email,
    };
  }

  factory User.fromMap(Map<String, dynamic> map) {
    return User(
      id: map['id'] ?? '',
      name: map['name'] ?? '',
      email: map['email'] ?? '',
    );
  }
}

示例代码 lib/repositories/user_storage_repository.dart

import 'dart:async';

import 'package:janus/janus.dart';

class UserStorage extends Janus {
  UserStorage() : super(cypher: true);
}

class UserRepo {
  final api = UserStorage();

  Future<void> save(User user) async {
    await api.save(user.toMap());
  }

  Future<User> load() async {
    return User.fromMap(await api.load());
  }
}

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

1 回复

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


在Flutter中实现实时音视频通信,可以使用janus_client插件,这是一个用于与Janus Gateway进行通信的Flutter插件。Janus Gateway是一个开源的WebRTC服务器,支持多种实时通信功能,如音视频通话、屏幕共享、录制等。

以下是如何在Flutter项目中使用janus_client插件的基本步骤:

1. 添加依赖

首先,在pubspec.yaml文件中添加janus_client插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  janus_client: ^0.1.0  # 请检查最新版本

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

2. 初始化Janus客户端

在你的Flutter应用中,初始化Janus客户端并连接到Janus Gateway。

import 'package:janus_client/janus_client.dart';

void initJanus() async {
  JanusTransport transport = JanusTransport(
    url: 'wss://your-janus-server.com:8989/janus', // Janus WebSocket URL
    withCredentials: true,
  );

  JanusClient janusClient = JanusClient(
    transport: transport,
    iceServers: [
      RTCIceServer(
        urls: 'stun:stun.l.google.com:19302',
      ),
      // 添加其他ICE服务器
    ],
  );

  await janusClient.connect();

  // 创建会话
  JanusSession session = await janusClient.createSession();

  // 附加插件
  JanusPlugin plugin = await session.attachPlugin('janus.plugin.videoroom');

  // 处理插件事件
  plugin.messages?.listen((event) {
    print('Received message: $event');
  });

  // 加入视频房间
  var joinResponse = await plugin.send({
    'request': 'join',
    'room': 1234, // 房间ID
    'ptype': 'publisher',
    'display': 'Flutter User',
  });

  print('Join response: $joinResponse');
}

3. 处理音视频流

在加入房间后,你可以使用WebRTC来处理音视频流。janus_client插件内部使用了flutter_webrtc来处理WebRTC相关的操作。

import 'package:flutter_webrtc/flutter_webrtc.dart';

void handleLocalStream(MediaStream stream) {
  // 显示本地视频流
  RTCVideoRenderer localRenderer = RTCVideoRenderer();
  await localRenderer.initialize();
  localRenderer.srcObject = stream;

  // 在UI中显示视频
  // 例如:使用VideoPlayer或RTCVideoView
}

void handleRemoteStream(MediaStream stream) {
  // 显示远程视频流
  RTCVideoRenderer remoteRenderer = RTCVideoRenderer();
  await remoteRenderer.initialize();
  remoteRenderer.srcObject = stream;

  // 在UI中显示视频
  // 例如:使用VideoPlayer或RTCVideoView
}

4. 处理信令和媒体协商

Janus Gateway会通过信令通道与客户端进行媒体协商。你需要在插件的事件监听器中处理这些信令消息,并根据需要创建或更新WebRTC连接。

5. 断开连接

在应用退出或用户离开房间时,确保断开与Janus Gateway的连接。

void disposeJanus() async {
  await plugin.detach();
  await session.destroy();
  await janusClient.disconnect();
}

6. 处理错误和异常

在实际应用中,你需要处理各种可能的错误和异常,例如网络连接问题、ICE协商失败等。

try {
  await janusClient.connect();
} catch (e) {
  print('Failed to connect to Janus: $e');
}
回到顶部
AI 助手
你好,我是IT营的 AI 助手
您可以尝试点击下方的快捷入口开启体验!