@poolse/react 2.13.1 → 2.14.0

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.
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { PoolseConfig, Poolse, Me, Uuid, Conversation, ConversationCreateRequest, Membership, MemberRole, Message, MessageCreateRequest, RealtimeStatus, Attachment, AttachmentUploadInput, PoolseUserProfile, CallRoomStatus, CallParticipant, CameraFacing, LiveKitModule, VoiceStatus, VoiceParticipant, VoiceRoomOptions, IncomingCall, OutgoingCall, CallMedia } from '@poolse/sdk';
2
+ import { PoolseConfig, Poolse, Me, Uuid, Conversation, ConversationCreateRequest, Membership, MemberRole, Message, MessageCreateRequest, RealtimeStatus, Attachment, AttachmentUploadInput, PoolseUserProfile, CallRoomStatus, CallParticipant, CameraFacing, CallDeviceKind, CallDevice, LiveKitModule, VoiceStatus, VoiceParticipant, VoiceRoomOptions, IncomingCall, OutgoingCall, CallMedia } from '@poolse/sdk';
3
3
  export { ApiError, Attachment, AttachmentStatus, AttachmentUploadInput, AttachmentUploadRequest, AttachmentUploadResponse, AuthError, Conversation, ConversationCreateRequest, Me, MemberRole, Membership, Message, MessageCreateRequest, MessageType, NetworkError, PoolseConfig, PoolseError, PoolseUserProfile, RateLimitedError, RealtimeStatus, Uuid } from '@poolse/sdk';
4
4
  import { ReactNode } from 'react';
5
5
 
@@ -518,6 +518,20 @@ interface UseCallRoom {
518
518
  micEnabled: boolean;
519
519
  /** Which camera is publishing. Meaningless while the camera is off. */
520
520
  facingMode: CameraFacing;
521
+ /**
522
+ * Selectable devices, refreshed as they are plugged in and removed.
523
+ *
524
+ * The web's answer to a phone's speaker button — a laptop has no
525
+ * earpiece, but it does have several microphones and a pair of
526
+ * headphones, and choosing between them is the same job. Sparse on
527
+ * React Native, where routing goes through the platform audio session
528
+ * instead (see `useCallAudio` in `@poolse/react-native`).
529
+ */
530
+ devices: Record<CallDeviceKind, CallDevice[]>;
531
+ /** Device id in use per kind, where the platform reports one. */
532
+ activeDevices: Partial<Record<CallDeviceKind, string>>;
533
+ /** Move the call onto another camera, microphone or output. */
534
+ selectDevice: (kind: CallDeviceKind, deviceId: string) => Promise<void>;
521
535
  /**
522
536
  * Everyone else has gone and is not coming back.
523
537
  *
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { PoolseConfig, Poolse, Me, Uuid, Conversation, ConversationCreateRequest, Membership, MemberRole, Message, MessageCreateRequest, RealtimeStatus, Attachment, AttachmentUploadInput, PoolseUserProfile, CallRoomStatus, CallParticipant, CameraFacing, LiveKitModule, VoiceStatus, VoiceParticipant, VoiceRoomOptions, IncomingCall, OutgoingCall, CallMedia } from '@poolse/sdk';
2
+ import { PoolseConfig, Poolse, Me, Uuid, Conversation, ConversationCreateRequest, Membership, MemberRole, Message, MessageCreateRequest, RealtimeStatus, Attachment, AttachmentUploadInput, PoolseUserProfile, CallRoomStatus, CallParticipant, CameraFacing, CallDeviceKind, CallDevice, LiveKitModule, VoiceStatus, VoiceParticipant, VoiceRoomOptions, IncomingCall, OutgoingCall, CallMedia } from '@poolse/sdk';
3
3
  export { ApiError, Attachment, AttachmentStatus, AttachmentUploadInput, AttachmentUploadRequest, AttachmentUploadResponse, AuthError, Conversation, ConversationCreateRequest, Me, MemberRole, Membership, Message, MessageCreateRequest, MessageType, NetworkError, PoolseConfig, PoolseError, PoolseUserProfile, RateLimitedError, RealtimeStatus, Uuid } from '@poolse/sdk';
4
4
  import { ReactNode } from 'react';
5
5
 
@@ -518,6 +518,20 @@ interface UseCallRoom {
518
518
  micEnabled: boolean;
519
519
  /** Which camera is publishing. Meaningless while the camera is off. */
520
520
  facingMode: CameraFacing;
521
+ /**
522
+ * Selectable devices, refreshed as they are plugged in and removed.
523
+ *
524
+ * The web's answer to a phone's speaker button — a laptop has no
525
+ * earpiece, but it does have several microphones and a pair of
526
+ * headphones, and choosing between them is the same job. Sparse on
527
+ * React Native, where routing goes through the platform audio session
528
+ * instead (see `useCallAudio` in `@poolse/react-native`).
529
+ */
530
+ devices: Record<CallDeviceKind, CallDevice[]>;
531
+ /** Device id in use per kind, where the platform reports one. */
532
+ activeDevices: Partial<Record<CallDeviceKind, string>>;
533
+ /** Move the call onto another camera, microphone or output. */
534
+ selectDevice: (kind: CallDeviceKind, deviceId: string) => Promise<void>;
521
535
  /**
522
536
  * Everyone else has gone and is not coming back.
523
537
  *
package/dist/index.js CHANGED
@@ -1070,6 +1070,12 @@ function useCallRoom(conversationId, opts) {
1070
1070
  const [micEnabled, setMic] = useState(false);
1071
1071
  const [facingMode, setFacing] = useState(opts.facing ?? "user");
1072
1072
  const [alone, setAlone] = useState(false);
1073
+ const [devices, setDevices] = useState({
1074
+ videoinput: [],
1075
+ audioinput: [],
1076
+ audiooutput: []
1077
+ });
1078
+ const [activeDevices, setActiveDevices] = useState({});
1073
1079
  const [error, setError] = useState(null);
1074
1080
  const [sfuAvailable, setSfuAvailable] = useState(null);
1075
1081
  const optsRef = useRef(opts);
@@ -1085,6 +1091,21 @@ function useCallRoom(conversationId, opts) {
1085
1091
  ...optsRef.current.aloneGraceMs !== void 0 ? { aloneGraceMs: optsRef.current.aloneGraceMs } : {}
1086
1092
  });
1087
1093
  }, [poolse, conversationId]);
1094
+ const refreshDevices = useCallback((target) => {
1095
+ void Promise.all([
1096
+ target.listDevices("videoinput"),
1097
+ target.listDevices("audioinput"),
1098
+ target.listDevices("audiooutput")
1099
+ ]).then(([videoinput, audioinput, audiooutput]) => {
1100
+ setDevices({ videoinput, audioinput, audiooutput });
1101
+ const active = {};
1102
+ for (const kind of ["videoinput", "audioinput", "audiooutput"]) {
1103
+ const id = target.getActiveDevice(kind);
1104
+ if (id) active[kind] = id;
1105
+ }
1106
+ setActiveDevices(active);
1107
+ });
1108
+ }, []);
1088
1109
  const sync = useCallback((target) => {
1089
1110
  if (!target) return;
1090
1111
  setCamera(target.isCameraEnabled());
@@ -1106,18 +1127,20 @@ function useCallRoom(conversationId, opts) {
1106
1127
  sync(room);
1107
1128
  });
1108
1129
  const offAlone = room.onAlone(() => setAlone(true));
1130
+ const offDevices = room.onDevices(() => refreshDevices(room));
1109
1131
  const offError = room.onError(setError);
1110
1132
  return () => {
1111
1133
  offStatus();
1112
1134
  offRoster();
1113
1135
  offAlone();
1136
+ offDevices();
1114
1137
  offError();
1115
1138
  if (joined.current) {
1116
1139
  joined.current = false;
1117
1140
  room.leave();
1118
1141
  }
1119
1142
  };
1120
- }, [room, sync]);
1143
+ }, [room, sync, refreshDevices]);
1121
1144
  const join = useCallback(async () => {
1122
1145
  if (!room) return false;
1123
1146
  setError(null);
@@ -1126,13 +1149,14 @@ function useCallRoom(conversationId, opts) {
1126
1149
  joined.current = connected;
1127
1150
  setSfuAvailable(connected);
1128
1151
  sync(room);
1152
+ if (connected) refreshDevices(room);
1129
1153
  return connected;
1130
1154
  } catch (err) {
1131
1155
  setError(err instanceof Error ? err : new Error(String(err)));
1132
1156
  setSfuAvailable(true);
1133
1157
  return false;
1134
1158
  }
1135
- }, [room, sync]);
1159
+ }, [room, sync, refreshDevices]);
1136
1160
  const leave = useCallback(() => {
1137
1161
  if (!joined.current) return;
1138
1162
  joined.current = false;
@@ -1167,6 +1191,17 @@ function useCallRoom(conversationId, opts) {
1167
1191
  await room.switchCamera();
1168
1192
  setFacing(room.getFacingMode());
1169
1193
  }, [room]);
1194
+ const selectDevice = useCallback(
1195
+ async (kind, deviceId) => {
1196
+ if (!room) return;
1197
+ await room.setActiveDevice(kind, deviceId);
1198
+ setActiveDevices((current) => ({
1199
+ ...current,
1200
+ [kind]: room.getActiveDevice(kind) ?? deviceId
1201
+ }));
1202
+ },
1203
+ [room]
1204
+ );
1170
1205
  return {
1171
1206
  status,
1172
1207
  participants,
@@ -1174,6 +1209,8 @@ function useCallRoom(conversationId, opts) {
1174
1209
  micEnabled,
1175
1210
  facingMode,
1176
1211
  alone,
1212
+ devices,
1213
+ activeDevices,
1177
1214
  error,
1178
1215
  sfuAvailable,
1179
1216
  join,
@@ -1181,6 +1218,7 @@ function useCallRoom(conversationId, opts) {
1181
1218
  setCameraEnabled,
1182
1219
  toggleCamera,
1183
1220
  switchCamera,
1221
+ selectDevice,
1184
1222
  setMicrophoneEnabled,
1185
1223
  toggleMic
1186
1224
  };