اذهب إلى المحتوى
  • 0

اتاحة امكانية بث حي من تطبيق Flutter

جوزيف ناثان

السؤال

Recommended Posts

  • 0

توجد شركة agara يمكنك قراءة التوثيق الخاص بها من هنا , تقريباً هي أفضل شركة تقدم خدمات live Streaming.

بعد الاشتراك في هذه الخدمة يمكنك تضمين مكتبة agora_rtc_engine  داخل مشروعك يمكنك إيجاد المكتبة من هنا.

في ملف pubspec.yaml تضع التالي 

agora_rtc_engine: ^3.3.3

ثم تقوم بتنفيذ الأمر التالي 

flutter pub get

بعد الاشتراك ستجد APPI_ID, TOKEN  حيث في ملف main.dart ستقوم بوضع كليهما بهذا الشكل 

const APP_ID = '';
const Token = '';

ثم تقوم بتعريف ملف main.dart بهذا الشكل 

import 'dart:async';

import 'package:agora_rtc_engine/rtc_engine.dart';
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Live Stream',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: homePage(),
    );
  }
}

ثم تقوم بتعريف homePage بهذا الشكل 

class homePage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => IndexState();
}

class IndexState extends State<homePage> {
  final _channelController = TextEditingController();
  bool _validateError = false;
  ClientRole _role = ClientRole.Broadcaster;

  @override
	void dispose() {
		// dispose input controller
		_channelController.dispose();
		super.dispose();
	}
	
	@override
	Widget build(BuildContext context) {
	  return Scaffold(
		appBar: AppBar(
		  title: Text('Agora Flutter QuickStart'),
		),
		body: Center(
		  child: Container(
			padding: const EdgeInsets.symmetric(horizontal: 20),
			height: 400,
			child: Column(
			  children: <Widget>[
				Row(
				  children: <Widget>[
					Expanded(
						child: TextField(
					  controller: _channelController,
					  decoration: InputDecoration(
						errorText:
							_validateError ? 'Channel name is mandatory' : null,
						border: UnderlineInputBorder(
						  borderSide: BorderSide(width: 1),
						),
						hintText: 'Channel name',
					  ),
					))
				  ],
				),
				Column(
				  children: [
					ListTile(
					  title: Text(ClientRole.Broadcaster.toString()),
					  leading: Radio(
						value: ClientRole.Broadcaster,
						groupValue: _role,
						onChanged: (ClientRole value) {
						  setState(() {
							_role = value;
						  });
						},
					  ),
					),
					ListTile(
					  title: Text(ClientRole.Audience.toString()),
					  leading: Radio(
						value: ClientRole.Audience,
						groupValue: _role,
						onChanged: (ClientRole value) {
						  setState(() {
							_role = value;
						  });
						},
					  ),
					)
				  ],
				),
				Padding(
				  padding: const EdgeInsets.symmetric(vertical: 20),
				  child: Row(
					children: <Widget>[
					  Expanded(
						child: RaisedButton(
						  onPressed: joinStream,
						  child: Text('Join'),
						  color: Colors.green,
						  textColor: Colors.black,
						),
					  )
					],
				  ),
				)
			  ],
			),
		  ),
		),
	  );
	}
	  /// زر الانضمام إلى البث
	  Future<void> joinStream() async {
		setState(() {
		  _channelController.text.isEmpty
			  ? _validateError = true
			  : _validateError = false;
		});
		if (_channelController.text.isNotEmpty) {
		  // انتظر إذن الكاميرا والميكروفون
		  await _handleCameraAndMic();
		  // أدخل صفحة البث المباشر وانضم إلى القناة باستخدام اسم القناة والدور المحدد في صفحة تسجيل الدخول
		  await Navigator.push(
			context,
			MaterialPageRoute(
			  builder: (context) => CallPage(
				channelName: _channelController.text,
				role: _role,
			  ),
			),
		  );
		}
	  }

	  // لتفعيل الكاميرا و المايكرفون
	  Future<void> _handleCameraAndMic() async {
		await PermissionHandler().requestPermissions(
		  [PermissionGroup.camera, PermissionGroup.microphone],
		);
	  }
}

كود صفحة البث , يوجد شرح مضمن بداخله للدوال  

class livePage extends StatefulWidget {
  final String channelName;
  final ClientRole role;
  const livePage({Key key, this.channelName, this.role}) : super(key: key);

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

class _livePageState extends State<CallPage> {
  final _users = <int>[];
  final _infoStrings = <String>[];
  bool muted = false;
  RtcEngine _engine;



  @override
  void dispose() {
    _users.clear();
    _engine.leaveChannel();
    _engine.destroy();
    super.dispose();
  }

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

  Future<void> initialize() async {
    if (APP_ID.isEmpty) {
      setState(() {
        _infoStrings.add(
          'مفقود ، يرجى تقديم APP_ID الخاص بك في',
        );
        _infoStrings.add('Agora Engine is not starting');
      });
      return;
    }

    await _initAgoraRtcEngine();
    _addAgoraEventHandlers();
        /// Join channel
    await _engine.joinChannel(Token, widget.channelName, null, 0);
  }
  
  
    // تخطيط شريط الأدوات
  Widget _toolbar() {
    if (widget.role == ClientRole.Audience) return Container();
    return Container(
      alignment: Alignment.bottomCenter,
      padding: const EdgeInsets.symmetric(vertical: 48),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          RawMaterialButton(
            onPressed: _onToggleMute,
            child: Icon(
              muted ? Icons.mic_off : Icons.mic,
              color: muted ? Colors.white : Colors.blueAccent,
              size: 20.0,
            ),
            shape: CircleBorder(),
            elevation: 2.0,
            fillColor: muted ? Colors.blueAccent : Colors.white,
            padding: const EdgeInsets.all(12.0),
          ),
          RawMaterialButton(
            onPressed: () => _onCallEnd(context),
            child: Icon(
              Icons.call_end,
              color: Colors.white,
              size: 35.0,
            ),
            shape: CircleBorder(),
            elevation: 2.0,
            fillColor: Colors.redAccent,
            padding: const EdgeInsets.all(15.0),
          ),
          RawMaterialButton(
            onPressed: _onSwitchCamera,
            child: Icon(
              Icons.switch_camera,
              color: Colors.blueAccent,
              size: 20.0,
            ),
            shape: CircleBorder(),
            elevation: 2.0,
            fillColor: Colors.white,
            padding: const EdgeInsets.all(12.0),
          )
        ],
      ),
    );
  }
  
  
  Future<void> _initAgoraRtcEngine() async {
	  RtcEngineConfig config = RtcEngineConfig(APP_ID);
	  _engine = await RtcEngine.createWithConfig(config);
	  await _engine.setChannelProfile(ChannelProfile.LiveBroadcasting);
	  await _engine.setClientRole(widget.role);
	}

void _addAgoraEventHandlers() {
  _engine.setEventHandler(RtcEngineEventHandler(error: (code) {
    setState(() {
      final info = 'onError: $code';
      _infoStrings.add(info);
    });
  }, joinChannelSuccess: (channel, uid, elapsed) {
    setState(() {
      final info = 'onJoinChannel: $channel, uid: $uid';
      _infoStrings.add(info);
    });
  }, leaveChannel: (stats) {
    setState(() {
      _infoStrings.add('onLeaveChannel');
      _users.clear();
    });
  }, userJoined: (uid, elapsed) {
    setState(() {
      final info = 'userJoined: $uid';
      _infoStrings.add(info);
      _users.add(uid);
    });
  }, userOffline: (uid, elapsed) {
    setState(() {
      final info = 'userOffline: $uid';
      _infoStrings.add(info);
      _users.remove(uid);
    });
  }));
}

	  /// تخطيط شريط الأدوات
  Widget _toolbar() {
    if (widget.role == ClientRole.Audience) return Container();
    return Container(
      alignment: Alignment.bottomCenter,
      padding: const EdgeInsets.symmetric(vertical: 48),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          RawMaterialButton(
            onPressed: _onToggleMute,
            child: Icon(
              muted ? Icons.mic_off : Icons.mic,
              color: muted ? Colors.white : Colors.blueAccent,
              size: 20.0,
            ),
            shape: CircleBorder(),
            elevation: 2.0,
            fillColor: muted ? Colors.blueAccent : Colors.white,
            padding: const EdgeInsets.all(12.0),
          ),
          RawMaterialButton(
            onPressed: () => _onCallEnd(context),
            child: Icon(
              Icons.call_end,
              color: Colors.white,
              size: 35.0,
            ),
            shape: CircleBorder(),
            elevation: 2.0,
            fillColor: Colors.redAccent,
            padding: const EdgeInsets.all(15.0),
          ),
          RawMaterialButton(
            onPressed: _onSwitchCamera,
            child: Icon(
              Icons.switch_camera,
              color: Colors.blueAccent,
              size: 20.0,
            ),
            shape: CircleBorder(),
            elevation: 2.0,
            fillColor: Colors.white,
            padding: const EdgeInsets.all(12.0),
          )
        ],
      ),
    );
  }


 // لوحة معلومات لعرض السجلات
  Widget _panel() {
    return Container(
      padding: const EdgeInsets.symmetric(vertical: 48),
      alignment: Alignment.bottomCenter,
      child: FractionallySizedBox(
        heightFactor: 0.5,
        child: Container(
          padding: const EdgeInsets.symmetric(vertical: 48),
          child: ListView.builder(
            reverse: true,
            itemCount: _infoStrings.length,
            itemBuilder: (BuildContext context, int index) {
              if (_infoStrings.isEmpty) {
                return null;
              }
              return Padding(
                padding: const EdgeInsets.symmetric(
                  vertical: 3,
                  horizontal: 10,
                ),
                child: Row(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    Flexible(
                      child: Container(
                        padding: const EdgeInsets.symmetric(
                          vertical: 2,
                          horizontal: 5,
                        ),
                        decoration: BoxDecoration(
                          color: Colors.yellowAccent,
                          borderRadius: BorderRadius.circular(5),
                        ),
                        child: Text(
                          _infoStrings[index],
                          style: TextStyle(color: Colors.blueGrey),
                        ),
                      ),
                    )
                  ],
                ),
              );
            },
          ),
        ),
      ),
    );
  }

	// وقف البث المباشر
	void _onCallEnd(BuildContext context) {
		Navigator.pop(context);
	  }

	  /// صامت
	  void _onToggleMute() {
		setState(() {
		  muted = !muted;
		});
		_engine.muteLocalAudioStream(muted);
	  }

	  @override
	  Widget build(BuildContext context) {
		return Scaffold(
		  appBar: AppBar(
			title: Text('Agora Flutter QuickStart'),
		  ),
		  backgroundColor: Colors.black,
		  body: Center(
			child: Stack(
			  children: <Widget>[
				_panel(),
				_toolbar(),
			  ],
			),
		  ),
		);
	  }
}

هذه الأكواد مجرد أمثلة يمكنك مراجعة توثيق agora من هنا فكل شيء مشروح بشكلٍ مفصل لكيفية تضمين المكتبة و الاشتراك في الخدمة.

رابط هذا التعليق
شارك على الشبكات الإجتماعية

انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أجب على هذا السؤال...

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.

  • إعلانات

  • تابعنا على



×
×
  • أضف...