emediaState.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. /**
  2. ** 呼叫流程 **
  3. caller -------------------------------------- callee
  4. ----------inviting--------------->
  5. <-------------alerting-------
  6. ----------confirmRing------------>
  7. <-------------answerCall-----
  8. ----------confirmCallee---------->
  9. */
  10. let disp = require("./broadcast");
  11. const CALLSTATUS = {
  12. idle: 0,
  13. inviting: 1,
  14. alerting: 2,
  15. confirmRing: 3, // caller
  16. receivedConfirmRing: 4, // callee
  17. answerCall: 5,
  18. receivedAnswerCall: 6,
  19. confirmCallee: 7
  20. }
  21. wx.WebIM.rtc = {
  22. // 用来放置本地客户端。
  23. client: null,
  24. // 用来放置本地音视频频轨道对象。
  25. localAudioTrack: null,
  26. localVideoTrack: null,
  27. timer: null
  28. }
  29. let emediaState = {
  30. callStatus: CALLSTATUS.idle,
  31. callDuration: '00:00',
  32. minisize: false,
  33. confr: {
  34. channel: '',
  35. token: '',
  36. type: null,
  37. callId: null,
  38. callerDevId: null,
  39. calleeDevId: null,
  40. confrName: '',
  41. callerIMName: '',
  42. calleeIMName: ''
  43. },
  44. gid: '',
  45. inviteModal: false,
  46. joinedMembers: [],
  47. invitedMembers: [],
  48. onMessage: function (message) {
  49. let me = emediaState
  50. console.log('msg', message)
  51. let msg = message
  52. // text invite message
  53. if (message.ext.action == 'invite') {
  54. console.log('收到邀请消息', message)
  55. message.calleeIMName = message.to
  56. message.callerIMName = message.from
  57. if (message.from == wx.WebIM.conn.context.jid.name) {
  58. return // 自己在另一端发出的邀请
  59. }
  60. if (emediaState.callStatus > CALLSTATUS.idle) { // 正忙
  61. if (message.ext.callId == emediaState.confr.callId) { // 多人会议中邀请别人
  62. emediaState.callStatus = CALLSTATUS.alerting
  63. emediaState.sendAlerting(message.from, message.ext.callerDevId, message.ext.callId) // 回复alerting消息
  64. } else {
  65. emediaState.answerCall.call(emediaState, 'busy', { callId: message.ext.callId, callerDevId: message.ext.callerDevId, to: message.from })
  66. }
  67. }
  68. emediaState.updateConfr(message)
  69. emediaState.sendAlerting(message.from, message.ext.callerDevId, message.ext.callId) // 回复alerting消息
  70. emediaState.callStatus = CALLSTATUS.alerting // 更改为alerting状态
  71. }
  72. // CMD sessage
  73. if (msg.action === "rtcCall") {
  74. if (msg.from === wx.WebIM.conn.context.jid.name) {
  75. return // 多端情况, 另一端自己发的消息
  76. }
  77. let msgInfo = msg.ext
  78. let deviceId = '';
  79. let callerDevId = ''
  80. let callId = '';
  81. switch (msgInfo.action) {
  82. case "alert":
  83. deviceId = msgInfo.calleeDevId
  84. callerDevId = msgInfo.callerDevId
  85. callId = msgInfo.callId
  86. console.log('收到回复的alert', msg)
  87. emediaState.confirmRing.call(emediaState, msg.from, deviceId, callerDevId, callId)
  88. break;
  89. case "confirmRing":
  90. console.log('收到confirmRing', msg)
  91. if (msgInfo.calleeDevId != wx.WebIM.conn.context.jid.clientResource) {
  92. console.log('不是自己设备的confirmRing', msg)
  93. return // 多端情况另一端的消息
  94. }
  95. if (!msgInfo.status && emediaState.callStatus < CALLSTATUS.receivedConfirmRing) {
  96. console.warn('邀请已失效')
  97. wx.showToast({
  98. title: "邀请已失效",
  99. duration: 1000
  100. });
  101. emediaState.callStatus = CALLSTATUS.idle
  102. emediaState.hangup()
  103. return
  104. }
  105. deviceId = msgInfo.calleeDevId
  106. emediaState.callStatus = CALLSTATUS.receivedConfirmRing
  107. console.log('清除定时器2')
  108. wx.WebIM.rtc.timer && clearTimeout(wx.WebIM.rtc.timer)
  109. // disp.fire('emedia.confirmRing');
  110. wx.showModal({
  111. title: '提示',
  112. content: '邀请你加入视频会议',
  113. success(res) {
  114. if (res.confirm) {
  115. console.log('emediaState ---', emediaState)
  116. if (emediaState.callStatus == 0) {
  117. return
  118. }
  119. me.answerCall.call(me, 'accept', msgInfo)
  120. let pages = getCurrentPages();
  121. let curPage = pages[pages.length - 1];
  122. if (curPage.route !== "pages/chatroom/chatroom") {
  123. var nameList = {
  124. myName: wx.WebIM.conn.context.jid.name,
  125. your: msg.from,
  126. action: 'join',
  127. data: msg
  128. };
  129. if (msgInfo.ext && msgInfo.ext.groupId) {
  130. nameList.groupId = msgInfo.ext.groupId
  131. }
  132. wx.navigateTo({
  133. url: "../chatroom/chatroom?username=" + JSON.stringify(nameList)
  134. });
  135. } else {
  136. disp.fire('emedia.confirmRing', msg);
  137. }
  138. } else {
  139. me.answerCall.call(me, 'refuse', msgInfo)
  140. }
  141. },
  142. fail() {
  143. me.answerCall.call(me, 'refuse', msgInfo)
  144. }
  145. })
  146. break;
  147. case "answerCall":
  148. console.log('收到回复的answerCall', msg)
  149. console.log('清除定时器1')
  150. wx.WebIM.rtc.timer && clearTimeout(wx.WebIM.rtc.timer)
  151. deviceId = msgInfo.calleeDevId
  152. if (msgInfo.callerDevId != wx.WebIM.conn.context.jid.clientResource) {
  153. console.log('不是自己设备的answerCall', msg)
  154. return // 多端情况另一端的消息
  155. }
  156. emediaState.confirmCallee(msg.from, deviceId, msgInfo.result)
  157. if (msgInfo.result !== 'accept') {
  158. if (msgInfo.result === 'busy') {
  159. console.error('对方正忙')
  160. wx.showToast({
  161. title: "对方正忙",
  162. duration: 1000
  163. });
  164. } else if (msgInfo.result === 'refuse') {
  165. console.error('对方已拒绝')
  166. wx.showToast({
  167. title: "对方已拒绝",
  168. duration: 1000
  169. });
  170. }
  171. if (emediaState.confr.type !== 2) { // 单人情况挂断,多人不挂断
  172. emediaState.hangup()
  173. disp.fire('hangup')
  174. emediaState.callStatus = CALLSTATUS.idle
  175. }
  176. }
  177. break;
  178. case "confirmCallee":
  179. console.log('收到confirmCallee', msg)
  180. if (msgInfo.calleeDevId != wx.WebIM.conn.context.jid.clientResource) {
  181. if (msg.to == wx.WebIM.conn.context.jid.name) {
  182. emediaState.hangup()
  183. emediaState.callStatus = CALLSTATUS.idle
  184. // disp.fire('hangup')
  185. wx.showToast({
  186. title: "已在其他设备处理",
  187. duration: 2000
  188. });
  189. return console.error('已在其他设备处理')
  190. }
  191. }
  192. else if (msg.ext.result != 'accept' && emediaState.callStatus != 7) {
  193. // 不在通话中收到 busy refuse时挂断
  194. emediaState.hangup()
  195. disp.fire('hangup')
  196. emediaState.callStatus = CALLSTATUS.idle
  197. return
  198. }
  199. emediaState.callStatus = CALLSTATUS.confirmCallee
  200. break;
  201. case "cancelCall":
  202. console.log('收到cancelCall', msg)
  203. if (msg.from == wx.WebIM.conn.context.jid.name) {
  204. return // 多端情况另一端的消息
  205. }
  206. if (msg.from == emediaState.confr.callerIMName) {
  207. emediaState.hangup()
  208. disp.fire('hangup')
  209. emediaState.callStatus = CALLSTATUS.idle
  210. }
  211. break;
  212. default:
  213. console.log('unexpected action')
  214. break;
  215. }
  216. }
  217. },
  218. // callee
  219. sendAlerting: (to, calleeDevId, callId) => {
  220. var id = wx.WebIM.conn.getUniqueId(); //生成本地消息id
  221. var msg = new wx.WebIM.message('cmd', id); //创建命令消息
  222. msg.set({
  223. to: to,
  224. action: 'rtcCall',
  225. ext: {
  226. action: 'alert',
  227. calleeDevId: wx.WebIM.conn.context.jid.clientResource,
  228. callerDevId: calleeDevId,
  229. callId: callId,
  230. ts: Date.now(),
  231. msgType: 'rtcCallWithAgora'
  232. },
  233. success: function (id, serverMsgId) {
  234. emediaState.callStatus = CALLSTATUS.alerting
  235. },
  236. fail: function (e) {
  237. console.log("Fail");
  238. }
  239. });
  240. console.log('被叫发出的alert: ', msg.body)
  241. wx.WebIM.conn.send(msg.body);
  242. wx.WebIM.rtc.timer = setTimeout(() => {
  243. console.log('定时器到期')
  244. emediaState.hangup()
  245. disp.fire('hangup')
  246. emediaState.callStatus = CALLSTATUS.idle
  247. }, 30000)
  248. console.log('设置定时器')
  249. },
  250. // caller
  251. confirmRing: function (to, calleeDevId, callerDevId, callId) {
  252. let me = emediaState;
  253. let confr = emediaState.confr
  254. let currentCallId = confr.callId
  255. let status = true
  256. console.log('confirmRing confr', confr)
  257. if (callerDevId !== wx.WebIM.conn.context.jid.clientResource) {
  258. console.warn('callerDevId 设备不相同')
  259. return
  260. }
  261. if (callId !== currentCallId) {
  262. console.warn('callId 不相同', callId)
  263. status = false
  264. }
  265. else if (emediaState.callStatus > 4 && confr.type != 2) { //已经在通话中
  266. status = false
  267. }
  268. var id = wx.WebIM.conn.getUniqueId(); //生成本地消息id
  269. var msg = new wx.WebIM.message('cmd', id); //创建命令消息
  270. msg.set({
  271. to: to,
  272. action: 'rtcCall',
  273. ext: {
  274. action: 'confirmRing',
  275. status: status, // TRUE为有效,FALSE为无效(miss)
  276. callerDevId: wx.WebIM.conn.context.jid.clientResource,
  277. calleeDevId: calleeDevId,
  278. callId: callId,
  279. ts: Date.now(),
  280. msgType: 'rtcCallWithAgora'
  281. },
  282. success: function (id, serverMsgId) {
  283. if (status) {
  284. me.callStatus = CALLSTATUS.confirmRing;
  285. }
  286. },
  287. fail: function (e) {
  288. console.log("Fail");
  289. }
  290. });
  291. console.log('发送confirmRing', msg)
  292. wx.WebIM.conn.send(msg.body);
  293. },
  294. // callee
  295. answerCall: (result, info) => {
  296. info = info || {}
  297. var id = wx.WebIM.conn.getUniqueId(); //生成本地消息id
  298. var msg = new wx.WebIM.message('cmd', id); //创建命令消息
  299. let currentCallId = info.currentCallId || info.callId
  300. let callerDevId = info.callerDevId || emediaState.confr.callerDevId
  301. let to = info.to || emediaState.confr.callerIMName
  302. msg.set({
  303. to: to,
  304. action: 'rtcCall',
  305. ext: {
  306. action: 'answerCall',
  307. result: result, // busy/accept/refuse
  308. callerDevId: callerDevId,
  309. calleeDevId: wx.WebIM.conn.context.jid.clientResource,
  310. callId: currentCallId,
  311. ts: Date.now(),
  312. msgType: 'rtcCallWithAgora'
  313. },
  314. success: function (id, serverMsgId) {
  315. },
  316. fail: function (e) {
  317. console.log("Fail"); //如禁言、拉黑后发送消息会失败
  318. }
  319. });
  320. console.log('发送answerCall', msg)
  321. wx.WebIM.conn.send(msg.body);
  322. },
  323. // caller
  324. confirmCallee: function (to, calleeDevId, result) {
  325. let me = emediaState
  326. var id = wx.WebIM.conn.getUniqueId();
  327. var msg = new wx.WebIM.message('cmd', id);
  328. let confr = emediaState.confr
  329. let currentCallId = confr.callId
  330. if (!confr.calleeDevId && confr.type != 2) {
  331. emediaState.updateConfr({
  332. to: confr.confrName,
  333. ext: {
  334. channelName: confr.channel,
  335. token: confr.token,
  336. type: confr.type,
  337. callerDevId: confr.callerDevId,
  338. calleeDevId: calleeDevId,
  339. callId: confr.callId,
  340. members: [{ name: 'name1', uid: 12345 }]
  341. },
  342. calleeIMName: confr.calleeIMName,
  343. callerIMName: confr.callerIMName
  344. })
  345. } else if (confr.calleeDevId != calleeDevId && confr.type != 2) {
  346. result = 'refuse'
  347. }
  348. msg.set({
  349. to: to,
  350. action: 'rtcCall',
  351. ext: {
  352. action: 'confirmCallee',
  353. result: result || 'accept', // busy/accept/refuse
  354. callerDevId: wx.WebIM.conn.context.jid.clientResource,
  355. calleeDevId: calleeDevId,
  356. callId: currentCallId,
  357. ts: Date.now(),
  358. msgType: 'rtcCallWithAgora'
  359. },
  360. success: function (id, serverMsgId) {
  361. me.callStatus = CALLSTATUS.confirmCallee
  362. },
  363. fail: function (e) {
  364. console.log("Fail")
  365. }
  366. });
  367. console.log('发送confirmCallee', msg)
  368. wx.WebIM.conn.send(msg.body);
  369. },
  370. cancelCall: function (to) {
  371. let me = emediaState
  372. var id = wx.WebIM.conn.getUniqueId();
  373. var msg = new wx.WebIM.message('cmd', id);
  374. let callerDevId = emediaState.confr.callerDevId
  375. let user = to || emediaState.confr.calleeIMName
  376. let currentCallId = emediaState.confr.callId
  377. if (!user) {
  378. console.log('-- to is undefined --')
  379. return
  380. }
  381. msg.set({
  382. to: user,
  383. action: 'rtcCall',
  384. ext: {
  385. action: 'cancelCall',
  386. callerDevId: callerDevId,
  387. callId: currentCallId,
  388. ts: Date.now(),
  389. msgType: 'rtcCallWithAgora'
  390. },
  391. success: function (id, serverMsgId) {
  392. me.callStatus = CALLSTATUS.idle
  393. },
  394. fail: function (e) {
  395. console.log("Fail");
  396. }
  397. });
  398. console.log('发送取消消息', msg)
  399. wx.WebIM.conn.send(msg.body);
  400. },
  401. hangup: () => {
  402. emediaState.callStatus = CALLSTATUS.idle
  403. emediaState.cancelCall()
  404. // dispatch(Creators.setCallDuration('00:00'))
  405. // dispatch(Creators.setMinisize(false))
  406. // dispatch(Creators.resetAll())
  407. // dispatch(Creators.setJoinedMembers([]))
  408. // dispatch(Creators.setInvitedMembers([]))
  409. // dispatch(Creators.updateConfr({
  410. // to: '',
  411. // ext: {}
  412. // }))
  413. emediaState.updateConfr({})
  414. },
  415. updateConfr: function (msg) {
  416. let confrInfo = msg.ext || {}
  417. let groupId
  418. let confr = {
  419. channel: confrInfo.channelName,
  420. token: confrInfo.token,
  421. type: confrInfo.type,
  422. callId: confrInfo.callId,
  423. callerDevId: confrInfo.callerDevId,
  424. calleeDevId: confrInfo.calleeDevId
  425. }
  426. if (confrInfo.type === 2) {
  427. confr.confrName = msg.to
  428. } else {
  429. confr.confrName = msg.from
  430. }
  431. if (msg.calleeIMName) {
  432. confr.calleeIMName = msg.calleeIMName
  433. }
  434. if (msg.callerIMName) {
  435. confr.callerIMName = msg.callerIMName
  436. }
  437. if (confrInfo.ext) {
  438. groupId = confrInfo.ext.groupId
  439. confr.gid = groupId
  440. }
  441. emediaState.confr = confr
  442. //return confrInfo.ext ? emediaState.confr.gid = groupId : emediaState.confr = confr
  443. },
  444. setConf: function (prop, value) {
  445. if (typeof prop == 'object') {
  446. for (let key in prop) {
  447. emediaState.confr[key] = prop[key]
  448. }
  449. return
  450. }
  451. emediaState.confr[prop] = value
  452. }
  453. }
  454. module.exports = emediaState