call-live-sdk1 0.0.20 → 0.0.21

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: "暂无可用的远程视频流"
@@ -272872,7 +272884,7 @@ const LivePlayer = ({
272872
272884
  await new Promise((resolve) => {
272873
272885
  audioElement.onloadedmetadata = resolve;
272874
272886
  });
272875
- const audioStream = audioElement.captureStream();
272887
+ audioElement.captureStream();
272876
272888
  const audioObject = new oa(audioElement, {
272877
272889
  selectable: true,
272878
272890
  hasControls: true,
@@ -272898,9 +272910,10 @@ const LivePlayer = ({
272898
272910
  canvas.add(audioObject);
272899
272911
  setFabricObjects((old) => [audioObject, ...old]);
272900
272912
  canvasRequestRenderAll();
272901
- const newBackgroundAudioStreams = new Map(backgroundAudioStreamsRef.current);
272902
- newBackgroundAudioStreams.set(streamId, audioStream);
272903
- backgroundAudioStreamsRef.current = newBackgroundAudioStreams;
272913
+ const videoStream = audioElement.captureStream();
272914
+ const newVideoStreams = new Map(activeVideoStreamsRef.current);
272915
+ newVideoStreams.set(streamId, videoStream);
272916
+ activeVideoStreamsRef.current = newVideoStreams;
272904
272917
  if (rtmpRef.current || canvasRtc) {
272905
272918
  await audioMixing();
272906
272919
  }
@@ -302346,6 +302359,9 @@ const RtcJoomRoom = reactExports.memo(({
302346
302359
  (_a3 = rtc2 == null ? void 0 : rtc2.engine) == null ? void 0 : _a3.unsubscribeStream(userId, MediaType$1.AUDIO);
302347
302360
  }, 100);
302348
302361
  }
302362
+ updateCallUser(userId, {
302363
+ isPublishStream: stream.mediaType
302364
+ });
302349
302365
  },
302350
302366
  handleUserUnpublishStream: async (event) => {
302351
302367
  var _a2, _b;
@@ -302360,6 +302376,9 @@ const RtcJoomRoom = reactExports.memo(({
302360
302376
  if (mediaType & MediaType$1.AUDIO) {
302361
302377
  await ((_b = getter().rtc) == null ? void 0 : _b.engine.unsubscribeStream(userId, MediaType$1.AUDIO));
302362
302378
  }
302379
+ updateCallUser(userId, {
302380
+ isPublishStream: mediaType
302381
+ });
302363
302382
  },
302364
302383
  handleUserStartVideoCapture: (event) => {
302365
302384
  const {
@@ -303694,7 +303713,7 @@ const WebLiveLogin = () => {
303694
303713
  nickname: loginData.data.nickname || "",
303695
303714
  token: loginData.data.token || "",
303696
303715
  device: isMobile$3 ? "mobile" : "pc",
303697
- videoList: [rtc_userid, rtc_userid + "screen", rtc_userid + "main"],
303716
+ videoList: [rtc_userid, rtc_userid + "screen", rtc_userid + "main", rtc_userid + "self"],
303698
303717
  isAudioEnabled: !rtcConfig.enter_muted && devicePermissions.microphone.granted && devicePermissions.microphone.enabled,
303699
303718
  isScreenEnabled: false,
303700
303719
  // 屏幕共享是否开启
@@ -304252,8 +304271,7 @@ const UserAvatar = reactExports.memo(({
304252
304271
  size = 40,
304253
304272
  className = ""
304254
304273
  }) => {
304255
- var _a2;
304256
- const avatarText = ((_a2 = nickname == null ? void 0 : nickname.charAt(0)) == null ? void 0 : _a2.toUpperCase()) || "?";
304274
+ const avatarText = (nickname == null ? void 0 : nickname.trim().charAt(0)) || "?";
304257
304275
  return /* @__PURE__ */ jsxRuntimeExports.jsx(Avatar, {
304258
304276
  size,
304259
304277
  className,
@@ -304853,8 +304871,12 @@ const UserVideoContainer = reactExports.memo(({
304853
304871
  const displayName = reactExports.useMemo(() => {
304854
304872
  return user.nickname || "未知用户";
304855
304873
  }, [user.nickname]);
304874
+ const isSelfWindow = reactExports.useMemo(() => {
304875
+ return videoId == null ? void 0 : videoId.includes("self");
304876
+ }, [videoId]);
304877
+ const maxNameLength = isSelfWindow ? 3 : 4;
304856
304878
  const avatarChar = reactExports.useMemo(() => {
304857
- return displayName.charAt(0).toUpperCase();
304879
+ return displayName.trim().charAt(0);
304858
304880
  }, [displayName]);
304859
304881
  const handleClick = reactExports.useCallback(() => {
304860
304882
  onClick == null ? void 0 : onClick(videoId || "");
@@ -304868,6 +304890,14 @@ const UserVideoContainer = reactExports.memo(({
304868
304890
  console.log("main======", user, videoId);
304869
304891
  }
304870
304892
  const noMirror = user.rtc_userid === callConfig.drawing_board_id || (videoId == null ? void 0 : videoId.includes("screen")) || !user.isMirror;
304893
+ console.log("[UserVideoContainer] 镜像设置调试:", {
304894
+ videoId,
304895
+ userRtcUserid: user.rtc_userid,
304896
+ callConfigRtcUserid: callConfig.rtc_userid,
304897
+ userIsMirror: user.isMirror,
304898
+ noMirror,
304899
+ shouldMirror: +!noMirror
304900
+ });
304871
304901
  const isModeFit = user.rtc_userid === callConfig.drawing_board_id || (videoId == null ? void 0 : videoId.includes("screen")) || user.device === "pc";
304872
304902
  if (user.rtc_userid === callConfig.rtc_userid) {
304873
304903
  rtc.engine.setLocalVideoPlayer((videoId == null ? void 0 : videoId.includes("screen")) ? StreamIndex$1.STREAM_INDEX_SCREEN : StreamIndex$1.STREAM_INDEX_MAIN, {
@@ -304935,7 +304965,7 @@ const UserVideoContainer = reactExports.memo(({
304935
304965
  className: "",
304936
304966
  children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", {
304937
304967
  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 : ""
304968
+ children: displayName ? displayName.length > maxNameLength ? `${displayName.substring(0, maxNameLength)}...` : displayName : ""
304939
304969
  })
304940
304970
  }), /* @__PURE__ */ jsxRuntimeExports.jsx("div", {
304941
304971
  className: `
@@ -305059,23 +305089,23 @@ const VideoSwipeContainer = reactExports.memo(
305059
305089
  cols: 2,
305060
305090
  rows: 1,
305061
305091
  maxVisibleItems: 2,
305062
- needsScroll: false,
305063
- centerVertically: true
305092
+ needsScroll: true,
305093
+ centerVertically: false
305064
305094
  };
305065
305095
  } else if (userCount <= 4) {
305066
305096
  return {
305067
305097
  cols: 2,
305068
305098
  rows: 2,
305069
305099
  maxVisibleItems: userCount,
305070
- needsScroll: false,
305071
- centerVertically: true
305100
+ needsScroll: true,
305101
+ centerVertically: false
305072
305102
  };
305073
305103
  } else if (userCount <= 6) {
305074
305104
  return {
305075
- cols: 2,
305076
- rows: 3,
305105
+ cols: 3,
305106
+ rows: 2,
305077
305107
  maxVisibleItems: userCount,
305078
- needsScroll: false,
305108
+ needsScroll: true,
305079
305109
  centerVertically: true
305080
305110
  };
305081
305111
  } else if (userCount <= 9) {
@@ -305083,8 +305113,8 @@ const VideoSwipeContainer = reactExports.memo(
305083
305113
  cols: 3,
305084
305114
  rows: 3,
305085
305115
  maxVisibleItems: userCount,
305086
- needsScroll: false,
305087
- centerVertically: true
305116
+ needsScroll: true,
305117
+ centerVertically: false
305088
305118
  };
305089
305119
  } else {
305090
305120
  return {
@@ -305100,79 +305130,85 @@ const VideoSwipeContainer = reactExports.memo(
305100
305130
  const baseStyles = {
305101
305131
  display: "grid",
305102
305132
  width: "100%",
305103
- height: gridLayout.needsScroll ? "100%" : "auto",
305104
305133
  alignContent: gridLayout.centerVertically ? "center" : "start",
305105
305134
  justifyContent: "center",
305106
305135
  margin: "0 auto",
305107
305136
  gap: "0",
305108
305137
  // 网格间距
305109
- padding: "0",
305138
+ padding: "0"
305110
305139
  // 无内边距
305111
- paddingBottom: gridLayout.needsScroll ? "env(safe-area-inset-bottom, 20px)" : "0"
305112
305140
  };
305113
305141
  if (userCount === 1) {
305114
305142
  return {
305115
305143
  ...baseStyles,
305116
305144
  gridTemplateColumns: "1fr",
305117
- gridTemplateRows: "1fr",
305145
+ gridTemplateRows: "auto",
305118
305146
  width: "100%",
305119
305147
  height: "100%"
305120
305148
  };
305121
305149
  } else if (userCount === 2) {
305122
305150
  return {
305123
305151
  ...baseStyles,
305124
- gridTemplateColumns: "repeat(2, 1fr)",
305125
- gridTemplateRows: "1fr",
305152
+ gridTemplateColumns: "repeat(2, minmax(0, 1fr))",
305153
+ gridAutoRows: "min-content",
305154
+ // 不压缩子元素
305126
305155
  width: "100%",
305127
- height: "100%"
305156
+ maxHeight: "100%",
305157
+ overflowY: "auto"
305128
305158
  };
305129
305159
  } else if (userCount <= 4) {
305130
305160
  return {
305131
305161
  ...baseStyles,
305132
- gridTemplateColumns: "repeat(2, 1fr)",
305133
- gridTemplateRows: "repeat(2, 1fr)",
305162
+ gridTemplateColumns: "repeat(2, minmax(0, 1fr))",
305163
+ gridAutoRows: "min-content",
305164
+ // 不压缩子元素
305134
305165
  width: "100%",
305135
- height: "100%"
305166
+ maxHeight: "100%",
305167
+ overflowY: "auto"
305136
305168
  };
305137
305169
  } else if (userCount <= 6) {
305138
305170
  return {
305139
305171
  ...baseStyles,
305140
- gridTemplateColumns: "repeat(2, 1fr)",
305141
- gridTemplateRows: "repeat(3, 1fr)",
305172
+ gridTemplateColumns: "repeat(3, minmax(0, 1fr))",
305173
+ gridAutoRows: "min-content",
305174
+ // 不压缩子元素
305142
305175
  width: "100%",
305143
- height: "100%"
305176
+ maxHeight: "100%",
305177
+ overflowY: "auto"
305144
305178
  };
305145
305179
  } else if (userCount <= 9) {
305146
305180
  return {
305147
305181
  ...baseStyles,
305148
- gridTemplateColumns: "repeat(3, 1fr)",
305149
- gridTemplateRows: "repeat(3, 1fr)",
305182
+ gridTemplateColumns: "repeat(3, minmax(0, 1fr))",
305183
+ gridAutoRows: "min-content",
305184
+ // 不压缩子元素
305150
305185
  width: "100%",
305151
- height: "100%"
305186
+ maxHeight: "100%",
305187
+ overflowY: "auto"
305152
305188
  };
305153
305189
  } else {
305154
305190
  return {
305155
305191
  ...baseStyles,
305156
- gridTemplateColumns: "repeat(3, 1fr)",
305157
- gridAutoRows: "minmax(calc(9/16 * min(33vw, 200px)), auto)",
305158
- // 基于宽度计算高度
305192
+ gridTemplateColumns: "repeat(3, minmax(0, 1fr))",
305193
+ gridAutoRows: "min-content",
305194
+ // 不压缩子元素
305159
305195
  width: "100%",
305160
305196
  height: "100%",
305161
- overflowY: "auto"
305197
+ overflowY: "auto",
305198
+ paddingBottom: "env(safe-area-inset-bottom, 20px)"
305162
305199
  };
305163
305200
  }
305164
305201
  }, [gridLayout.centerVertically, gridLayout.needsScroll, userCount]);
305165
305202
  const videoContainerStyles = reactExports.useMemo(() => {
305166
305203
  return {
305167
305204
  width: "100%",
305168
- height: "100%",
305169
305205
  aspectRatio: "9/16"
305170
- // 保持9:16比例
305206
+ // 保持9:16比例,高度自动计算
305171
305207
  };
305172
305208
  }, [userCount]);
305173
305209
  const gridItemClassName = reactExports.useMemo(() => {
305174
305210
  const baseClass = " overflow-hidden shadow-sm";
305175
- return `${baseClass} flex-shrink-0 w-full h-full`;
305211
+ return `${baseClass} flex-shrink-0 w-full`;
305176
305212
  }, [userCount]);
305177
305213
  const slideContainerStyle = reactExports.useMemo(
305178
305214
  () => ({
@@ -305651,7 +305687,12 @@ const MobileLive = reactExports.memo(({
305651
305687
  }
305652
305688
  const callUser = callUsers.find((user) => user.videoList.includes(videoId));
305653
305689
  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)) {
305690
+ if (
305691
+ // 画板
305692
+ (callUser == null ? void 0 : callUser.rtc_userid) !== callConfig.drawing_board_id && // 共享屏幕
305693
+ index2 !== 1 && // 开镜像
305694
+ (callUser == null ? void 0 : callUser.isMirror)
305695
+ ) {
305655
305696
  videoElement.style.transform = "scaleX(-1)";
305656
305697
  } else {
305657
305698
  videoElement.style.transform = "scaleX(1)";