Flutter屏幕投射插件castscreen的使用

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

Flutter屏幕投射插件castscreen的使用

dart_castscreen 是一个Dart包,可以将视频流投射到UPnP和DLNA设备上。以下是该插件的主要功能和示例代码。

功能

  • 发现UPnP客户端/设备
  • 客户端/设备/服务/操作的规范
  • 调用泛型或映射的操作
  • 提供了丰富的扩展

示例

发现客户端

import 'package:castscreen/castscreen.dart';

void main(List<String> args) async {
  final clients = await CastScreen.discoverClient();
  for (var client in clients) {
    print(client);
  }
}

带选项发现客户端

import 'package:castscreen/castscreen.dart';

void main(List<String> args) async {
  final clients = await CastScreen.discoverClient(
    ipv4: true,
    ipv6: false,
    port: 1900,
    ST: 'upnp:rootdevice',
    timeout: const Duration(seconds: 3),
    onError: (Exception e) => print('error: $e'),
  );
  for (var client in clients) {
    print(client);
  }
}

发现设备

import 'package:castscreen/castscreen.dart';

void main(List<String> args) async {
  final devices = await CastScreen.discoverDevice();
  for (var device in devices) {
    print(device);
  }
}

带选项发现设备

import 'package:castscreen/castscreen.dart';

void main(List<String> args) async {
  final devices = await CastScreen.discoverDevice(
    ipv4: true,
    ipv6: false,
    port: 1900,
    ST: 'upnp:rootdevice',
    timeout: const Duration(seconds: 3),
    onError: (Exception e) => print('error: $e'),
  );
  for (var device in devices) {
    print(device);
  }
}

调用泛型操作

import 'package:castscreen/castscreen.dart';

void main(List<String> args) async {
  final devices = await CastScreen.discoverDevice();
  final dev = devices.first;
  final alive = await dev.alive();
  if (!alive) {
    print('Device is not alive.');
    return;
  }
  final output = await dev.avTransportService!
      .invoke<CustomActionInput, CustomActionOutput>(
    'Custom',
    CustomActionInput(),
    CustomActionInput.toMap,
    CustomActionOutput.fromMap,
  );
  print(output);
}

final class CustomActionInput {
  const CustomActionInput();
  static Map<String, String> toMap(CustomActionInput input) {
    return {};
  }
}

final class CustomActionOutput {
  const CustomActionOutput();
  factory CustomActionOutput.fromMap(Map<String, String> m) {
    return const CustomActionOutput();
  }
}

调用映射操作

import 'package:castscreen/castscreen.dart';

void main(List<String> args) async {
  final devices = await CastScreen.discoverDevice();
  final dev = devices.first;
  final alive = await dev.alive();
  if (!alive) {
    print('Device is not alive.');
    return;
  }
  final output = await dev.avTransportService!.invokeMap('Custom', {});
  print(output);
}

设置AVTransportURI

import 'package:castscreen/castscreen.dart';

void main(List<String> args) async {
  final devices = await CastScreen.discoverDevice();
  final dev = devices.first;
  final alive = await dev.alive();
  if (!alive) {
    print('Device is not alive.');
    return;
  }
  final output = await dev
      .setAVTransportURI(SetAVTransportURIInput('http://example.com/v.mp4'));
  print(output);
}

停止播放

import 'package:castscreen/castscreen.dart';

void main(List<String> args) async {
  final devices = await CastScreen.discoverDevice();
  final dev = devices.first;
  final alive = await dev.alive();
  if (!alive) {
    print('Device is not alive.');
    return;
  }
  final output = await dev.stop(StopInput());
  print(output);
}

Flutter示例应用

以下是一个完整的Flutter示例应用,展示了如何使用 dart_castscreen 插件来发现设备、播放和停止视频流。

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

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'CastScreen Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'CastScreen Demo Home Page'),
    );
  }
}

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

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  List<Device> devices = [];
  Device? curDev;
  final String playUrl = 'https://leshiyuncdn.ahjunqin.top/20240109/BWCSLaI6/index.m3u8';

  Future<void> search() async {
    devices = await CastScreen.discoverDevice(timeout: const Duration(seconds: 3));
    curDev = null;
    setState(() {});
  }

  Future<void> play() async {
    if (curDev == null) {
      return;
    }
    final alive = await curDev!.alive();
    if (!alive) {
      return;
    }
    await curDev!.setAVTransportURI(SetAVTransportURIInput(playUrl));
  }

  Future<void> stop() async {
    if (curDev == null) {
      return;
    }
    final alive = await curDev!.alive();
    if (!alive) {
      return;
    }
    await curDev!.stop(const StopInput());
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            const Text('选择设备:'),
            devices.isNotEmpty
                ? DropdownButton<Device>(
                    value: curDev,
                    elevation: 16,
                    style: const TextStyle(color: Colors.deepPurple),
                    underline: Container(
                      height: 2,
                      color: Colors.deepPurpleAccent,
                    ),
                    onChanged: (Device? value) {
                      curDev = value;
                      setState(() {});
                    },
                    items: devices.map<DropdownMenuItem<Device>>((dev) {
                      return DropdownMenuItem<Device>(
                        value: dev,
                        child: Text(dev.spec.friendlyName),
                      );
                    }).toList(),
                  )
                : const Text('无设备'),
            TextButton(onPressed: search, child: const Text('Search')),
            TextButton(onPressed: play, child: const Text('Play')),
            TextButton(onPressed: stop, child: const Text('Stop')),
          ],
        ),
      ),
    );
  }
}

这个示例应用展示了如何:

  1. 发现可用的UPnP/DLNA设备。
  2. 选择一个设备进行投射。
  3. 播放和停止视频流。

希望这些示例能帮助你更好地理解和使用 dart_castscreen 插件。如果你有任何问题或需要进一步的帮助,请随时提问!


更多关于Flutter屏幕投射插件castscreen的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter屏幕投射插件castscreen的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter中使用cast_screen插件来实现屏幕投射功能的代码示例。请注意,cast_screen插件可能不是官方的Flutter插件,因此在实际项目中,你可能需要找到类似功能的插件或自行实现。不过,这里我会基于一个假设的插件接口来提供一个示例。

首先,你需要在pubspec.yaml文件中添加cast_screen插件的依赖(假设它存在):

dependencies:
  flutter:
    sdk: flutter
  cast_screen: ^x.y.z  # 替换为实际的版本号

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

接下来,在你的Flutter项目中,你可以按照以下步骤来实现屏幕投射功能:

  1. 导入必要的包
import 'package:flutter/material.dart';
import 'package:cast_screen/cast_screen.dart';  // 假设这是插件的包名
  1. 初始化并启动屏幕投射

在你的主页面或者需要投射屏幕的地方,你可以初始化并启动屏幕投射。下面是一个简单的示例:

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: CastScreenPage(),
    );
  }
}

class CastScreenPage extends StatefulWidget {
  @override
  _CastScreenPageState createState() => _CastScreenPageState();
}

class _CastScreenPageState extends State<CastScreenPage> {
  CastScreen? _castScreen;
  bool _isCasting = false;

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

  Future<void> _initCastScreen() async {
    // 初始化CastScreen插件
    _castScreen = await CastScreen.init();

    // 监听设备发现事件
    _castScreen?.deviceDiscovered?.listen((CastDevice device) {
      // 在这里处理发现的设备,比如显示设备列表
      print("Device discovered: ${device.name}");
    });

    // 监听连接状态变化事件
    _castScreen?.castingStateChanged?.listen((CastingState state) {
      setState(() {
        _isCasting = state == CastingState.connected;
      });
    });
  }

  Future<void> _startCasting(CastDevice device) async {
    if (!_isCasting) {
      try {
        await _castScreen?.startCasting(device);
      } catch (e) {
        print("Failed to start casting: $e");
      }
    } else {
      print("Already casting...");
    }
  }

  Future<void> _stopCasting() async {
    if (_isCasting) {
      try {
        await _castScreen?.stopCasting();
      } catch (e) {
        print("Failed to stop casting: $e");
      }
    } else {
      print("Not casting...");
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Cast Screen Example"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text("Casting: $_isCasting"),
            ElevatedButton(
              onPressed: () async {
                // 这里应该有一个设备选择逻辑,这里简化为直接调用_startCasting
                // 假设我们已经有了一个CastDevice对象叫做selectedDevice
                CastDevice selectedDevice = /* 获取或选择一个CastDevice */;
                await _startCasting(selectedDevice);
              },
              child: Text("Start Casting"),
            ),
            ElevatedButton(
              onPressed: () async {
                await _stopCasting();
              },
              child: Text("Stop Casting"),
            ),
          ],
        ),
      ),
    );
  }
}

注意

  • 上面的代码是一个简化的示例,实际上你需要处理设备的发现、选择以及错误处理等。
  • CastDeviceCastingState是假设的类,你需要根据实际的插件API进行调整。
  • 插件的API可能会变化,因此请参考你使用的cast_screen插件的官方文档。

由于cast_screen插件可能不是一个真实存在的官方插件,因此在实际项目中,你可能需要寻找一个功能相似的插件,比如flutter_cast或者其他支持DLNA/Chromecast等协议的插件,并根据其文档进行相应的实现。

回到顶部