{"id":15724123,"url":"https://github.com/mobinx/easymeet-js","last_synced_at":"2026-01-03T00:03:41.796Z","repository":{"id":254614372,"uuid":"846925013","full_name":"MobinX/EasyMeet-js","owner":"MobinX","description":"EasyMeetjs is a robust and versatile TypeScript library that provides a solid foundation for building WebRTC-based applications. It simplifies the complexities of WebRTC, enabling developers to easily incorporate real-time communication features into their projects.From simple audio video calling to real time peer to peer file transfer , everything","archived":false,"fork":false,"pushed_at":"2024-09-01T17:46:34.000Z","size":1551,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-22T09:14:52.344Z","etag":null,"topics":["data","meeting","react","realtime","screensharing","streaming-video","webrtc","zoom"],"latest_commit_sha":null,"homepage":"https://meetupx.vercel.app/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MobinX.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-08-24T10:45:42.000Z","updated_at":"2024-09-01T17:48:25.000Z","dependencies_parsed_at":"2024-08-24T19:28:09.411Z","dependency_job_id":"0f08b78c-db51-4fe9-8f86-670b3274e094","html_url":"https://github.com/MobinX/EasyMeet-js","commit_stats":null,"previous_names":["mobinx/easymeet-js"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MobinX%2FEasyMeet-js","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MobinX%2FEasyMeet-js/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MobinX%2FEasyMeet-js/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MobinX%2FEasyMeet-js/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MobinX","download_url":"https://codeload.github.com/MobinX/EasyMeet-js/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243318767,"owners_count":20272136,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["data","meeting","react","realtime","screensharing","streaming-video","webrtc","zoom"],"created_at":"2024-10-03T22:14:51.258Z","updated_at":"2026-01-03T00:03:41.766Z","avatar_url":"https://github.com/MobinX.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n# EasyMeetjs: The easiest yet flexible and robust webrtc libraty for react and javascript with typescript support\n\n**EasyMeetjs** is a robust and versatile TypeScript library that provides a solid foundation for building WebRTC-based applications. It simplifies the complexities of WebRTC, enabling developers to easily incorporate real-time communication features into their projects.From simple audio video calling to real time peer to peer file transfer , everything can be done in just 40 lines! 😉😉\n\n## Demo app implemented using this library\n [MeetUp -\u003e  https://meetupx.vercel.app/](https://meetupx.vercel.app/)\n\n## Key Features:\n\n* **Peer-to-Peer Connection Management:** Seamlessly handles the creation, management, and closure of WebRTC peer connections, facilitating direct communication between users.\n* **Media Handling (Audio/Video/Screen Sharing):** Supports capturing, sending, and receiving audio, video, and screen share streams, enriching the communication experience.\n* **Data Channels:** Enables the exchange of arbitrary data between peers, extending the possibilities beyond just audio and video.\n* **File Transfer:** Implements a file transfer mechanism leveraging data channels, allowing users to share files directly.\n* **State Management and Event Handling:** Maintains and updates the state of peers, media streams, and file transfers, providing callbacks to react to changes.\n* **Well-Structured and Comprehensive:** Encapsulates the complexities of WebRTC, offering a convenient interface for developers to build upon.\n\n## Installation:\n\n```bash\nnpm install @mobinx/easymeet\n```\n\n## Usage: (React Next.js - using meterd iceServers and ably as socket server)\n\nMeet.tsx\n```typescript\n\"use client\"\nimport Ably from \"ably\";\nimport { useEasyMeet } from \"@mobinx/easymeet/react\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { FileState } from \"@mobinx/easymeet\";\n\nconst ably = new Ably.Realtime({ key: 'your-ably-api-key', clientId: Math.random().toString(36).substring(7) })\nably.connection.once('connected').then(() =\u003e {\n    console.log('Connected to Ably!');\n})\nconst channel = ably.channels.get('quickstart');\nchannel.presence.enter(\"mobin\");\n\n\n\nasync function sendmsg(msg: any, to: any) {\n  await channel.publish(\"greeting\", {\n    data: msg,\n    clientId: ably.auth.clientId,\n    to: to,\n  });\n  console.log(\"message sent: \", msg);\n}\n\nconst VIdeo = ({ stream }: { stream: MediaStream }) =\u003e {\n  let viref = useRef\u003cHTMLVideoElement | null\u003e(null);\n  let [isPlay, setIsPlay] = useState(false);\n  useEffect(() =\u003e {\n    if (viref.current) {\n      viref.current.srcObject = stream;\n      viref.current?.play();\n      viref.current.onplaying = () =\u003e {\n        console.log(\"playing\");\n        setIsPlay(true);\n      };\n      viref.current.onpause = () =\u003e {\n        console.log(\"pause\");\n        setIsPlay(false);\n        viref.current?.play();\n      };\n\n      if (viref.current.paused) {\n        viref.current.play();\n      }\n    }\n  });\n\n  return (\n    \u003cvideo\n      ref={viref}\n      playsInline\n      autoPlay\n      muted\n      style={{ width: \"100%\" }}\n      controls={true}\n    \u003e\u003c/video\u003e\n  );\n};\n\nconst AUdeo = ({ stream }: { stream: MediaStream }) =\u003e {\n  let viref = useRef\u003cHTMLAudioElement | null\u003e(null);\n  let [isPlay, setIsPlay] = useState(false);\n  useEffect(() =\u003e {\n    if (viref.current) {\n      viref.current.srcObject = stream;\n      viref.current?.play();\n      viref.current.onplaying = () =\u003e {\n        console.log(\"playing\");\n        setIsPlay(true);\n      };\n      viref.current.onpause = () =\u003e {\n        console.log(\"pause\");\n        setIsPlay(false);\n        viref.current?.play();\n      };\n\n      if (viref.current.paused) {\n        viref.current.play();\n      }\n    }\n  });\n\n  return (\n    \u003caudio\n      ref={viref}\n      playsInline\n      autoPlay\n      style={{ width: \"100%\" }}\n      controls={true}\n    \u003e\u003c/audio\u003e\n  );\n};\n\nexport default function Meet({ iceServers }: { iceServers: any }) {\n  const isInit = useRef\u003cboolean | null\u003e(null);\n  const {\n    isSystemReady,\n    joinExistingPeer,\n    joinNewPeer,\n    leavePeer,\n    sendFile,\n    fileSharingCompleted,\n    fileSharingState,\n    onSocketMessage,\n    sendDataChannelMsg,\n    newDataChannelMsg,\n    toggleAudio,\n    toggleCamera,\n    toggleScreenShare,\n    isAudioOn,\n    isVideoOn,\n    isScreenShareOn,\n    audioStream,\n    videoStream,\n    screenShareStream,\n    peers,\n  } = useEasyMeet(ably.auth.clientId, iceServers, sendmsg);\n  const [myMsg, setMyMsg] = useState\u003cstring\u003e(\"\");\n  const [allMsg, setAllMsg] = useState\u003c{ from: string; msg: string }[]\u003e([]);\n  const [fileProgress, setFileProgress] = useState\u003c\n    {\n      id: string;\n      progress: number;\n      url?: string | null;\n      fileState?: FileState;\n    }[]\n  \u003e([]);\n  useEffect(() =\u003e {\n    console.log(peers);\n  }, [peers]);\n  useEffect(() =\u003e {\n    if (fileSharingState) {\n      setFileProgress((prev) =\u003e {\n        let tempArray = [];\n        prev.map((item) =\u003e {\n          if (item.id != fileSharingState.fileId) {\n            tempArray.push(item);\n          }\n        });\n        tempArray.push({\n          id: fileSharingState.fileId,\n          progress: fileSharingState.progress,\n          fileState: fileSharingState,\n        });\n        return tempArray;\n      });\n    }\n  }, [fileSharingState]);\n  useEffect(() =\u003e {\n    console.log(fileSharingCompleted);\n    if (fileSharingCompleted) {\n      setFileProgress((prev) =\u003e {\n        let tempArray = [];\n        prev.map((item) =\u003e {\n          if (item.id != fileSharingCompleted.file.fileId) {\n            tempArray.push(item);\n          }\n        });\n        tempArray.push({\n          id: fileSharingCompleted.file.fileId,\n          progress: 100,\n          url: fileSharingCompleted.objectUrl,\n          fileState: fileSharingCompleted.file,\n        });\n        return tempArray;\n      });\n    }\n  }, [fileSharingCompleted]);\n  useEffect(() =\u003e {\n    if (newDataChannelMsg) {\n      setAllMsg((prev) =\u003e prev.concat([newDataChannelMsg]));\n    }\n  }, [newDataChannelMsg]);\n  useEffect(() =\u003e {\n    async function init() {\n      if (!isInit.current) {\n        if (isSystemReady) {\n          console.log(\"isSystemReady\");\n          await channel.subscribe(\"greeting\", async (message) =\u003e {\n            if (message.clientId === ably.auth.clientId) {\n              return;\n            }\n            if (message.data.to === ably.auth.clientId) {\n              console.log(\"message received from: \" + message.clientId);\n              await onSocketMessage(message.data.data, message.clientId!, null);\n            }\n          });\n          channel.presence.subscribe(\"enter\", async function (member) {\n            if (member.clientId === ably.auth.clientId) {\n              return;\n            }\n            console.log(\"informAboutNewConnection\", member);\n            joinNewPeer(member.clientId);\n          });\n\n          channel.presence.subscribe(\"leave\", async function (member) {\n            if (member.clientId === ably.auth.clientId) {\n              return;\n            }\n            console.log(\"leave\", member);\n            leavePeer(member.clientId);\n          });\n          channel.presence.get().then((other_users: any) =\u003e {\n            console.log(\"userconnected\", other_users);\n            if (other_users) {\n              for (var i = 0; i \u003c other_users.length; i++) {\n                if (other_users[i].clientId !== ably.auth.clientId)\n                  joinExistingPeer(other_users[i].clientId, false);\n              }\n            }\n          });\n\n          isInit.current = true;\n        }\n      }\n    }\n\n    init();\n  }, [\n    isSystemReady,\n    joinExistingPeer,\n    joinNewPeer,\n    leavePeer,\n    onSocketMessage,\n  ]);\n\n  return (\n    \u003cdiv className=\"flex flex-row space-x-3\"\u003e\n      my id: {ably.auth.clientId}\n      \u003cinput\n        value={myMsg}\n        onChange={(e) =\u003e setMyMsg(e.target.value)}\n        className=\"bg-gray-200\"\n      /\u003e\n      \u003cbutton\n        onClick={() =\u003e {\n          sendDataChannelMsg(myMsg, \"all\");\n          setAllMsg((prev) =\u003e\n            prev.concat([{ from: ably.auth.clientId, msg: myMsg }])\n          );\n          setMyMsg(\"\");\n        }}\n      \u003e\n        send\n      \u003c/button\u003e\n      \u003cinput\n        type=\"file\"\n        onChange={async (e) =\u003e {\n          const file = e.target.files?.[0];\n          if (file) {\n            peers.forEach((peer) =\u003e {\n              sendFile(peer.socketId, file);\n            });\n          }\n        }}\n      /\u003e\n      \u003cbutton className=\"mx-2\" onClick={async () =\u003e await toggleAudio()}\u003e\n        {isAudioOn ? \"mute\" : \"unmute\"}\n      \u003c/button\u003e\n      \u003cbutton onClick={async () =\u003e await toggleCamera()}\u003e\n        {isVideoOn ? \"camera off\" : \"camera on\"}\n      \u003c/button\u003e\n      \u003cbutton onClick={async () =\u003e await toggleScreenShare()}\u003e\n        {isScreenShareOn ? \"stop screen share\" : \"start screen share\"}\n      \u003c/button\u003e\n      \u003cdiv\u003e\n        {isVideoOn \u0026\u0026 \u003cVIdeo stream={videoStream!} /\u003e}\n        {isScreenShareOn \u0026\u0026 \u003cVIdeo stream={screenShareStream!} /\u003e}\n      \u003c/div\u003e\n      \u003chr /\u003e\n      {allMsg.map((msg, key) =\u003e (\n        \u003cdiv key={key}\u003e\n          {msg.from} : {msg.msg}\n        \u003c/div\u003e\n      ))}\n      \u003chr /\u003e\n      \u003chr /\u003e\n      \u003cdiv\u003e\n        {fileProgress.map((item, key) =\u003e {\n          return (\n            \u003cdiv key={key}\u003e\n              id: {item.fileState?.fileName}\n              \u003cprogress max=\"100\" value={item.progress}\u003e\u003c/progress\u003e\n              {item.url \u0026\u0026 (\n                \u003ca href={item.url} download={item.fileState?.fileName}\u003e\n                  download\n                \u003c/a\u003e\n              )}\n            \u003c/div\u003e\n          );\n        })}\n      \u003c/div\u003e\n      \u003cdiv\u003e\n        {peers.map((peer, key) =\u003e (\n          \u003cdiv key={key}\u003e\n            Peer Id: {peer.socketId}\n            {peer.isScreenShareOn \u0026\u0026 \u003cVIdeo stream={peer.screenShareStream!} /\u003e}\n            {peer.isVideoOn \u0026\u0026 \u003cVIdeo stream={peer.videoStream!} /\u003e}\n            {peer.isAudioOn \u0026\u0026 \u003cAUdeo stream={peer.audioStream!} /\u003e}\n          \u003c/div\u003e\n        ))}\n      \u003c/div\u003e\n    \u003c/div\u003e\n  );\n}\n\n\n\n```\n\npage.tsx\n\n```typescript\nimport Image from \"next/image\";\nimport dynamic from \"next/dynamic\";\n\nconst Meet = dynamic(() =\u003e import(\"./Meet\"), { ssr: false });\n\n\nexport default async function Home() {\n  const response = await fetch(\"your-metered-api-key\");\n  const iceServers = await response.json();\n  console.log(iceServers);\n  return (\n    \u003cdiv\u003e\n      \u003cMeet iceServers={iceServers} /\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n## Usage: (Html with Jquery , Meterd and ably)\nindex.html\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n\n\u003chead\u003e\n\n    \u003cmeta name=\"viewport\" content=\"width=device-width\" /\u003e\n    \u003ctitle\u003eMulti Conn App\u003c/title\u003e\n    \u003cscript src=\"https://cdn.ably.com/lib/ably.min-1.js\"\u003e\u003c/script\u003e\n    \u003cscript src=\"https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.4/socket.io.js\"\u003e\u003c/script\u003e\n    \u003cscript src=\"https://unpkg.com/jquery@3.7.1/dist/jquery.js\"\u003e\u003c/script\u003e\n    \u003c!-- \u003cscript src=\"scripts/jquery.signalR-2.2.2.min.js\"\u003e\u003c/script\u003e --\u003e\n    \u003c!-- \u003cscript src=\"https://localhost:44338/signalr/hubs\"\u003e\u003c/script\u003e --\u003e\n    \u003cscript src=\"https://unpkg.com/@mobinx/easymeet@1.0.4/dist/easy-meet.min.js\"\u003e\u003c/script\u003e\n    \u003c!-- \u003cscript type=\"module\"\u003e\n        import WebrtcBase from './dist/index.js';\n       \n    \u003c/script\u003e --\u003e\n    \u003cscript src=\"app.js\"\u003e\u003c/script\u003e\n\n\n\n    \u003cscript\u003e\n\n        $(function () {\n\n            const urlParams = new URLSearchParams(window.location.search);\n\n            var meeting_id = urlParams.get('mid');\n\n            // if (!meeting_id) {\n            //     var murl = window.location.origin + \"?mid=\" +  (new Date()).getTime();\n            //     $('#meetingid').attr('href',murl).text(murl);\n            //     $(\"#meetingContainer\").hide();\n            //     $(\"#meetingbox\").show();\n            //     return;\n            // }\n\n            // var user_id = urlParams.get('uid');\n            // if (!user_id) {\n            //     user_id = window.prompt('Enter your nick!');\n            // }\n\n            // if (!user_id || !meeting_id) {\n            //     alert('user id or meeting id missing');\n            //     return;\n            // }\n            $(\"#meetingContainer\").show();\n            $(\"#meetingbox\").hide();\n\n            // MyApp._init(user_id,meeting_id);\n\n        });\n    \u003c/script\u003e\n\u003c/head\u003e\n\n\u003cbody\u003e\n\n\n\n    \u003cdiv id=\"meetingContainer\" style=\"display: none;\"\u003e\n        \u003ch1 id='meetingname'\u003e\u003c/h1\u003e\n        \u003cinput type=\"file\" id=\"fileinput\" /\u003e\n        \u003cbutton id=\"btnsendfile\"\u003eSend File\u003c/button\u003e\n        \u003cdiv id=\"fileprogress\"\u003e\u003c/div\u003e\n        \u003cdiv\u003e\n\n            \u003cinput type=\"text\" id=\"msgbox\" /\u003e\n            \u003cbutton id=\"btnsend\"\u003eSend\u003c/button\u003e\n\n            \u003cdiv id='messages'\u003e\u003c/div\u003e\n\n            \u003cdiv id='divUsers' style=\"display:none\"\u003e\n                \u003cdiv id=\"me\" class=\"userbox\"\u003e\n                    \u003ch2\u003e\u003c/h2\u003e\n                    \u003cdiv\u003e\n                        \u003cvideo autoplay muted id=\"localVideoCtr\"\u003e\u003c/video\u003e\n                        \u003cvideo autoplay muted id=\"localScreenVideoCtr\"\u003e\u003c/video\u003e\n\n                    \u003c/div\u003e\n                \u003c/div\u003e\n                \u003cdiv id=\"otherTemplate\" class=\"userbox\" style=\"display:none\"\u003e\n                    \u003ch2\u003e\u003c/h2\u003e\n                    \u003cdiv\u003e\n                        \u003cvideo autoplay muted id=\"remoteVideoCtr111 \" class=\"video\"\u003e\u003c/video\u003e\n                        \u003cvideo autoplay muted id=\"remoteVideoCtr111\" class=\"screen\"\u003e\u003c/video\u003e\n\n                        \u003caudio autoplay controls id=\"remoteAudioCtr111\" class=\"audio\"\u003e\u003c/audio\u003e\n                    \u003c/div\u003e\n                \u003c/div\u003e\n            \u003c/div\u003e\n        \u003c/div\u003e\n\n        \u003cdiv style=\"clear: both;\"\u003e\u003c/div\u003e\n        \u003cdiv class=\"toolbox\" style=\"display:none\"\u003e\n            \u003cbutton id=\"btnMuteUnmute\"\u003eUnMute\u003c/button\u003e\n            \u003cbutton id=\"btnStartStopCam\"\u003eStart Camera\u003c/button\u003e\n            \u003cbutton id=\"btnStartStopScreenshare\"\u003eScreen Share\u003c/button\u003e\n        \u003c/div\u003e\n    \u003c/div\u003e\n    \u003cbr\u003e\n    \u003cbr\u003e\n\n\n\n\u003c/body\u003e\n\n\u003c/html\u003e\n```\napp.js\n```javascript\n(async () =\u003e {\n\n    const response = await fetch(\"https://virsys.metered.live/api/v1/turn/credentials?apiKey=ca9f4e60bf446fc29401ccb1fa904d110708\");\n    const iceServers = await response.json();\n    let isWrtcInit = false;\n    const ably = new Ably.Realtime({ key: 'YSXfdw.ksCpsA:Bf6jKYu4LPPpMfiFkSMJrZ4q4ArLDkuBf7bJCPxKQUo', clientId: Math.random().toString(36).substring(7) });\n    ably.connection.once('connected').then(async () =\u003e {\n        console.log('Connected to Ably!');\n    })\n    const myid = ably.auth.clientId;\n    console.log('myid: ', myid);\n    const channel = ably.channels.get('quickstart');\n    let easymeet = new EasyMeet.WebrtcBase(ably.auth.clientId, iceServers, sendmsg,);\n    document.title = myid;\n\n    async function sendmsg(msg, to) {\n        await channel.publish('greeting', { data: msg, clientId: myid, to: to });\n        console.log('message sent: ', msg);\n    }\n\n\n\n    await channel.subscribe('greeting', async (message) =\u003e {\n\n        // clientid ==  sender from\n        // id == receiver (to)\n        if (message.clientId === myid) {\n            //checking i am not worikng on my own msg\n            return;\n        } else {\n\n            if (message.data.to === myid) {\n                //checking if the msg is for me\n                console.log('message received from: ' + message.clientId);\n               \n                console.log(message);\n                await easymeet.onSocketMessage(message.data.data, message.clientId);\n\n            }\n\n        }\n\n    });\n\n    let _localVideoPlayer = document.getElementById('localVideoCtr');\n    let localScreenVideoCtr = document.getElementById('localScreenVideoCtr');\n\n    easymeet.onFileStateChange((fileState) =\u003e {\n\n        console.log(fileState);\n        if (document.getElementById('fileprogress' + fileState.fileId) == null) {\n            let progress = document.createElement('progress');\n            progress.id = 'fileprogress' + fileState.fileId;\n            progress.value = parseInt(fileState.progress);\n            progress.max = 100;\n            $(\"#fileprogress\").append(progress);\n        }\n        else {\n            document.getElementById('fileprogress' + fileState.fileId).value = parseInt(fileState.progress);\n        }\n\n        // $(\"#fileprogress\").append(`\u003cdiv\u003e${(fileState.progress) + \"%  \" + parseInt(fileState.transferSpeed) + \"kb/s\" }  \u003c/div\u003e`)\n    })\n    easymeet.onFileTransferCompleted((fileState, objectURl) =\u003e {\n        console.log(fileState, objectURl);\n        $(\"#fileprogress\").append(`\u003cdiv\u003eCompleted\u003c/div\u003e`)\n        document.getElementById('fileprogress' + fileState.fileId).value = 100;\n\n        // // $(\"#fileprogress\").append(`\u003cdiv\u003e${JSON.stringify(fileState)}\u003c/div\u003e`)\n        $(\"#fileprogress\").append(`\u003ca href=\"${objectURl}\" download=\"${fileState.fileName}\"\u003e${objectURl}\u003c/a\u003e`)\n    })\n\n    $(\"#btnsendfile\").on('click', async function () {\n        let file = document.getElementById('fileinput').files[0];\n        console.log(file);\n        (easymeet.getAllPeerDetails()).forEach(element =\u003e {\n            console.log(element.socketId);\n            easymeet.sendFile(element.socketId, file);\n        });\n\n    });\n \n\n    easymeet.onCameraVideoStateChange((state, stream) =\u003e {\n        if (state) {\n            _localVideoPlayer.srcObject = stream;\n        }\n        else {\n            _localVideoPlayer.srcObject = null;\n        }\n\n    })\n    easymeet.onScreenShareVideoStateChange((state, stream) =\u003e {\n        if (state) {\n            localScreenVideoCtr.srcObject = stream;\n        }\n        else {\n            localScreenVideoCtr.srcObject = null;\n        }\n\n    })\n\n    $(\"#btnMuteUnmute\").on('click', async function () {\n        await easymeet.toggleAudio()\n\n    });\n    $(\"#btnStartStopCam\").on('click', async function () {\n        await easymeet.toggleCamera();\n    });\n\n    $(\"#btnStartStopScreenshare\").on('click', async function () {\n        await easymeet.toggleScreenShare();\n    })\n\n    easymeet.onDataChannelMsg((from, msg) =\u003e {\n        console.log(\"onDataChannelMsg\", from, msg);\n        $(\"#messages\").append(\"\u003cli\u003e\" + from + \": \" + msg + \"\u003c/li\u003e\");\n    })\n\n    easymeet.onPeerStateChange((peerstate) =\u003e {\n        if (peerstate) {\n            console.log(\"peerstate\", peerstate);\n            for (let peerz in peerstate) {\n                let pr = peerstate[peerz];\n                let remoteElm = document.getElementById(peerstate[peerz].socketId);\n                if (!remoteElm) {\n                    AddNewUser(peerstate[peerz].socketId, peerstate[peerz].socketId);\n                }\n                let video = remoteElm.querySelector('.video'), audio = remoteElm.querySelector('audio'), screen = remoteElm.querySelector('.screen');\n                if (pr.isAudioOn) {\n                    if (audio) {\n                        audio.srcObject = peerstate[peerz].audioStream;\n                        audio.play();\n                    }\n                }\n                else {\n                    if (audio) {\n                        audio.srcObject = null;\n                    }\n                }\n                if (pr.isVideoOn) {\n                    if (video) {\n                        video.srcObject = peerstate[peerz].videoStream;\n                    }\n                }\n                else {\n                    if (video) {\n                        video.srcObject = null;\n                    }\n                }\n\n                if (pr.isScreenShareOn) {\n                    if (screen) {\n                        screen.srcObject = peerstate[peerz].screenShareStream;\n                    }\n                }\n                else {\n                    if (screen) {\n                        screen.srcObject = null;\n                    }\n                }\n\n\n\n            }\n        }\n    })\n\n\n    channel.presence.subscribe('enter', async function (member) {\n        if (member.clientId === myid) {\n            return;\n        }\n        console.log(\"informAboutNewConnection\", member);\n        AddNewUser(member.clientId, member.clientId);\n        easymeet.createConnection(member.clientId, true);\n    });\n\n    channel.presence.subscribe('leave', async function (member) {\n        if (member.clientId === myid) {\n            return;\n        }\n        $('#' + member.clientId).remove();\n        easymeet.closeConnection(member.clientId);\n    });\n    channel.presence.get(function (err, other_users) {\n        console.log(\"userconnected\", other_users);\n        $('#divUsers .other').remove();\n        if (other_users) {\n            for (var i = 0; i \u003c other_users.length; i++) {\n                AddNewUser(other_users[i].clientId, other_users[i].clientId);\n                easymeet.createConnection(other_users[i].clientId, false);\n            }\n        }\n        $(\".toolbox\").show();\n        $('#messages').show();\n        $('#divUsers').show();\n    });\n\n\n    $('#btnResetMeeting').on('click', function () {\n        socket.emit('reset');\n    });\n\n    $('#btnsend').on('click', function () {\n        //_hub.server.sendMessage($('#msgbox').val());\n        easymeet.sendDataChannelMsg(\"all\", $('#msgbox').val());\n\n    });\n\n    $('#divUsers').on('dblclick', 'video', function () {\n        this.requestFullscreen();\n    });\n\n\n    function AddNewUser(other_user_id, connId) {\n        var $newDiv = $('#otherTemplate').clone();\n        $newDiv = $newDiv.attr('id', connId).addClass('other');\n        $newDiv.find('h2').text(other_user_id);\n        $newDiv.find('video').attr('id', 'v_' + connId);\n        $newDiv.find('audio').attr('id', 'a_' + connId);\n        $newDiv.show();\n        $('#divUsers').append($newDiv);\n    }\n    channel.presence.enter(\"mobin\");\n})();\n\n```\n\n\n\n## Public API for core library (vanilla js)\n**Public Methods:**\n\nThis table provides a detailed description of all public methods available in the `WebrtcBase` class from @mobinx/easymeet:\n\nlike \n```javascript\nlet webrtc = new EasyMeet.WebrtcBase(\"you-socket-id\", iceServers, sendmsg /*the function used by easymeet system for sending msg to other over socket, takes msg and to ,two perameter , see usages example avobe */);\n\n```\n\n| Method                                     | Description                                                                                           | Usage Example                                                                                                                                                |\n|-------------------------------------------|-------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `createConnection(connid, polite, extraInfo)` | Establishes a WebRTC connection with a peer.                                                          | `webrtc.createConnection('peer-id', false, { username: 'Alice' });`                                                                                          |\n| `closeConnection(connid)`                  | Closes the connection with a specific peer.                                                            | `webrtc.closeConnection('peer-id');`                                                                                                                             |\n| `onSocketMessage(message, from_connid, extraInfo)` | Handles incoming signaling messages from a peer.                                                    | `webrtc.onSocketMessage(JSON.stringify({ offer: offer }), 'peer-id', { username: 'Bob' });`                                                                |\n| `onPeerStateChange(fn)`                   | Registers a callback to be notified of peer state changes (e.g., audio/video on/off).                 | `webrtc.onPeerStateChange((peerStates) =\u003e { console.log('Peer states updated:', peerStates); });`                                                               |\n| `getAllPeerDetails()`                     | Returns an array of details for all connected peers.                                                 | `const peerDetails = webrtc.getAllPeerDetails(); console.log('Connected peers:', peerDetails);`                                                              |\n| `getPeerDetailsById(connid)`              | Returns the details of a specific peer by their connection ID.                                         | `const peerDetails = webrtc.getPeerDetailsById('peer-id'); console.log('Peer details:', peerDetails);`                                                         |\n| `startCamera(cameraConfig)`                | Starts the user's camera with optional configuration (resolution, audio).                            | `webrtc.startCamera({ video: { width: 1280, height: 720 }, audio: true });`                                                                                     |\n| `stopCamera()`                            | Stops the user's camera.                                                                               | `webrtc.stopCamera();`                                                                                                                                          |\n| `toggleCamera()`                           | Toggles the camera on or off.                                                                          | `webrtc.toggleCamera();`                                                                                                                                         |\n| `startScreenShare(screenConfig)`           | Starts screen sharing with optional configuration.                                                     | `webrtc.startScreenShare();`                                                                                                                                     |\n| `stopScreenShare()`                       | Stops screen sharing.                                                                                  | `webrtc.stopScreenShare();`                                                                                                                                       |\n| `toggleScreenShare()`                      | Toggles screen sharing on or off.                                                                     | `webrtc.toggleScreenShare();`                                                                                                                                      |\n| `startAudio()`                             | Starts the user's microphone.                                                                          | `webrtc.startAudio();`                                                                                                                                          |\n| `stopAudio()`                              | Stops the user's microphone.                                                                            | `webrtc.stopAudio();`                                                                                                                                           |\n| `toggleAudio()`                            | Toggles the microphone on or off.                                                                       | `webrtc.toggleAudio();`                                                                                                                                         |\n| `isLocalAudioOn()`                        | Returns `true` if the local audio is on, `false` otherwise.                                          | `const audioOn = webrtc.isLocalAudioOn(); console.log('Local audio is on:', audioOn);`                                                                      |\n| `isLocalVideoOn()`                        | Returns `true` if the local video is on, `false` otherwise.                                          | `const videoOn = webrtc.isLocalVideoOn(); console.log('Local video is on:', videoOn);`                                                                      |\n| `isLocalScreenShareOn()`                 | Returns `true` if local screen sharing is on, `false` otherwise.                                     | `const screenSharingOn = webrtc.isLocalScreenShareOn(); console.log('Local screen sharing is on:', screenSharingOn);`                                           |\n| `onCameraVideoStateChange(fn)`            | Registers a callback for camera video state changes.                                                  | `webrtc.onCameraVideoStateChange((state, stream) =\u003e { console.log('Camera state changed:', state, stream); });`                                                |\n| `onScreenShareVideoStateChange(fn)`      | Registers a callback for screen share video state changes.                                             | `webrtc.onScreenShareVideoStateChange((state, stream) =\u003e { console.log('Screen share state changed:', state, stream); });`                                       |\n| `onAudioStateChange(fn)`                   | Registers a callback for audio state changes.                                                         | `webrtc.onAudioStateChange((state, stream) =\u003e { console.log('Audio state changed:', state, stream); });`                                                     |\n| `sendDataChannelMsg(conId, msg)`           | Sends a message over the data channel to a specific peer or all peers (if `conId` is \"all\").        | `webrtc.sendDataChannelMsg('peer-id', { message: 'This is a data channel message!' });`                                                                      |\n| `onDataChannelMsg(fn)`                    | Registers a callback function to handle incoming data channel messages.                               | `webrtc.onDataChannelMsg((connId, message) =\u003e { console.log('Data channel message from', connId, ':', message); });`                                             |\n| `sendFile(to, file)`                      | Sends a file to a specific peer.                                                                       | `webrtc.sendFile('peer-id', fileInput.files[0]);`                                                                                                             |\n| `onFileSendingReq(fn)`                     | Registers a callback to handle file sending requests (allows confirmation before accepting a file). | `webrtc.onFileSendingReq((filename, connId) =\u003e { return confirm(`Accept file ${filename} from ${connId}?`); });`                                              |\n| `onFileStateChange(fn)`                    | Registers a callback to track file transfer progress.                                                  | `webrtc.onFileStateChange((fileState) =\u003e { console.log('File transfer progress:', fileState.progress); });`                                                   |\n| `onFileTransferCompleted(fn)`            | Registers a callback to handle completed file transfers.                                             | `webrtc.onFileTransferCompleted((fileState, objectUrl) =\u003e { console.log('File transfer completed:', fileState, objectUrl); });`                                |\n| `onError(fn)`                             | Registers a callback function to handle errors.                                                      | `webrtc.onError((error) =\u003e { console.error('WebRTC Error:', error); });`                                                                                  |\n\n\n\n## Public Method of React Hook (useEasyMeet)\n\nYou can use those from \n@mobinx/easymeet/react\n```javascript\nimport {useEasyMeet} from \"@mobinx/easymeet/react\"\nlet {startCamera, isVideoOn , isAudioOn , peers, fileSharingState ...and more} = useEasyMeet(\"you-socket-id\", iceServers, sendmsg /*the function used by easymeet system for sending msg to other over socket, takes msg and to ,two perameter , see usages example avobe */)\n```\n\n| Method/State                                  | Description                                                                                                                   | Usage Example                                                                                                                                                                                                     |\n|----------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `webRTCBaseRef`                             | A ref object containing the underlying `WebrtcBase` instance.                                                                  | `webRTCBaseRef.current?.sendDataChannelMsg('peer-id', 'Hello!');` (Access the `WebrtcBase` instance directly if needed)                                                                                            |\n| `error`                                       | An object containing error information (if any).                                                                              | `if (error) { console.error('WebRTC Error:', error.message); }`                                                                                                                                                     |\n| `onSocketMessage(message, from_connid, extraInfo)` | Handles incoming signaling messages from a peer.                                                                            | `onSocketMessage(JSON.stringify({ offer: offer }), 'peer-id', { username: 'Bob' });`                                                                                                                            |\n| `startCamera(cameraConfig)`                 | Starts the user's camera with optional configuration.                                                                         | `startCamera({ video: { width: 1280, height: 720 }, audio: true });`                                                                                                                                                |\n| `stopCamera()`                               | Stops the user's camera.                                                                                                     | `stopCamera();`                                                                                                                                                                                                    |\n| `startScreenShare(screenConfig)`            | Starts screen sharing with optional configuration.                                                                           | `startScreenShare();`                                                                                                                                                                                                |\n| `stopScreenShare()`                          | Stops screen sharing.                                                                                                        | `stopScreenShare();`                                                                                                                                                                                               |\n| `toggleCamera()`                            | Toggles the camera on or off.                                                                                                | `toggleCamera();`                                                                                                                                                                                                  |\n| `toggleScreenShare()`                       | Toggles screen sharing on or off.                                                                                           | `toggleScreenShare();`                                                                                                                                                                                             |\n| `startAudio()`                              | Starts the user's microphone.                                                                                                | `startAudio();`                                                                                                                                                                                                   |\n| `stopAudio()`                               | Stops the user's microphone.                                                                                                  | `stopAudio();`                                                                                                                                                                                                    |\n| `toggleAudio()`                             | Toggles the microphone on or off.                                                                                             | `toggleAudio();`                                                                                                                                                                                                  |\n| `isLocalAudioOn()`                           | Returns `true` if the local audio is on, `false` otherwise.                                                                    | `const audioOn = isLocalAudioOn();`                                                                                                                                                                                  |\n| `isLocalVideoOn()`                           | Returns `true` if the local video is on, `false` otherwise.                                                                    | `const videoOn = isLocalVideoOn();`                                                                                                                                                                                  |\n| `isLocalScreenShareOn()`                    | Returns `true` if local screen sharing is on, `false` otherwise.                                                               | `const screenSharingOn = isLocalScreenShareOn();`                                                                                                                                                                       |\n| `joinExistingPeer(peerID, extraData)`        | Joins an existing peer connection.                                                                                          | `joinExistingPeer('peer-id', { username: 'Alice' });`                                                                                                                                                                 |\n| `joinNewPeer(peerID, extraData)`             | Initiates a new peer connection.                                                                                            | `joinNewPeer('peer-id', { username: 'Bob' });`                                                                                                                                                                    |\n| `leavePeer(peerID)`                          | Leaves a peer connection.                                                                                                   | `leavePeer('peer-id');`                                                                                                                                                                                            |\n| `isAudioOn`                                  | Indicates whether the remote peer's audio is on.                                                                              | `const peerAudioOn = peers.find(peer =\u003e peer.socketId === 'peer-id')?.isAudioOn;`                                                                                                                                       |\n| `isVideoOn`                                  | Indicates whether the remote peer's video is on.                                                                              | `const peerVideoOn = peers.find(peer =\u003e peer.socketId === 'peer-id')?.isVideoOn;`                                                                                                                                       |\n| `isScreenShareOn`                           | Indicates whether the remote peer is screen sharing.                                                                          | `const peerScreenSharingOn = peers.find(peer =\u003e peer.socketId === 'peer-id')?.isScreenShareOn;`                                                                                                                            |\n| `audioStream`                                | The remote peer's audio stream.                                                                                              | `\u003caudio ref={audioRef} srcObject={audioStream} autoPlay /\u003e`                                                                                                                                                           |\n| `videoStream`                                | The remote peer's video stream.                                                                                              | `\u003cvideo ref={videoRef} srcObject={videoStream} autoPlay /\u003e`                                                                                                                                                           |\n| `screenShareStream`                          | The remote peer's screen share stream.                                                                                       | `\u003cvideo ref={screenShareRef} srcObject={screenShareStream} autoPlay /\u003e`                                                                                                                                                    |\n| `newDataChannelMsg`                          | The latest data channel message received.                                                                                    | `useEffect(() =\u003e { if (newDataChannelMsg) { console.log('New data channel message:', newDataChannelMsg.msg, 'from:', newDataChannelMsg.from); } }, [newDataChannelMsg]);`                                                |\n| `fileSharingCompleted`                       | Details of a completed file transfer.                                                                                        | `useEffect(() =\u003e { if (fileSharingCompleted) { console.log('File transfer completed:', fileSharingCompleted.file, 'URL:', fileSharingCompleted.objectUrl); } }, [fileSharingCompleted]);`                                     |\n| `fileSharingState`                           | The current state of an ongoing file transfer.                                                                               | `useEffect(() =\u003e { if (fileSharingState) { console.log('File transfer progress:', fileSharingState.progress); } }, [fileSharingState]);`                                                                              |\n| `isSystemReady`                              | Indicates whether the WebRTC system is initialized and ready.                                                                | `if (isSystemReady) { // Perform WebRTC operations }`                                                                                                                                                                |\n| `peers`                                      | An array of connected peer states.                                                                                           | `peers.map(peer =\u003e \u003cdiv key={peer.socketId}\u003ePeer: {peer.socketId}, Audio: {peer.isAudioOn}, Video: {peer.isVideoOn}\u003c/div\u003e)`                                                                                             |\n| `sendDataChannelMsg(msg, toID)`              | Sends a data channel message to a specific peer.                                                                              | `sendDataChannelMsg('Hello from data channel!', 'peer-id');`                                                                                                                                                         |\n| `sendFile(to, file)`                         | Sends a file to a specific peer.                                                                                             | `const fileInput = useRef(null); // ... \u003cinput type=\"file\" ref={fileInput} /\u003e ... sendFile('peer-id', fileInput.current.files[0]);`                                                                                |\n\n\n\n\n## Contributing:\n\nContributions are welcome! Please open an issue or submit a pull request if you have any suggestions, bug fixes, or new features.\n\n## License:\n\nThis project is licensed under the [MIT License](LICENSE).\n\n## Acknowledgements:\n\n* [WebRTC](https://webrtc.org/) - The underlying technology powering this library.\n\n## Contact:\n\nFor any inquiries or support, please contact MobinX at [mobin0219@gmail.com](mobin0219@gmail.com).\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmobinx%2Feasymeet-js","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmobinx%2Feasymeet-js","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmobinx%2Feasymeet-js/lists"}