shogo4405 / HaishinKit.dart

Camera and Microphone streaming library via RTMP for Flutter.
https://pub.dev/packages/haishin_kit
BSD 3-Clause "New" or "Revised" License
32 stars 20 forks source link

Draggable turns black when moved #34

Closed kevin4dhd closed 1 year ago

kevin4dhd commented 1 year ago

Describe the bug

Hello, I am using a Draggable so that when transmitting I can move the camera, when it starts it looks good but when I move it it looks black, is there any way to use NetStreamDrawableTexture with Draggable?

To Reproduce

Wrap NetStreamDrawableTexture in a Draggable, just that

Expected behavior

That you can continue to see the preview camera when you move it

Version

0.9.4

Smartphone info.

0.9.4

Additional context

No response

Screenshots

https://github.com/shogo4405/HaishinKit.dart/assets/22886367/4ab3ce46-a31f-43df-bf41-d39f0cfc6360

Relevant log output

No response

shogo4405 commented 1 year ago

t's unclear whether it's a specification issue with Flutter or a bug in the library.

kevin4dhd commented 1 year ago

Here is an example


import 'package:audio_session/audio_session.dart';
import 'package:flutter/material.dart';
import 'package:haishin_kit/audio_source.dart';
import 'package:haishin_kit/net_stream_drawable_texture.dart';
import 'package:haishin_kit/rtmp_connection.dart';
import 'package:haishin_kit/rtmp_stream.dart';
import 'package:haishin_kit/video_source.dart';
import 'package:permission_handler/permission_handler.dart';

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

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

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

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

class _MyHomePageState extends State<MyHomePage> {
  RtmpConnection? _connection;
  RtmpStream? _stream;
  bool _recording = false;
  CameraPosition currentPosition = CameraPosition.back;

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

  Future<void> initPlatformState() async {
    await Permission.camera.request();
    await Permission.microphone.request();

    // Set up AVAudioSession for iOS.
    final session = await AudioSession.instance;
    await session.configure(const AudioSessionConfiguration(
      avAudioSessionCategory: AVAudioSessionCategory.playAndRecord,
      avAudioSessionCategoryOptions:
          AVAudioSessionCategoryOptions.allowBluetooth,
    ));

    RtmpConnection connection = await RtmpConnection.create();
    connection.eventChannel.receiveBroadcastStream().listen((event) {
      switch (event["data"]["code"]) {
        case 'NetConnection.Connect.Success':
          _stream?.publish("live");
          setState(() {
            _recording = true;
          });
          break;
      }
    });
    RtmpStream stream = await RtmpStream.create(connection);
    stream.attachAudio(AudioSource());
    stream.attachVideo(VideoSource(position: currentPosition));

    if (!mounted) return;

    setState(() {
      _connection = connection;
      _stream = stream;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('HaishinKit example app'), actions: [
        IconButton(
          icon: const Icon(Icons.flip_camera_android),
          onPressed: () {
            if (currentPosition == CameraPosition.front) {
              currentPosition = CameraPosition.back;
            } else {
              currentPosition = CameraPosition.front;
            }
            _stream?.attachVideo(VideoSource(position: currentPosition));
          },
        )
      ]),
      body: _stream == null
          ? const Text("")
          : Stack(
              children: [
                DraggableWidgetEmisor(
                  child: Stack(
                    children: [
                      AspectRatio(
                          aspectRatio: 9 / 16,
                          child: NetStreamDrawableTexture(_stream)),
                    ],
                  ),
                ),
              ],
            ),
      floatingActionButton: FloatingActionButton(
        child: _recording
            ? const Icon(Icons.fiber_smart_record)
            : const Icon(Icons.not_started),
        onPressed: () {
          if (_recording) {
            _connection?.close();
            setState(() {
              _recording = false;
            });
          } else {
            _connection?.connect("rtmp://192.168.1.9/live");
          }
        },
      ),
    );
  }
}

class DraggableWidgetEmisor extends StatefulWidget {
  final Widget child;

  DraggableWidgetEmisor({
    required this.child,
  });

  @override
  _DraggableWidgetStateEmisor createState() => _DraggableWidgetStateEmisor();
}

class _DraggableWidgetStateEmisor extends State<DraggableWidgetEmisor> {
  Offset offset = Offset.zero;
  final double widgetWidth = 90 * 2;
  final double widgetHeight = 160 * 2;
  final double valorExtranio = 29;

  Widget get draggableChild => Container(
        width: widgetWidth,
        height: widgetHeight,
        color: Colors.black,
        child: Center(child: widget.child),
      );

  @override
  Widget build(BuildContext context) {
    var screenSize = MediaQuery.of(context).size;

    return Positioned(
      left: offset.dx,
      top: offset.dy,
      child: Draggable(
        feedback: Material(
          type: MaterialType.transparency,
          child: draggableChild,
        ),
        childWhenDragging: Container(),
        onDragEnd: (details) {
          setState(() {
            double dx = details.offset.dx;
            double dy = details.offset.dy;

            dy = dy - valorExtranio;

            // Verifica que el widget no se salga de los bordes horizontales de la pantalla
            if (dx < 0) dx = 0;
            if (dx > screenSize.width - widgetWidth) {
              dx = screenSize.width - widgetWidth;
            }

            // Verifica que el widget no se salga de los bordes verticales de la pantalla
            if (dy < 0) {
              dy = 0;
            }
            if (dy > screenSize.height - widgetHeight - (valorExtranio)) {
              dy = screenSize.height - widgetHeight - (valorExtranio);
            }

            offset = Offset(dx, dy);
          });
        },
        child: draggableChild,
      ),
    );
  }
}