index.jsx 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. import React, { Component } from 'react';
  2. import sdk, { Client } from 'urtc-sdk';
  3. import config from '../../config';
  4. import MediaPlayer from '../../components/MediaPlayer';
  5. import './index.css';
  6. const { AppId, AppKey } = config;
  7. // 此处使用固定的房间号的随机的用户ID,请自行替换
  8. const RoomId = "ssss02";
  9. const UserId = Math.floor(Math.random() * 1000000).toString();
  10. console.log('UCloudRTC sdk version: ', sdk.version);
  11. export default class Room extends Component {
  12. constructor() {
  13. super();
  14. this.state = {
  15. roomId: RoomId,
  16. userId: UserId,
  17. isJoinedRoom: false,
  18. selectedStream: null,
  19. localStreams: [],
  20. remoteStreams: [],
  21. }
  22. }
  23. componentDidMount() {
  24. if (!AppId || !AppKey) {
  25. alert('请先设置 AppId 和 AppKey');
  26. return;
  27. }
  28. if (!RoomId) {
  29. alert('请先设置 RoomId');
  30. return;
  31. }
  32. if (!UserId) {
  33. alert('请先设置 UserId');
  34. return;
  35. }
  36. const token = sdk.generateToken(AppId, AppKey, RoomId, UserId);
  37. this.client = new Client(AppId, token);
  38. this.client.on('stream-published', (localStream) => {
  39. console.info('stream-published: ', localStream);
  40. const { localStreams } = this.state;
  41. localStreams.push(localStream);
  42. this.setState({ localStreams });
  43. });
  44. this.client.on('stream-added', (remoteStream) => {
  45. console.info('stream-added: ', remoteStream);
  46. const { remoteStreams } = this.state;
  47. remoteStreams.push(remoteStream);
  48. // 自动订阅
  49. this.client.subscribe(remoteStream.sid, (err) => {
  50. console.error('自动订阅失败:', err);
  51. });
  52. this.setState({ remoteStreams });
  53. });
  54. this.client.on('stream-subscribed', (remoteStream) => {
  55. console.info('stream-subscribed: ', remoteStream);
  56. const { remoteStreams } = this.state;
  57. const idx = remoteStreams.findIndex(item => item.sid === remoteStream.sid);
  58. if (idx >= 0 ) {
  59. remoteStreams.splice(idx, 1, remoteStream);
  60. }
  61. this.setState({ remoteStreams });
  62. });
  63. this.client.on('stream-removed', (remoteStream) => {
  64. console.info('stream-removed: ', remoteStream);
  65. const { remoteStreams } = this.state;
  66. const idx = remoteStreams.findIndex(item => item.sid === remoteStream.sid);
  67. if (idx >= 0 ) {
  68. remoteStreams.splice(idx, 1);
  69. }
  70. this.setState({ remoteStreams });
  71. });
  72. window.addEventListener('beforeunload', this.handleLeaveRoom);
  73. }
  74. componentWillUnmount() {
  75. console.info('component will unmout');
  76. window.removeEventListener('beforeunload', this.handleLeaveRoom);
  77. this.handleLeaveRoom();
  78. }
  79. handleJoinRoom = () => {
  80. const { roomId, userId, isJoinedRoom } = this.state;
  81. if (isJoinedRoom) {
  82. alert('已经加入了房间');
  83. return;
  84. }
  85. if (!roomId) {
  86. alert('请先填写房间号');
  87. return;
  88. }
  89. this.client.joinRoom(roomId, userId, () => {
  90. console.info('加入房间成功');
  91. this.setState({ isJoinedRoom: true });
  92. }, (err) => {
  93. console.error('加入房间失败: ', err);
  94. });
  95. }
  96. handlePublish = () => {
  97. this.client.publish(err => {
  98. console.error('发布失败:', err);
  99. });
  100. }
  101. handlePublishScreen = () => {
  102. this.client.publish({audio: false, video: false, screen: true}, err => {
  103. console.error('发布失败:', err);
  104. });
  105. }
  106. handleUnpublish = () => {
  107. const { selectedStream } = this.state;
  108. if (!selectedStream) {
  109. alert('未选择需要取消发布的本地流');
  110. return;
  111. }
  112. this.client.unpublish(selectedStream.sid, (stream) => {
  113. console.info('取消发布本地流成功:', stream);
  114. const { localStreams } = this.state;
  115. const idx = localStreams.findIndex(item => item.sid === stream.sid);
  116. if (idx >=0) {
  117. localStreams.splice(idx, 1);
  118. }
  119. this.setState({
  120. localStreams,
  121. selectedStream: null
  122. });
  123. }, (err) => {
  124. console.error('取消发布本地流失败:', err);
  125. })
  126. }
  127. handleSubscribe = () => {
  128. const { selectedStream } = this.state;
  129. if (!selectedStream) {
  130. alert('未选择需要订阅的远端流');
  131. return;
  132. }
  133. this.client.subscribe(selectedStream.sid, (err) => {
  134. console.error('订阅失败:', err);
  135. });
  136. }
  137. handleUnsubscribe = () => {
  138. const { selectedStream } = this.state;
  139. if (!selectedStream) {
  140. alert('未选择需要取消订阅的远端流');
  141. return;
  142. }
  143. this.client.unsubscribe(selectedStream.sid, (stream) => {
  144. console.info('取消订阅成功:', stream);
  145. const { remoteStreams } = this.state;
  146. const idx = remoteStreams.findIndex(item => item.sid === stream.sid);
  147. if (idx >=0) {
  148. remoteStreams.splice(idx, 1, stream);
  149. }
  150. this.setState({
  151. remoteStreams,
  152. });
  153. }, (err) => {
  154. console.error('订阅失败:', err);
  155. });
  156. }
  157. handleLeaveRoom = () => {
  158. const { isJoinedRoom } = this.state;
  159. if (!isJoinedRoom) {
  160. return;
  161. }
  162. this.client.leaveRoom(() => {
  163. console.info('离开房间成功');
  164. this.setState({
  165. selectedStream: null,
  166. localStreams: [],
  167. remoteStreams: [],
  168. isJoinedRoom: false,
  169. });
  170. }, (err) => {
  171. console.error('离开房间失败:', err);
  172. });
  173. }
  174. handleSelectStream = (stream) => {
  175. console.log('select stream: ', stream);
  176. this.setState({ selectedStream: stream });
  177. }
  178. renderLocalStream() {
  179. const { localStreams } = this.state;
  180. return localStreams.map(stream => {
  181. return stream.mediaStream ?
  182. <MediaPlayer className="local-stream" key={stream.sid} client={this.client} stream={stream} onClick={this.handleSelectStream}/> :
  183. null;
  184. });
  185. }
  186. renderRemoteStream() {
  187. const { remoteStreams } = this.state;
  188. return remoteStreams.map(stream => {
  189. return stream.mediaStream ?
  190. <MediaPlayer className="remote-stream" key={stream.sid} client={this.client} stream={stream} onClick={this.handleSelectStream} /> :
  191. <div className="media-player remote-stream" key={stream.sid} onClick={() => { this.handleSelectStream(stream) }}>
  192. <div style={{ overflow: 'hidden', textOverflow: 'ellipsis' }}>用户ID: {stream.uid}</div>
  193. <div style={{ overflow: 'hidden', textOverflow: 'ellipsis' }}>流ID: {stream.sid}</div>
  194. <p> unsubscribe </p>
  195. </div>;
  196. });
  197. }
  198. render() {
  199. const { selectedStream, isJoinedRoom } = this.state;
  200. return (
  201. <div className="room">
  202. <label>房间号:{RoomId}({isJoinedRoom ? '已加入' : '未加入'})</label>
  203. <p>当前选中的流:{selectedStream ? selectedStream.sid : '未选择'}</p>
  204. <h3>本地(发布)流</h3>
  205. {
  206. this.renderLocalStream()
  207. }
  208. <h3>远端(订阅)流</h3>
  209. {
  210. this.renderRemoteStream()
  211. }
  212. <h3>操作</h3>
  213. <button onClick={this.handleJoinRoom}>加入房间</button>
  214. <button onClick={this.handlePublish}>发布</button>
  215. <button onClick={this.handlePublishScreen}>屏幕共享</button>
  216. <button onClick={this.handleUnpublish}>取消发布/屏幕共享</button>
  217. <button onClick={this.handleSubscribe}>订阅</button>
  218. <button onClick={this.handleUnsubscribe}>取消订阅</button>
  219. <button onClick={this.handleLeaveRoom}>离开房间</button>
  220. </div>
  221. )
  222. }
  223. }