agora.io's voice call doesn't work in flutter

26 views Asked by At

I wanna to get voice call function in my app(using flutter). Here is my code and log.

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'MainScreen.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:agora_rtc_engine/agora_rtc_engine.dart';
import 'package:permission_handler/permission_handler.dart';
import 'dart:core';

// ChatRoom 모델
class ChatRoom {
  final String title;
  final int limit;
  final bool isPrivate;
  final String password;
  final String ownerId;
  final String ownerPhotoUrl;
  final String ownerNickname;


  ChatRoom({
    required this.title,
    required this.limit,
    required this.isPrivate,
    required this.password,
    required this.ownerId,
    required this.ownerPhotoUrl,
    required this.ownerNickname,


  });

  Map<String, dynamic> toMap() {
    return {
      'title': title,
      'limit': limit,
      'isPrivate': isPrivate,
      'password': password,
      'ownerId': ownerId,
      'ownerPhotoUrl': ownerPhotoUrl,
      'ownerNickname': ownerNickname,
    };
  }
}



class VoiceChatRoomScreen extends StatefulWidget {
  final String roomId;


  VoiceChatRoomScreen({Key? key, required this.roomId}) : super(key: key);

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

class _VoiceChatRoomScreenState extends State<VoiceChatRoomScreen> {
  String appId = "af65ec64fd244043a786ba6b820fa01f";
  int uid = 0; // uid of the local user

  int? _remoteUid; // uid of the remote user
  bool _isJoined = false; // Indicates if the local user has joined the channel
  late RtcEngine agoraEngine; // Agora engine instance

  final GlobalKey<ScaffoldMessengerState> scaffoldMessengerKey
  = GlobalKey<ScaffoldMessengerState>(); // Global key to access the scaffold

  showMessage(String message) {
    scaffoldMessengerKey.currentState?.showSnackBar(SnackBar(
      content: Text(message),
    ));
  }



  List<Map<String, dynamic>> members = [];
  String ownerId = '';
  final DatabaseReference _userStatusRef = FirebaseDatabase.instance.reference()
      .child('usersStatus');
  List<String> onlineMembers = [];

  @override
  void initState() {
    super.initState();
    // 채팅방 정보와 멤버 정보를 로드하는 기존의 메서드를 유지합니다.
    _loadRoomInfo();
    _loadRoomMembers();
    setupVoiceSDKEngine().then((_) {
      join(); // Ensure join is called after setupVoiceSDKEngine is completed
    });
  }

  Future<void> setupVoiceSDKEngine() async {
    // retrieve or request microphone permission
    await [Permission.microphone].request();

    //create an instance of the Agora engine
    agoraEngine = createAgoraRtcEngine();
    await agoraEngine.initialize(RtcEngineContext(
        appId: appId
    ));

    // Register the event handler
    agoraEngine.registerEventHandler(
      RtcEngineEventHandler(
        onJoinChannelSuccess: (RtcConnection connection, int elapsed) {
          showMessage("Local user uid:${connection.localUid} joined the channel");
          setState(() {
            _isJoined = true;
          });
          print("Local user joined the channel");
        },
        onUserJoined: (RtcConnection connection, int remoteUid, int elapsed) {
          showMessage("Remote user uid:$remoteUid joined the channel");
          setState(() {
            _remoteUid = remoteUid;
          });
          print("Remote user joined the channel with uid: $remoteUid");
        },
        onUserOffline: (RtcConnection connection, int remoteUid,
            UserOfflineReasonType reason) {
          showMessage("Remote user uid:$remoteUid left the channel");
          setState(() {
            _remoteUid = null;
          });
          print("Remote user left the channel with uid: $remoteUid");
        },
      ),


    );

  }

  Future<void> join() async {
    ChannelMediaOptions options = const ChannelMediaOptions(
      clientRoleType: ClientRoleType.clientRoleBroadcaster,
      channelProfile: ChannelProfileType.channelProfileCommunication,
    );

    await agoraEngine.joinChannel(
      token: widget.roomId,
      channelId: widget.roomId ,
      options: options,
      uid: uid,
    );
    print("Channel join request sent with channelId: ${widget.roomId}");
  }



  // 채팅방 정보를 로드하는 메서드

  Future<void> _loadRoomInfo() async {
    DocumentSnapshot roomSnapshot = await FirebaseFirestore.instance
        .collection('chatRooms')
        .doc(widget.roomId)
        .get();

    if (roomSnapshot.exists) {
      Map<String, dynamic> roomData = roomSnapshot.data() as Map<String,
          dynamic>;
      setState(() {
        ownerId = roomData['ownerId'];
        print("방장 ID: $ownerId"); // 방장 ID 로그 출력
      });
    }
  }


  @override
  void dispose() {
    // WebRTC 리소스 정리

    // 채팅방을 떠나는 로직. 예를 들어, 서버에 'leave' 메시지를 보낼 수 있습니다.
    leaveChatRoom().then((_) {
      // 채팅방을 떠난 후, 메인 화면으로 돌아갑니다.
      Navigator.of(context).pushAndRemoveUntil(
        MaterialPageRoute(builder: (context) => MainScreen()),
            (Route<dynamic> route) => false,
      );
    });
    agoraEngine.leaveChannel();


    super.dispose();
  }


  Future<void> leaveChatRoom() async {
    final userId = FirebaseAuth.instance.currentUser?.uid;
    if (userId != null) {
      // 사용자를 오프라인으로 설정

      // 'chatRooms/{roomId}/members/{userId}' 문서 삭제
      await FirebaseFirestore.instance
          .collection('chatRooms')
          .doc(widget.roomId)
          .collection('members')
          .doc(userId)
          .delete();


      setState(() {
        _isJoined = false;
        _remoteUid = null;
      });
      agoraEngine.leaveChannel();

    }
  }


  Future<void> _loadRoomMembers() async {
    FirebaseFirestore.instance
        .collection('chatRooms')
        .doc(widget.roomId)
        .collection('members')
        .snapshots()
        .listen((snapshot) async {
      // 온라인 상태인 사용자 ID 목록을 가져옵니다.

      // 멤버 목록을 업데이트합니다.
      List<Map<String, dynamic>> updatedMembers = [];
      for (var doc in snapshot.docs) {
        String memberId = doc.id;

        Map<String, dynamic> memberData = doc.data() as Map<String, dynamic>;
        updatedMembers.add(memberData);
      }

      if (mounted) {
        setState(() {
          members = updatedMembers;
        });
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    // UI 구성 부분은 이전과 동일하되, 방장 여부 확인 로직을 추가합니다.
    return Scaffold(
      appBar: AppBar(
        title: Text('음성 채팅방'),
      ),
      body: members.isEmpty
          ? Center(child: CircularProgressIndicator())
          : ListView.builder(
        itemCount: members.length,
        itemBuilder: (context, index) {
          bool isOwner = members[index]['uid'] == ownerId; // 방장 여부 판단
          return ListTile(
            leading: CircleAvatar(
              backgroundImage: NetworkImage(members[index]['photoUrl']),
              radius: 25,
            ),
            title: Text(members[index]['nickname']),
            trailing: isOwner
                ? Text(
                '방장', style: TextStyle(color: Colors.red)) // 방장일 경우 "King" 표시
                : null,
          );
        },
      ),
    );
  }
}

,,,,

and the log is saying I succeeded to enter the voice channel.


[info] [iris_rtc_api_engine.cc:407] api name RtcEngine_initialize_0320339 result 0 outdata {"result":0}
[info] [iris_rtc_api_engine.cc:343] api name RtcEngine_setAppType params "{"appType":4}"
[info] [iris_rtc_api_engine.cc:407] api name RtcEngine_setAppType result 0 outdata {"result":0}
[info] [iris_rtc_api_engine.cc:343] api name RtcEngine_registerEventHandler_5fc0465 params "{}"
[info] [i
ris_rtc_api_engine.cc:395] api name RtcEngine_registerEventHandler_5fc0465 extened params "{"event":10796528752}"
[info] [iris_rtc_api_engine.cc:407] api name RtcEngine_registerEventHandler_5fc0465 result 0 outdata {"result":0}
[info] [iris_rtc_api_engine.cc:341] api name RtcEngine_joinChannel_cdbb747 params "{"token":"qOEc***************GPsO","channelId":"qOEcnJcSyg1I4DgSGPsO","uid":0,"options":{"clientRoleType":1,"channelProfile":0}}"
[info] [iris_rtc_api_engine.cc:407] api name RtcEngine_joinChannel_cdbb747 result 0 outdata {"result":0}
flutter: Channel join request sent with channelId: qOEcnJcSyg1I4DgSGPsO

but the voice call doesn't work in my voiceroom... what do i have to do??!!


E/libc    (17700): Access denied finding property "net.dns1"
E/libc    (17700): Access denied finding property "net.dns2"
E/libc    (17700): Access denied finding property "net.dns3"
E/libc    (17700): Access denied finding property "net.dns4"

and whenever I say to phone, these emerged...

I wanna get voice call function in my flutter app

0

There are 0 answers