call-live-sdk1 0.0.20 → 0.0.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -189243,7 +189243,7 @@ const useCallStore = create$c()(
189243
189243
  nickname,
189244
189244
  token: token2,
189245
189245
  device: isMobile$3 ? "mobile" : "pc",
189246
- videoList: [rtc_userid, rtc_userid + "screen", rtc_userid + "main"],
189246
+ videoList: [rtc_userid, rtc_userid + "screen", rtc_userid + "main", rtc_userid + "self"],
189247
189247
  ...initCallUser,
189248
189248
  // 根据enter_muted配置设置初始音频状态
189249
189249
  // enter_muted: 0-否(音频开启) 1-是(音频关闭/静音)
@@ -189921,17 +189921,6 @@ const useCallStore = create$c()(
189921
189921
  isAudioEnabled,
189922
189922
  isAudioDisabled: isBanned ?? false
189923
189923
  });
189924
- if (rtc && rtc.engine) {
189925
- await rtc.engine.sendRoomMessage(
189926
- JSON.stringify({
189927
- type: "media",
189928
- data: {
189929
- media_type: "audio",
189930
- media_state: isAudioEnabled ? 1 : 0
189931
- }
189932
- })
189933
- );
189934
- }
189935
189924
  return {
189936
189925
  success: true,
189937
189926
  message: isAudioEnabled ? "麦克风已开启" : "麦克风已关闭",
@@ -189958,17 +189947,6 @@ const useCallStore = create$c()(
189958
189947
  isVideoEnabled: newVideoState,
189959
189948
  isVideoDisabled: isBanned ?? false
189960
189949
  });
189961
- if (rtc && rtc.engine) {
189962
- await rtc.engine.sendRoomMessage(
189963
- JSON.stringify({
189964
- type: "media",
189965
- data: {
189966
- media_type: "video",
189967
- media_state: newVideoState ? 1 : 0
189968
- }
189969
- })
189970
- );
189971
- }
189972
189950
  return {
189973
189951
  success: true,
189974
189952
  message: newVideoState ? "摄像头已开启" : "摄像头已关闭",
@@ -190182,7 +190160,7 @@ const useCallStore = create$c()(
190182
190160
  context.arc(avatarX + avatarRadius, avatarY + avatarRadius, avatarRadius, 0, 2 * Math.PI);
190183
190161
  context.fill();
190184
190162
  if (user && user.nickname) {
190185
- const firstLetter = user.nickname.charAt(0).toUpperCase();
190163
+ const firstLetter = user.nickname.trim().charAt(0);
190186
190164
  context.fillStyle = "#ffffff";
190187
190165
  context.font = `${avatarSize * 0.5}px Arial`;
190188
190166
  context.textAlign = "center";
@@ -202729,6 +202707,185 @@ const DropdownButton = (props) => {
202729
202707
  DropdownButton.__ANT_BUTTON = true;
202730
202708
  const Dropdown = Dropdown$1;
202731
202709
  Dropdown.Button = DropdownButton;
202710
+ const useVideoSlotBinding = ({
202711
+ item,
202712
+ livePlayerRef,
202713
+ fenge
202714
+ }) => {
202715
+ const { callUsers, getter } = useCallStore();
202716
+ const [selectedValue, setSelectedValue] = reactExports.useState(
202717
+ item.objectType === "videoSlot" && item.userId && item.streamIndex ? `${item.userId}${fenge}${item.streamIndex}` : ""
202718
+ );
202719
+ reactExports.useEffect(() => {
202720
+ if (item.objectType === "videoSlot" && item.userId && item.streamIndex) {
202721
+ setSelectedValue(`${item.userId}${fenge}${item.streamIndex}`);
202722
+ }
202723
+ }, [item.userId, item.streamIndex, item.objectType, fenge]);
202724
+ const targetUser = reactExports.useMemo(() => {
202725
+ if (!selectedValue)
202726
+ return void 0;
202727
+ const userId = selectedValue.split(fenge)[0];
202728
+ return callUsers.find((user) => user.rtc_userid === userId);
202729
+ }, [selectedValue, fenge, callUsers]);
202730
+ const handleStreamChange = (value, option) => {
202731
+ var _a2, _b;
202732
+ console.log("选择的视频槽:", value, option);
202733
+ setSelectedValue(value);
202734
+ if (!value) {
202735
+ try {
202736
+ if (!livePlayerRef.current) {
202737
+ console.error("livePlayerRef未初始化");
202738
+ return;
202739
+ }
202740
+ livePlayerRef.current.addEmptyVideoSlot({ id: item.id });
202741
+ console.log("成功清除连麦嘉宾绑定状态");
202742
+ } catch (error2) {
202743
+ console.error("清除连麦嘉宾绑定状态失败:", error2);
202744
+ }
202745
+ return;
202746
+ }
202747
+ try {
202748
+ const [userId, streamIndex] = String(value).split(fenge);
202749
+ const canvas = getter().fabricInstance;
202750
+ if (!canvas) {
202751
+ console.error("画布未初始化");
202752
+ return;
202753
+ }
202754
+ const videoSlotObj = ((_a2 = canvas.getObjects()) == null ? void 0 : _a2.find((o2) => o2.id === item.id)) || item;
202755
+ canvas.setActiveObject(videoSlotObj);
202756
+ const user = callUsers.find((user2) => user2.rtc_userid === userId);
202757
+ if (!user) {
202758
+ console.error("找不到用户:", userId);
202759
+ return;
202760
+ }
202761
+ if (user.isVideoEnabled) {
202762
+ livePlayerRef.current.bindVideoSlotToFirstEmpty({
202763
+ id: item.id,
202764
+ userId,
202765
+ device: user.device,
202766
+ streamIndex: streamIndex === "screen" ? "screen" : "main",
202767
+ userName: targetUser == null ? void 0 : targetUser.nickname
202768
+ });
202769
+ if (videoSlotObj) {
202770
+ videoSlotObj.userId = userId;
202771
+ videoSlotObj.streamIndex = streamIndex;
202772
+ }
202773
+ } else {
202774
+ const targetObj = (_b = canvas.getObjects()) == null ? void 0 : _b.find((o2) => o2.id === item.id);
202775
+ if (targetObj) {
202776
+ livePlayerRef.current.createCameraClosedPlaceholder(
202777
+ { ...targetObj, streamIndex },
202778
+ user
202779
+ );
202780
+ }
202781
+ }
202782
+ } catch (error2) {
202783
+ console.error("绑定连麦嘉宾失败:", error2);
202784
+ }
202785
+ };
202786
+ reactExports.useEffect(() => {
202787
+ var _a2;
202788
+ if (item.objectType !== "videoSlot" || !livePlayerRef.current)
202789
+ return;
202790
+ try {
202791
+ const canvas = getter().fabricInstance;
202792
+ if (!canvas) {
202793
+ console.error("画布未初始化");
202794
+ return;
202795
+ }
202796
+ const videoSlotObj = (_a2 = canvas.getObjects()) == null ? void 0 : _a2.find((o2) => o2.id === item.id);
202797
+ if (!videoSlotObj) {
202798
+ console.error("找不到对应的连麦嘉宾对象:", item.id);
202799
+ return;
202800
+ }
202801
+ const [, streamIndex = "main"] = selectedValue.split(fenge);
202802
+ if (!targetUser || streamIndex === "screen" && !targetUser.isScreenEnabled) {
202803
+ console.log(`用户${item.userId}已退出,恢复为空连麦嘉宾`);
202804
+ setSelectedValue("");
202805
+ try {
202806
+ livePlayerRef.current.addEmptyVideoSlot({ id: item.id });
202807
+ } catch (error2) {
202808
+ console.error("恢复空连麦嘉宾失败:", error2);
202809
+ }
202810
+ return;
202811
+ }
202812
+ console.log(
202813
+ `${targetUser.nickname || targetUser.rtc_userid}摄像头状态变更为: ${targetUser.isVideoEnabled ? "开启" : "关闭"}`
202814
+ );
202815
+ if (targetUser.isVideoEnabled) {
202816
+ try {
202817
+ livePlayerRef.current.bindVideoSlotToFirstEmpty({
202818
+ id: item.id,
202819
+ userId: targetUser.rtc_userid,
202820
+ streamIndex: streamIndex === "screen" ? "screen" : "main",
202821
+ userName: targetUser.nickname
202822
+ });
202823
+ videoSlotObj.userId = targetUser.rtc_userid;
202824
+ videoSlotObj.streamIndex = streamIndex;
202825
+ } catch (bindError) {
202826
+ console.error("绑定视频流失败:", bindError);
202827
+ }
202828
+ } else {
202829
+ try {
202830
+ livePlayerRef.current.createCameraClosedPlaceholder(
202831
+ { ...videoSlotObj, streamIndex },
202832
+ targetUser
202833
+ );
202834
+ videoSlotObj._cameraClosedPlaceholder = true;
202835
+ } catch (placeholderError) {
202836
+ console.error("创建摄像头关闭占位符失败:", placeholderError);
202837
+ }
202838
+ }
202839
+ } catch (error2) {
202840
+ console.error("监听嘉宾视频状态变化时发生错误:", error2);
202841
+ }
202842
+ }, [targetUser, targetUser == null ? void 0 : targetUser.isVideoEnabled, targetUser == null ? void 0 : targetUser.isPublishStream, item.userId, item.id, selectedValue, fenge, livePlayerRef, getter]);
202843
+ return {
202844
+ selectedValue,
202845
+ setSelectedValue,
202846
+ targetUser,
202847
+ handleStreamChange
202848
+ };
202849
+ };
202850
+ const useVideoSlotStreams = () => {
202851
+ const { callUsers, callConfig } = useCallStore();
202852
+ const fenge = '-":}{_+';
202853
+ const availableStreams = reactExports.useMemo(
202854
+ () => callUsers.flatMap((user) => {
202855
+ const list = [];
202856
+ if (user.waiting_mode_state === WaitingModeState.WAITING) {
202857
+ return list;
202858
+ }
202859
+ if (user.rtc_userid === (callConfig == null ? void 0 : callConfig.drawing_board_id)) {
202860
+ return list;
202861
+ }
202862
+ list.push({
202863
+ label: `${user.nickname || user.rtc_userid} · 摄像头`,
202864
+ value: `${user.rtc_userid}${fenge}main`,
202865
+ isVideoEnabled: user.isVideoEnabled,
202866
+ rtc_userid: user.rtc_userid,
202867
+ nickname: user.nickname,
202868
+ isScreenEnabled: user.isScreenEnabled
202869
+ });
202870
+ if (user == null ? void 0 : user.isScreenEnabled) {
202871
+ list.push({
202872
+ label: `${user.nickname || user.rtc_userid} · 屏幕共享`,
202873
+ value: `${user.rtc_userid}${fenge}screen`,
202874
+ isVideoEnabled: user.isScreenEnabled,
202875
+ rtc_userid: user.rtc_userid,
202876
+ nickname: user.nickname,
202877
+ isScreenEnabled: user.isScreenEnabled
202878
+ });
202879
+ }
202880
+ return list;
202881
+ }),
202882
+ [callUsers, callConfig == null ? void 0 : callConfig.drawing_board_id]
202883
+ );
202884
+ return {
202885
+ availableStreams,
202886
+ fenge
202887
+ };
202888
+ };
202732
202889
  const {
202733
202890
  useToken: useToken$2
202734
202891
  } = theme;
@@ -202753,31 +202910,32 @@ const MetaItem = ({
202753
202910
  setFabricObjects,
202754
202911
  setDocumentInfo,
202755
202912
  scenes,
202756
- currentScene
202757
- } = useCallStore();
202758
- const {
202759
- callUsers,
202760
- getter,
202761
- callConfig
202913
+ currentScene,
202914
+ callConfig,
202915
+ getter
202762
202916
  } = useCallStore();
202763
202917
  const [items, setItems] = reactExports.useState(item);
202764
202918
  const [isHoveredId, setIsHoveredId] = reactExports.useState(null);
202919
+ const [itemKeyColor, setItemKeyColor] = reactExports.useState((_a2 = item == null ? void 0 : item.chromaKeyOptions) == null ? void 0 : _a2.keyColor);
202765
202920
  reactExports.useEffect(() => {
202766
202921
  setItems(item);
202767
202922
  }, [item]);
202923
+ const videoSlotStreams = useVideoSlotStreams();
202924
+ const videoSlotBinding = useVideoSlotBinding({
202925
+ item,
202926
+ livePlayerRef,
202927
+ fenge: videoSlotStreams.fenge
202928
+ });
202768
202929
  const isMutedRef = reactExports.useRef(true);
202769
202930
  const [isMuted, setIsMuted] = reactExports.useState(true);
202770
202931
  const [isLoop, setIsLoop] = reactExports.useState(false);
202771
- const fenge = '-":}{_+';
202772
- const [selectedValue, setSelectedValue] = reactExports.useState(item.objectType === "videoSlot" && item.userId && item.streamIndex ? `${item.userId}${fenge}${item.streamIndex}` : "");
202773
202932
  const [currentTime, setCurrentTime] = reactExports.useState(0);
202774
202933
  const [isPlay, setIsPlay] = reactExports.useState(false);
202775
202934
  const [duration, setDuration] = reactExports.useState(0);
202776
202935
  const sliderStateRef = reactExports.useRef(false);
202936
+ const [isSliderHovered, setIsSliderHovered] = reactExports.useState(false);
202777
202937
  const [hasMicrophone, setHasMicrophone] = reactExports.useState(false);
202778
202938
  const [micMuted, setMicMuted] = reactExports.useState(true);
202779
- const [isSliderHovered, setIsSliderHovered] = reactExports.useState(false);
202780
- const [itemKeyColor, setItemKeyColor] = reactExports.useState((_a2 = item == null ? void 0 : item.chromaKeyOptions) == null ? void 0 : _a2.keyColor);
202781
202939
  const handleLoopChange = (checked) => {
202782
202940
  setIsLoop(checked);
202783
202941
  if (item.objectType === "video" || item.objectType === "audio") {
@@ -202800,7 +202958,7 @@ const MetaItem = ({
202800
202958
  },
202801
202959
  audio: (checked) => {
202802
202960
  var _a3, _b;
202803
- const audioStream = livePlayerRef.current.getBackgroundAudioStreams().get(item.id);
202961
+ const audioStream = livePlayerRef.current.getActiveVideoStreams().get(item.id);
202804
202962
  if (audioStream) {
202805
202963
  audioStream.getAudioTracks().forEach((track) => {
202806
202964
  track.enabled = !checked;
@@ -202965,34 +203123,6 @@ const MetaItem = ({
202965
203123
  width: 300,
202966
203124
  padding: "12px 16px"
202967
203125
  };
202968
- const availableStreams = React$2.useMemo(() => callUsers.flatMap((user) => {
202969
- const list = [];
202970
- if (user.waiting_mode_state === WaitingModeState.WAITING) {
202971
- return list;
202972
- }
202973
- if (user.rtc_userid === (callConfig == null ? void 0 : callConfig.drawing_board_id)) {
202974
- return list;
202975
- }
202976
- list.push({
202977
- label: `${user.nickname || user.rtc_userid} · 摄像头`,
202978
- value: `${user.rtc_userid}${fenge}main`,
202979
- isVideoEnabled: user.isVideoEnabled,
202980
- rtc_userid: user.rtc_userid,
202981
- nickname: user.nickname,
202982
- isScreenEnabled: user.isScreenEnabled
202983
- });
202984
- if (user == null ? void 0 : user.isScreenEnabled) {
202985
- list.push({
202986
- label: `${user.nickname || user.rtc_userid} · 屏幕共享`,
202987
- value: `${user.rtc_userid}${fenge}screen`,
202988
- isVideoEnabled: user.isScreenEnabled,
202989
- rtc_userid: user.rtc_userid,
202990
- nickname: user.nickname,
202991
- isScreenEnabled: user.isScreenEnabled
202992
- });
202993
- }
202994
- return list;
202995
- }), [callUsers]);
202996
203126
  reactExports.useEffect(() => {
202997
203127
  const handleCallStatusChanged = (data2) => {
202998
203128
  if (item.objectType === "camera" || item.objectType === "microphone") {
@@ -203011,67 +203141,6 @@ const MetaItem = ({
203011
203141
  }
203012
203142
  }
203013
203143
  }, [callConfig.isCall]);
203014
- const targetUser = reactExports.useMemo(() => availableStreams.find((user) => user.rtc_userid === (selectedValue == null ? void 0 : selectedValue.split(fenge)[0])), [selectedValue, availableStreams]);
203015
- reactExports.useEffect(() => {
203016
- var _a3;
203017
- if (item.objectType !== "videoSlot" || !livePlayerRef.current)
203018
- return;
203019
- try {
203020
- const canvas = getter().fabricInstance;
203021
- if (!canvas) {
203022
- console.error("画布未初始化");
203023
- return;
203024
- }
203025
- const videoSlotObj = (_a3 = canvas.getObjects()) == null ? void 0 : _a3.find((o2) => o2.id === item.id);
203026
- if (!videoSlotObj) {
203027
- console.error("找不到对应的连麦嘉宾对象:", item.id);
203028
- return;
203029
- }
203030
- const [, streamIndex = "main"] = selectedValue.split(fenge);
203031
- if (!targetUser || streamIndex === "screen" && !targetUser.isScreenEnabled) {
203032
- console.log(`用户${item.userId}已退出,恢复为空连麦嘉宾`);
203033
- setSelectedValue("");
203034
- try {
203035
- livePlayerRef.current.addEmptyVideoSlot({
203036
- id: item.id
203037
- });
203038
- } catch (error2) {
203039
- console.error("恢复空连麦嘉宾失败:", error2);
203040
- }
203041
- return;
203042
- }
203043
- console.log(`${targetUser.nickname || targetUser.rtc_userid}摄像头状态变更为: ${targetUser.isVideoEnabled ? "开启" : "关闭"}`);
203044
- if (targetUser.isVideoEnabled) {
203045
- try {
203046
- livePlayerRef.current.bindVideoSlotToFirstEmpty({
203047
- id: item.id,
203048
- userId: targetUser.rtc_userid,
203049
- streamIndex: streamIndex === "screen" ? "screen" : "main",
203050
- userName: targetUser.nickname
203051
- });
203052
- videoSlotObj.userId = targetUser.rtc_userid;
203053
- videoSlotObj.streamIndex = streamIndex;
203054
- } catch (bindError) {
203055
- console.error("绑定视频流失败:", bindError);
203056
- }
203057
- } else {
203058
- try {
203059
- livePlayerRef.current.createCameraClosedPlaceholder({
203060
- ...videoSlotObj,
203061
- streamIndex
203062
- }, targetUser);
203063
- videoSlotObj._cameraClosedPlaceholder = true;
203064
- } catch (placeholderError) {
203065
- console.error("创建摄像头关闭占位符失败:", placeholderError);
203066
- }
203067
- }
203068
- } catch (error2) {
203069
- console.error("监听嘉宾视频状态变化时发生错误:", error2);
203070
- }
203071
- }, [targetUser, targetUser == null ? void 0 : targetUser.isVideoEnabled, item.userId, item.id, selectedValue]);
203072
- reactExports.useEffect(() => {
203073
- setItems(item);
203074
- }, [item]);
203075
203144
  return (
203076
203145
  // 媒体项容器
203077
203146
  // - 根据选中/悬停状态应用不同背景色
@@ -203214,72 +203283,15 @@ const MetaItem = ({
203214
203283
  })]
203215
203284
  }), item.objectType === "videoSlot" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", {
203216
203285
  className: "mt-3.5 pl-1 pr-1",
203217
- children: callConfig.isCall ? availableStreams.length > 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx(Select$1, {
203286
+ children: callConfig.isCall ? videoSlotStreams.availableStreams.length > 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx(Select$1, {
203218
203287
  className: "w-full",
203219
203288
  allowClear: true,
203220
- value: selectedValue,
203289
+ value: videoSlotBinding.selectedValue,
203221
203290
  placeholder: "选择嘉宾视频流绑定到此槽",
203222
- options: availableStreams,
203291
+ options: videoSlotStreams.availableStreams,
203223
203292
  showSearch: true,
203224
203293
  optionFilterProp: "label",
203225
- onChange: (val, opt) => {
203226
- var _a3, _b;
203227
- console.log("选择的视频槽:", val, opt);
203228
- setSelectedValue(val);
203229
- if (!val) {
203230
- try {
203231
- if (!livePlayerRef.current) {
203232
- console.error("livePlayerRef未初始化");
203233
- return;
203234
- }
203235
- livePlayerRef.current.addEmptyVideoSlot({
203236
- id: item.id
203237
- });
203238
- console.log("成功清除连麦嘉宾绑定状态");
203239
- } catch (error2) {
203240
- console.error("清除连麦嘉宾绑定状态失败:", error2);
203241
- }
203242
- return;
203243
- }
203244
- try {
203245
- const [userId, streamIndex] = String(val).split(fenge);
203246
- const canvas = getter().fabricInstance;
203247
- if (!canvas) {
203248
- console.error("画布未初始化");
203249
- return;
203250
- }
203251
- const videoSlotObj = ((_a3 = canvas.getObjects()) == null ? void 0 : _a3.find((o2) => o2.id === item.id)) || item;
203252
- canvas.setActiveObject(videoSlotObj);
203253
- const user = callUsers.find((user2) => user2.rtc_userid === userId);
203254
- if (!user) {
203255
- console.error("找不到用户:", userId);
203256
- return;
203257
- }
203258
- if (user.isVideoEnabled) {
203259
- livePlayerRef.current.bindVideoSlotToFirstEmpty({
203260
- id: item.id,
203261
- userId,
203262
- device: user.device,
203263
- streamIndex: streamIndex === "screen" ? "screen" : "main",
203264
- userName: targetUser.nickname
203265
- });
203266
- if (videoSlotObj) {
203267
- videoSlotObj.userId = userId;
203268
- videoSlotObj.streamIndex = streamIndex;
203269
- }
203270
- } else {
203271
- const targetObj = (_b = canvas.getObjects()) == null ? void 0 : _b.find((o2) => o2.id === item.id);
203272
- if (targetObj) {
203273
- livePlayerRef.current.createCameraClosedPlaceholder({
203274
- ...targetObj,
203275
- streamIndex
203276
- }, user);
203277
- }
203278
- }
203279
- } catch (error2) {
203280
- console.error("绑定连麦嘉宾失败:", error2);
203281
- }
203282
- },
203294
+ onChange: videoSlotBinding.handleStreamChange,
203283
203295
  notFoundContent: /* @__PURE__ */ jsxRuntimeExports.jsx("div", {
203284
203296
  className: "text-#fff/80",
203285
203297
  children: "暂无可用的远程视频流"
@@ -271100,6 +271112,7 @@ class RtcClient {
271100
271112
  */
271101
271113
  join(token2, roomId, uid2, extraInfo, autoOption) {
271102
271114
  console.log("autoOption", autoOption);
271115
+ console.log("extraInfo", extraInfo);
271103
271116
  return this.engine.joinRoom(
271104
271117
  token2,
271105
271118
  roomId,
@@ -272872,7 +272885,7 @@ const LivePlayer = ({
272872
272885
  await new Promise((resolve) => {
272873
272886
  audioElement.onloadedmetadata = resolve;
272874
272887
  });
272875
- const audioStream = audioElement.captureStream();
272888
+ audioElement.captureStream();
272876
272889
  const audioObject = new oa(audioElement, {
272877
272890
  selectable: true,
272878
272891
  hasControls: true,
@@ -272898,9 +272911,10 @@ const LivePlayer = ({
272898
272911
  canvas.add(audioObject);
272899
272912
  setFabricObjects((old) => [audioObject, ...old]);
272900
272913
  canvasRequestRenderAll();
272901
- const newBackgroundAudioStreams = new Map(backgroundAudioStreamsRef.current);
272902
- newBackgroundAudioStreams.set(streamId, audioStream);
272903
- backgroundAudioStreamsRef.current = newBackgroundAudioStreams;
272914
+ const videoStream = audioElement.captureStream();
272915
+ const newVideoStreams = new Map(activeVideoStreamsRef.current);
272916
+ newVideoStreams.set(streamId, videoStream);
272917
+ activeVideoStreamsRef.current = newVideoStreams;
272904
272918
  if (rtmpRef.current || canvasRtc) {
272905
272919
  await audioMixing();
272906
272920
  }
@@ -302238,13 +302252,29 @@ const RtcJoomRoom = reactExports.memo(({
302238
302252
  try {
302239
302253
  (_a2 = getter().rtc) == null ? void 0 : _a2.bindEngineEvents();
302240
302254
  console.log(`[rtcJoin]:token${token2},rtc_room_id${rtc_room_id},rtc_userid${rtc_userid}`);
302241
- await ((_b = getter().rtc) == null ? void 0 : _b.join(token2, rtc_room_id, rtc_userid, JSON.stringify({
302242
- nickname,
302255
+ const extraInfo = {
302256
+ nickname: nickname || "",
302243
302257
  device: isMobile$3 ? "mobile" : "pc",
302244
- microphone: isAudioEnabled ?? false,
302245
- camera: isVideoEnabled ?? false,
302246
- mirror: (media_devices == null ? void 0 : media_devices.mirrorEnabled) ?? false
302247
- }), {
302258
+ // 防御性代码:确保 device 总是有值
302259
+ microphone: !!isAudioEnabled,
302260
+ // 转换为布尔值
302261
+ camera: !!isVideoEnabled,
302262
+ // 转换为布尔值
302263
+ mirrorEnabled: !!(media_devices == null ? void 0 : media_devices.mirrorEnabled)
302264
+ // 防御性代码:转换为布尔值
302265
+ };
302266
+ console.log("[rtcJoin] 发送的 extraInfo:", JSON.stringify(extraInfo, null, 2));
302267
+ console.log("[rtcJoin] media_devices:", media_devices);
302268
+ console.log("[rtcJoin] isMobile:", isMobile$3);
302269
+ console.log("[rtcJoin] isAudioEnabled:", isAudioEnabled);
302270
+ console.log("[rtcJoin] isVideoEnabled:", isVideoEnabled);
302271
+ console.log("[rtcJoin] nickname:", nickname);
302272
+ Object.keys(extraInfo).forEach((key) => {
302273
+ if (extraInfo[key] === void 0 || extraInfo[key] === null) {
302274
+ console.error(`[rtcJoin] 警告:${key} 字段值为 ${extraInfo[key]}`);
302275
+ }
302276
+ });
302277
+ await ((_b = getter().rtc) == null ? void 0 : _b.join(token2, rtc_room_id, rtc_userid, JSON.stringify(extraInfo), {
302248
302278
  // 自动发布本地音视频流
302249
302279
  isAutoPublish: false,
302250
302280
  // 自动订阅房间内其他用户的音频流
@@ -302346,6 +302376,9 @@ const RtcJoomRoom = reactExports.memo(({
302346
302376
  (_a3 = rtc2 == null ? void 0 : rtc2.engine) == null ? void 0 : _a3.unsubscribeStream(userId, MediaType$1.AUDIO);
302347
302377
  }, 100);
302348
302378
  }
302379
+ updateCallUser(userId, {
302380
+ isPublishStream: stream.mediaType
302381
+ });
302349
302382
  },
302350
302383
  handleUserUnpublishStream: async (event) => {
302351
302384
  var _a2, _b;
@@ -302360,6 +302393,9 @@ const RtcJoomRoom = reactExports.memo(({
302360
302393
  if (mediaType & MediaType$1.AUDIO) {
302361
302394
  await ((_b = getter().rtc) == null ? void 0 : _b.engine.unsubscribeStream(userId, MediaType$1.AUDIO));
302362
302395
  }
302396
+ updateCallUser(userId, {
302397
+ isPublishStream: mediaType
302398
+ });
302363
302399
  },
302364
302400
  handleUserStartVideoCapture: (event) => {
302365
302401
  const {
@@ -302441,12 +302477,14 @@ const RtcJoomRoom = reactExports.memo(({
302441
302477
  userId,
302442
302478
  extraInfo
302443
302479
  } = userInfo;
302480
+ console.log("[handleUserJoin] 接收到的 extraInfo:", extraInfo);
302444
302481
  const extraObj = JSON.parse(extraInfo || "");
302482
+ console.log("[handleUserJoin] 解析后的 extraObj:", extraObj);
302445
302483
  const rtc_canvasid = callConfig.drawing_board_id === userId;
302446
302484
  joinCallUser({
302447
302485
  rtc_userid: userId,
302448
- nickname: (extraObj == null ? void 0 : extraObj.nickname) || userId,
302449
- device: (extraObj == null ? void 0 : extraObj.device) || "pc",
302486
+ nickname: extraObj == null ? void 0 : extraObj.nickname,
302487
+ device: extraObj == null ? void 0 : extraObj.device,
302450
302488
  rtc_room_id: callConfig.rtc_room_id,
302451
302489
  isVideoEnabled: (extraObj == null ? void 0 : extraObj.camera) ?? false,
302452
302490
  isAudioEnabled: (extraObj == null ? void 0 : extraObj.microphone) ?? false,
@@ -303694,7 +303732,7 @@ const WebLiveLogin = () => {
303694
303732
  nickname: loginData.data.nickname || "",
303695
303733
  token: loginData.data.token || "",
303696
303734
  device: isMobile$3 ? "mobile" : "pc",
303697
- videoList: [rtc_userid, rtc_userid + "screen", rtc_userid + "main"],
303735
+ videoList: [rtc_userid, rtc_userid + "screen", rtc_userid + "main", rtc_userid + "self"],
303698
303736
  isAudioEnabled: !rtcConfig.enter_muted && devicePermissions.microphone.granted && devicePermissions.microphone.enabled,
303699
303737
  isScreenEnabled: false,
303700
303738
  // 屏幕共享是否开启
@@ -304252,8 +304290,7 @@ const UserAvatar = reactExports.memo(({
304252
304290
  size = 40,
304253
304291
  className = ""
304254
304292
  }) => {
304255
- var _a2;
304256
- const avatarText = ((_a2 = nickname == null ? void 0 : nickname.charAt(0)) == null ? void 0 : _a2.toUpperCase()) || "?";
304293
+ const avatarText = (nickname == null ? void 0 : nickname.trim().charAt(0)) || "?";
304257
304294
  return /* @__PURE__ */ jsxRuntimeExports.jsx(Avatar, {
304258
304295
  size,
304259
304296
  className,
@@ -304853,8 +304890,12 @@ const UserVideoContainer = reactExports.memo(({
304853
304890
  const displayName = reactExports.useMemo(() => {
304854
304891
  return user.nickname || "未知用户";
304855
304892
  }, [user.nickname]);
304893
+ const isSelfWindow = reactExports.useMemo(() => {
304894
+ return videoId == null ? void 0 : videoId.includes("self");
304895
+ }, [videoId]);
304896
+ const maxNameLength = isSelfWindow ? 3 : 4;
304856
304897
  const avatarChar = reactExports.useMemo(() => {
304857
- return displayName.charAt(0).toUpperCase();
304898
+ return displayName.trim().charAt(0);
304858
304899
  }, [displayName]);
304859
304900
  const handleClick = reactExports.useCallback(() => {
304860
304901
  onClick == null ? void 0 : onClick(videoId || "");
@@ -304868,6 +304909,14 @@ const UserVideoContainer = reactExports.memo(({
304868
304909
  console.log("main======", user, videoId);
304869
304910
  }
304870
304911
  const noMirror = user.rtc_userid === callConfig.drawing_board_id || (videoId == null ? void 0 : videoId.includes("screen")) || !user.isMirror;
304912
+ console.log("[UserVideoContainer] 镜像设置调试:", {
304913
+ videoId,
304914
+ userRtcUserid: user.rtc_userid,
304915
+ callConfigRtcUserid: callConfig.rtc_userid,
304916
+ userIsMirror: user.isMirror,
304917
+ noMirror,
304918
+ shouldMirror: +!noMirror
304919
+ });
304871
304920
  const isModeFit = user.rtc_userid === callConfig.drawing_board_id || (videoId == null ? void 0 : videoId.includes("screen")) || user.device === "pc";
304872
304921
  if (user.rtc_userid === callConfig.rtc_userid) {
304873
304922
  rtc.engine.setLocalVideoPlayer((videoId == null ? void 0 : videoId.includes("screen")) ? StreamIndex$1.STREAM_INDEX_SCREEN : StreamIndex$1.STREAM_INDEX_MAIN, {
@@ -304935,7 +304984,7 @@ const UserVideoContainer = reactExports.memo(({
304935
304984
  className: "",
304936
304985
  children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", {
304937
304986
  className: "bg-black bg-opacity-50 rounded px-2 py-1 text-white text-xs font-medium truncate",
304938
- children: displayName ? displayName.length > 4 ? `${displayName.substring(0, 4)}...` : displayName : ""
304987
+ children: displayName ? displayName.length > maxNameLength ? `${displayName.substring(0, maxNameLength)}...` : displayName : ""
304939
304988
  })
304940
304989
  }), /* @__PURE__ */ jsxRuntimeExports.jsx("div", {
304941
304990
  className: `
@@ -305059,23 +305108,23 @@ const VideoSwipeContainer = reactExports.memo(
305059
305108
  cols: 2,
305060
305109
  rows: 1,
305061
305110
  maxVisibleItems: 2,
305062
- needsScroll: false,
305063
- centerVertically: true
305111
+ needsScroll: true,
305112
+ centerVertically: false
305064
305113
  };
305065
305114
  } else if (userCount <= 4) {
305066
305115
  return {
305067
305116
  cols: 2,
305068
305117
  rows: 2,
305069
305118
  maxVisibleItems: userCount,
305070
- needsScroll: false,
305071
- centerVertically: true
305119
+ needsScroll: true,
305120
+ centerVertically: false
305072
305121
  };
305073
305122
  } else if (userCount <= 6) {
305074
305123
  return {
305075
- cols: 2,
305076
- rows: 3,
305124
+ cols: 3,
305125
+ rows: 2,
305077
305126
  maxVisibleItems: userCount,
305078
- needsScroll: false,
305127
+ needsScroll: true,
305079
305128
  centerVertically: true
305080
305129
  };
305081
305130
  } else if (userCount <= 9) {
@@ -305083,8 +305132,8 @@ const VideoSwipeContainer = reactExports.memo(
305083
305132
  cols: 3,
305084
305133
  rows: 3,
305085
305134
  maxVisibleItems: userCount,
305086
- needsScroll: false,
305087
- centerVertically: true
305135
+ needsScroll: true,
305136
+ centerVertically: false
305088
305137
  };
305089
305138
  } else {
305090
305139
  return {
@@ -305100,79 +305149,85 @@ const VideoSwipeContainer = reactExports.memo(
305100
305149
  const baseStyles = {
305101
305150
  display: "grid",
305102
305151
  width: "100%",
305103
- height: gridLayout.needsScroll ? "100%" : "auto",
305104
305152
  alignContent: gridLayout.centerVertically ? "center" : "start",
305105
305153
  justifyContent: "center",
305106
305154
  margin: "0 auto",
305107
305155
  gap: "0",
305108
305156
  // 网格间距
305109
- padding: "0",
305157
+ padding: "0"
305110
305158
  // 无内边距
305111
- paddingBottom: gridLayout.needsScroll ? "env(safe-area-inset-bottom, 20px)" : "0"
305112
305159
  };
305113
305160
  if (userCount === 1) {
305114
305161
  return {
305115
305162
  ...baseStyles,
305116
305163
  gridTemplateColumns: "1fr",
305117
- gridTemplateRows: "1fr",
305164
+ gridTemplateRows: "auto",
305118
305165
  width: "100%",
305119
305166
  height: "100%"
305120
305167
  };
305121
305168
  } else if (userCount === 2) {
305122
305169
  return {
305123
305170
  ...baseStyles,
305124
- gridTemplateColumns: "repeat(2, 1fr)",
305125
- gridTemplateRows: "1fr",
305171
+ gridTemplateColumns: "repeat(2, minmax(0, 1fr))",
305172
+ gridAutoRows: "min-content",
305173
+ // 不压缩子元素
305126
305174
  width: "100%",
305127
- height: "100%"
305175
+ maxHeight: "100%",
305176
+ overflowY: "auto"
305128
305177
  };
305129
305178
  } else if (userCount <= 4) {
305130
305179
  return {
305131
305180
  ...baseStyles,
305132
- gridTemplateColumns: "repeat(2, 1fr)",
305133
- gridTemplateRows: "repeat(2, 1fr)",
305181
+ gridTemplateColumns: "repeat(2, minmax(0, 1fr))",
305182
+ gridAutoRows: "min-content",
305183
+ // 不压缩子元素
305134
305184
  width: "100%",
305135
- height: "100%"
305185
+ maxHeight: "100%",
305186
+ overflowY: "auto"
305136
305187
  };
305137
305188
  } else if (userCount <= 6) {
305138
305189
  return {
305139
305190
  ...baseStyles,
305140
- gridTemplateColumns: "repeat(2, 1fr)",
305141
- gridTemplateRows: "repeat(3, 1fr)",
305191
+ gridTemplateColumns: "repeat(3, minmax(0, 1fr))",
305192
+ gridAutoRows: "min-content",
305193
+ // 不压缩子元素
305142
305194
  width: "100%",
305143
- height: "100%"
305195
+ maxHeight: "100%",
305196
+ overflowY: "auto"
305144
305197
  };
305145
305198
  } else if (userCount <= 9) {
305146
305199
  return {
305147
305200
  ...baseStyles,
305148
- gridTemplateColumns: "repeat(3, 1fr)",
305149
- gridTemplateRows: "repeat(3, 1fr)",
305201
+ gridTemplateColumns: "repeat(3, minmax(0, 1fr))",
305202
+ gridAutoRows: "min-content",
305203
+ // 不压缩子元素
305150
305204
  width: "100%",
305151
- height: "100%"
305205
+ maxHeight: "100%",
305206
+ overflowY: "auto"
305152
305207
  };
305153
305208
  } else {
305154
305209
  return {
305155
305210
  ...baseStyles,
305156
- gridTemplateColumns: "repeat(3, 1fr)",
305157
- gridAutoRows: "minmax(calc(9/16 * min(33vw, 200px)), auto)",
305158
- // 基于宽度计算高度
305211
+ gridTemplateColumns: "repeat(3, minmax(0, 1fr))",
305212
+ gridAutoRows: "min-content",
305213
+ // 不压缩子元素
305159
305214
  width: "100%",
305160
305215
  height: "100%",
305161
- overflowY: "auto"
305216
+ overflowY: "auto",
305217
+ paddingBottom: "env(safe-area-inset-bottom, 20px)"
305162
305218
  };
305163
305219
  }
305164
305220
  }, [gridLayout.centerVertically, gridLayout.needsScroll, userCount]);
305165
305221
  const videoContainerStyles = reactExports.useMemo(() => {
305166
305222
  return {
305167
305223
  width: "100%",
305168
- height: "100%",
305169
305224
  aspectRatio: "9/16"
305170
- // 保持9:16比例
305225
+ // 保持9:16比例,高度自动计算
305171
305226
  };
305172
305227
  }, [userCount]);
305173
305228
  const gridItemClassName = reactExports.useMemo(() => {
305174
305229
  const baseClass = " overflow-hidden shadow-sm";
305175
- return `${baseClass} flex-shrink-0 w-full h-full`;
305230
+ return `${baseClass} flex-shrink-0 w-full`;
305176
305231
  }, [userCount]);
305177
305232
  const slideContainerStyle = reactExports.useMemo(
305178
305233
  () => ({
@@ -305651,13 +305706,20 @@ const MobileLive = reactExports.memo(({
305651
305706
  }
305652
305707
  const callUser = callUsers.find((user) => user.videoList.includes(videoId));
305653
305708
  const index2 = callUser == null ? void 0 : callUser.videoList.findIndex((id3) => id3 === videoId);
305654
- if ((callUser == null ? void 0 : callUser.rtc_userid) !== callConfig.drawing_board_id && index2 !== 1 && (callUser == null ? void 0 : callUser.isMirror)) {
305709
+ if (
305710
+ // 画板
305711
+ (callUser == null ? void 0 : callUser.rtc_userid) !== callConfig.drawing_board_id && // 共享屏幕
305712
+ index2 !== 1 && // 开镜像
305713
+ (callUser == null ? void 0 : callUser.isMirror)
305714
+ ) {
305655
305715
  videoElement.style.transform = "scaleX(-1)";
305656
305716
  } else {
305657
305717
  videoElement.style.transform = "scaleX(1)";
305658
305718
  }
305659
305719
  videoElement.className = "w-full h-full ";
305660
- videoElement.style.objectFit = index2 === 1 ? "contain" : (callUser == null ? void 0 : callUser.device) === "pc" ? "contain" : "cover";
305720
+ const isModeFit = callUser.rtc_userid === callConfig.drawing_board_id || index2 === 1 || callUser.device === "pc";
305721
+ debugger;
305722
+ videoElement.style.objectFit = isModeFit ? "contain" : "cover";
305661
305723
  videoElement.setAttribute("playsinline", "");
305662
305724
  videoElement.setAttribute("webkit-playsinline", "");
305663
305725
  videoElement.srcObject = _videoElement.srcObject;