@wetspace/wetrtc 2.0.1 → 2.0.2

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.
@@ -0,0 +1,34 @@
1
+ import { WetRTCPlayer } from './index';
2
+ import type { WetCreateConnectOneOption, ConnectionState } from './index';
3
+ import type { MutableRefObject } from 'react';
4
+ interface UseWebRtcParams {
5
+ name: string | number | MutableRefObject<string | number>;
6
+ senderSdp: (sdp: RTCSessionDescriptionInit) => void;
7
+ senderIce?: (ice: RTCIceCandidate) => void;
8
+ connectionConfig?: {
9
+ configuration?: RTCConfiguration;
10
+ constraints?: MediaStreamConstraints;
11
+ };
12
+ onError?: (err: {
13
+ code: string;
14
+ message: string;
15
+ }) => void;
16
+ }
17
+ declare const useWetRTC: (options: UseWebRtcParams) => {
18
+ connect: (transDirect?: WetCreateConnectOneOption['transDirect'], sdp?: RTCSessionDescriptionInit | undefined) => Promise<void>;
19
+ disconnect: () => void;
20
+ play: (type: 'remote' | 'local', player?: WetRTCPlayer) => void;
21
+ answerAction: (sdp: RTCSessionDescriptionInit) => void;
22
+ connectState: ConnectionState;
23
+ useAblesState: {
24
+ audioinput: boolean;
25
+ audiooutput: boolean;
26
+ videoinput: boolean;
27
+ };
28
+ useAbleRef: MutableRefObject<{
29
+ audioinput: boolean;
30
+ audiooutput: boolean;
31
+ videoinput: boolean;
32
+ }>;
33
+ };
34
+ export { useWetRTC };
@@ -5,51 +5,53 @@ export interface WetRTCConnectctItem {
5
5
  state: ConnectionState;
6
6
  uuid: string;
7
7
  name: string;
8
+ streams: MediaStream | null;
9
+ transDirect: 'recvonly' | 'sendonly' | 'sendrecv';
8
10
  }
9
- export interface WetRTCoptions {
11
+ export interface WetRTCItemType {
12
+ connect: (sdp?: RTCSessionDescriptionInit | undefined, stateChange?: ((state: ConnectionState) => void) | undefined) => Promise<RTCSessionDescriptionInit | null>;
13
+ play?: (player?: WetRTCPlayer) => void;
14
+ setRemoteSdp: (sdp: RTCSessionDescriptionInit) => void;
15
+ addIceCandidate: (sdp: RTCIceCandidate) => void;
16
+ self: WetRTCConnectctItem;
17
+ }
18
+ export interface WetCreateConnectOneOption {
10
19
  configuration?: RTCConfiguration;
11
- constraints?: MediaStreamConstraints;
12
- localPlayer?: WetRTCPlayer;
20
+ uuid?: string;
21
+ name?: string;
22
+ transDirect?: 'recvonly' | 'sendonly' | 'sendrecv';
23
+ iceCb?: (candidate: RTCIceCandidate) => void;
13
24
  }
14
25
  export declare class WetRTC {
15
- streamControl: {
16
- stream: MediaStream;
17
- close: () => void;
18
- } | null;
19
26
  rtcConnectMap: Map<string | number, WetRTCConnectctItem>;
20
- private _options;
27
+ private constraints;
28
+ private streamControl;
21
29
  private isUseAbles;
22
- constructor(configuration?: RTCConfiguration, constraints?: MediaStreamConstraints);
23
- private init;
30
+ constructor(options?: MediaStreamConstraints);
31
+ getUseAbleDevices(): Promise<MediaDeviceInfo[] | null>;
24
32
  private captureStream;
25
- /**
26
- * 创建连接
27
- */
28
- createConnectOne(option: {
29
- sdp?: RTCSessionDescriptionInit;
30
- player: WetRTCPlayer;
31
- uuid?: string;
32
- name?: string;
33
- }): {
34
- uuid: string;
35
- setRemote: (sdp: RTCSessionDescriptionInit) => void;
36
- addIceCandidate: (sdp: RTCIceCandidate) => void;
37
- next: (icecandidateCb: (candidate: RTCIceCandidate) => void, stateChange?: ((state: ConnectionState) => void) | undefined) => Promise<RTCSessionDescriptionInit>;
38
- };
39
- /**
40
- * 关闭连接
41
- */
42
- disconnect(uuid?: string): void;
33
+ closeCaptureStream(): void;
34
+ playLocalStream(player: WetRTCPlayer): void;
35
+ createConnectOne(option: Omit<WetCreateConnectOneOption, 'transDirect'> & {
36
+ transDirect: 'sendonly';
37
+ }): Omit<WetRTCItemType, 'play'>;
38
+ createConnectOne(option: Omit<WetCreateConnectOneOption, 'transDirect'> & {
39
+ transDirect?: 'recvonly' | 'sendrecv';
40
+ }): WetRTCItemType;
43
41
  /**
44
42
  * 获取特定的连接
45
43
  */
46
44
  getConnectById(uuid: string): WetRTCConnectctItem | undefined;
47
45
  /**
48
- * 设置远程sdp信息
46
+ * 关闭流的
49
47
  */
50
- setRemoteDescriptionById(uuid: string, sdp: RTCSessionDescriptionInit): Promise<unknown>;
48
+ private closeStream;
49
+ /**
50
+ * 关闭连接
51
+ */
52
+ disconnect(uuid?: string): void;
51
53
  /**
52
- * 设置远程IceCandidate信息
54
+ * 关闭所有的流
53
55
  */
54
- addIceCandidateById(uuid: string, sdp: RTCIceCandidateInit): Promise<unknown>;
56
+ close(): void;
55
57
  }
package/es/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- import { getUseAbleDevices, getMediaStream } from './libs';
2
- import { SaveFileToLocal, createStreamToRecord } from './libs/record';
3
- import { WetRTC } from './core';
4
- export { getUseAbleDevices, getMediaStream, SaveFileToLocal, createStreamToRecord };
1
+ import { getUseAbleDevices, getMediaStream, concatStream, filterStream, getRtcPeerTracks } from './libs';
2
+ import { streamToRecord } from './libs/record';
3
+ import { WetRTC } from './core/index';
4
+ import { useWetRTC } from './core/hook';
5
+ export { getUseAbleDevices, getMediaStream, concatStream, filterStream, streamToRecord, getRtcPeerTracks, useWetRTC, };
5
6
  export default WetRTC;
package/es/index.js CHANGED
@@ -1 +1 @@
1
- function __awaiter(e,s,a,c){return new(a=a||Promise)(function(o,t){function n(e){try{r(c.next(e))}catch(e){t(e)}}function i(e){try{r(c.throw(e))}catch(e){t(e)}}function r(e){var t;e.done?o(e.value):((t=e.value)instanceof a?t:new a(function(e){e(t)})).then(n,i)}r((c=c.apply(e,s||[])).next())})}const getUseAbleDevices=()=>__awaiter(void 0,void 0,void 0,function*(){return navigator.mediaDevices.enumerateDevices?yield navigator.mediaDevices.enumerateDevices():Promise.reject({type:"CompatibilityError",message:"暂不支持-getUseAbleDevices"})}),getMediaStream=(n="display")=>{const i="display"===n?"getDisplayMedia":"getUserMedia";return o=>__awaiter(void 0,void 0,void 0,function*(){if(!navigator.mediaDevices[i])return Promise.reject({type:"CompatibilityError",message:`暂不支持-${i},`});try{var e="display"===n?o:o||{video:!0,audio:{noiseSuppression:!0,echoCancellation:!0,enableBackground:!1,suppressLocalAudioPlayback:!0}};const t=yield navigator.mediaDevices[i](e);return{stream:t,close:()=>{t.getTracks().forEach(e=>{e.stop()})}}}catch(e){return"Permission denied"===e.message?Promise.reject({type:"CancelError",message:"请求已经取消"}):Promise.reject({type:"GeneralError",message:e.message||"未知错误"})}})},filterStream=(e,t)=>{let o=[];return e.forEach(e=>{o=[...o,...e.getTracks().filter(e=>t?e.kind===t:e)]}),new MediaStream(o)},getRemoteTracks=e=>e.getReceivers().map(e=>e.track),getSaveProgressNum=(e,i)=>{const t=e.getReader();let r=0;return new ReadableStream({start(n){return function o(){return t.read().then(e=>{var{done:e,value:t}=e;if(!e)return r+=(null==t?void 0:t.length)||0,console.log(r/i),n.enqueue(t),o();n.close()})}()}})},SaveFileToLocal=(e,t)=>{e=URL.createObjectURL(e);const o=document.createElement("a");o.href=e,o.target="_blank",o.style.display="none",document.body.appendChild(o),o.download=t,o.click(),URL.revokeObjectURL(e),document.body.removeChild(o)},createStreamToRecord=(e,t={audioBitsPerSecond:128e3,videoBitsPerSecond:25e5,mimeType:"video/webm"})=>{const n=t.mimeType?t.mimeType.split("/"):["webm"];let i=(new Date).getTime().toString();const o=MediaRecorder.isTypeSupported(t.mimeType||"");if(!o)throw new Error(t.mimeType+"类型不支持");const r=new MediaRecorder(e,t);r.addEventListener("dataavailable",e=>{const t=e.data,o=t.size;e=URL.createObjectURL(t);fetch(e).then(e=>e.ok?e:Promise.reject("保存视频失败")).then(e=>e.body).then(e=>e?(SaveFileToLocal(t,i+"."+n[(null===n||void 0===n?void 0:n.length)-1]),getSaveProgressNum(e,o)):Promise.reject("没有可用的流"))});const s=()=>{o&&r.stop()};return{start:()=>{o&&r.start()},pause:()=>{o&&r.pause()},save:e=>{o&&(i=e||(new Date).getTime().toString(),s())},stop:s,resume:()=>{o&&r.resume()}}};let getRandomValues;const rnds8=new Uint8Array(16);function rng(){if(!getRandomValues&&!(getRandomValues="undefined"!=typeof crypto&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto)))throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");return getRandomValues(rnds8)}const byteToHex=[];for(let e=0;e<256;++e)byteToHex.push((e+256).toString(16).slice(1));function unsafeStringify(e,t=0){return(byteToHex[e[t+0]]+byteToHex[e[t+1]]+byteToHex[e[t+2]]+byteToHex[e[t+3]]+"-"+byteToHex[e[t+4]]+byteToHex[e[t+5]]+"-"+byteToHex[e[t+6]]+byteToHex[e[t+7]]+"-"+byteToHex[e[t+8]]+byteToHex[e[t+9]]+"-"+byteToHex[e[t+10]]+byteToHex[e[t+11]]+byteToHex[e[t+12]]+byteToHex[e[t+13]]+byteToHex[e[t+14]]+byteToHex[e[t+15]]).toLowerCase()}const randomUUID="undefined"!=typeof crypto&&crypto.randomUUID&&crypto.randomUUID.bind(crypto);var native={randomUUID:randomUUID};function v4(e,t,o){if(native.randomUUID&&!t&&!e)return native.randomUUID();const n=(e=e||{}).random||(e.rng||rng)();if(n[6]=15&n[6]|64,n[8]=63&n[8]|128,t){o=o||0;for(let e=0;e<16;++e)t[o+e]=n[e];return t}return unsafeStringify(n)}class WetRTC{constructor(e,t){this.streamControl=null,this.rtcConnectMap=new Map,this._options={configuration:{iceServers:[{urls:"stun:stun.l.google.com:19302"}]}},this.isUseAbles={audiooutput:!1,audioinput:!1,videoinput:!1},this.init({configuration:e,constraints:t})}init(e){this._options.constraints=null==e?void 0:e.constraints,this._options.configuration=Object.assign(Object.assign({},this._options.configuration),null==e?void 0:e.configuration),getUseAbleDevices().then(e=>{const t=e.map(e=>e.kind);this.isUseAbles.audioinput=t.includes("audioinput"),this.isUseAbles.videoinput=t.includes("videoinput"),this.isUseAbles.audiooutput=t.includes("audiooutput")}).catch(e=>{"CompatibilityError"===e.type&&(this.isUseAbles.audioinput=!0,this.isUseAbles.videoinput=!0,this.isUseAbles.audiooutput=!0)})}captureStream(){return __awaiter(this,void 0,void 0,function*(){var e=yield getMediaStream("user")(this._options.constraints);this.streamControl=e})}createConnectOne(o){const i=null==o?void 0:o.sdp,r=new RTCPeerConnection(this._options.configuration),s=(null==o?void 0:o.uuid)||v4(),a={RTCPeerIns:r,state:"new",name:(null==o?void 0:o.name)||s,uuid:s};return r.addEventListener("track",e=>{const t=o.player;t?(t.setAttribute("autoplay",""),t.setAttribute("playsinline",""),console.log(e.streams,t),t.srcObject=e.streams[0]):console.warn("缺少媒体播放元素video或者是audio")}),{uuid:s,setRemote:e=>{r.setRemoteDescription(e)},addIceCandidate:e=>{r.addIceCandidate(e)},next:(o,n)=>__awaiter(this,void 0,void 0,function*(){if(this.rtcConnectMap.set(s,a),r.addEventListener("icecandidate",e=>{e.candidate&&(console.log("icecandidate",e),o(e.candidate))}),r.addEventListener("connectionstatechange",e=>{e=e.target;a.state=e.connectionState,console.log(a.state),n&&n(a.state)}),this.streamControl||(yield this.captureStream()),this.streamControl){const t=filterStream([this.streamControl.stream],"video");t.getTracks().forEach(e=>{r.addTrack(e,t)})}var e;return i?(yield r.setRemoteDescription(i),e=yield r.createAnswer(),yield r.setLocalDescription(e),e):(e=yield r.createOffer(),yield r.setLocalDescription(e),e)})}}disconnect(e){var t;if(e){if(!this.rtcConnectMap.has(e))return;const o=this.getConnectById(e);if(o){const n=getRemoteTracks(o.RTCPeerIns);n.forEach(e=>{null!=e&&e.stop()}),o.RTCPeerIns.close(),this.rtcConnectMap.delete(e)}}else this.rtcConnectMap.forEach(e=>{const t=getRemoteTracks(e.RTCPeerIns);t.forEach(e=>{null!=e&&e.stop()}),e.RTCPeerIns.close()}),this.rtcConnectMap.clear();0===this.rtcConnectMap.size&&null!==(t=this.streamControl)&&void 0!==t&&t.close()}getConnectById(e){return this.rtcConnectMap.get(e)}setRemoteDescriptionById(t,o){return __awaiter(this,void 0,void 0,function*(){const e=this.getConnectById(t);try{yield null===e||void 0===e?void 0:e.RTCPeerIns.setRemoteDescription(o)}catch(e){return e}})}addIceCandidateById(t,o){return __awaiter(this,void 0,void 0,function*(){const e=this.getConnectById(t);try{yield null===e||void 0===e?void 0:e.RTCPeerIns.addIceCandidate(o)}catch(e){return e}})}}export{SaveFileToLocal,createStreamToRecord,WetRTC as default,getMediaStream,getUseAbleDevices};
1
+ import{useRef,useState,useEffect,useCallback}from"react";function __awaiter(e,s,a,c){return new(a=a||Promise)(function(n,t){function r(e){try{o(c.next(e))}catch(e){t(e)}}function i(e){try{o(c.throw(e))}catch(e){t(e)}}function o(e){var t;e.done?n(e.value):((t=e.value)instanceof a?t:new a(function(e){e(t)})).then(r,i)}o((c=c.apply(e,s||[])).next())})}const getUseAbleDevices=()=>__awaiter(void 0,void 0,void 0,function*(){return navigator.mediaDevices&&navigator.mediaDevices.enumerateDevices?yield navigator.mediaDevices.enumerateDevices():(console.error("navigator.mediaDevices.enumerateDevices"),null)}),getMediaStream=(e="display")=>{const r="display"===e?"getDisplayMedia":"getUserMedia";return n=>__awaiter(void 0,void 0,void 0,function*(){if(navigator.mediaDevices[r]){var e=n||{video:!0,audio:{noiseSuppression:!0,echoCancellation:!0,enableBackground:!1,suppressLocalAudioPlayback:!0}};const t=yield navigator.mediaDevices[r](e);return{streams:t,close(){t.getTracks().forEach(e=>{e.stop()})}}}return console.error("不支持mediaDevices"),null})},concatStream=e=>{let t=[];return e.forEach(e=>{t=[...t,...e.getTracks()]}),new MediaStream(t)},filterStream=(e,t)=>{let n=[];return e.forEach(e=>{n=[...n,...e.getTracks().filter(e=>t?e.kind===t:e)]}),new MediaStream(n)},getRtcPeerTracks=(e,t)=>{const n={receivers(){return e.getReceivers().map(e=>e.track)},senders(){return e.getSenders().map(e=>e.track)}};return t?n[t]():[...n.receivers(),...n.senders()]},SaveFileToLocal=(e,t)=>{e=URL.createObjectURL(e);const n=document.createElement("a");n.href=e,n.target="_blank",n.style.display="none",document.body.appendChild(n),n.download=t,n.click(),URL.revokeObjectURL(e),document.body.removeChild(n)},streamToRecord=(e,t={audioBitsPerSecond:128e3,videoBitsPerSecond:25e5,mimeType:"video/webm"})=>{const n=t.mimeType?t.mimeType.split("/"):["webm"];let r=(new Date).getTime().toString();const i=MediaRecorder.isTypeSupported(t.mimeType||"");if(!i)throw new Error(t.mimeType+"类型不支持");const o=new MediaRecorder(e,t);o.addEventListener("dataavailable",e=>{SaveFileToLocal(e.data,r+"."+n[(null===n||void 0===n?void 0:n.length)-1])});const s=()=>{i&&o.stop()};return{start:()=>{i&&o.start()},pause:()=>{i&&o.pause()},save:e=>{i&&(r=e||(new Date).getTime().toString(),s())},stop:s,resume:()=>{i&&o.resume()}}};let getRandomValues;const rnds8=new Uint8Array(16);function rng(){if(!getRandomValues&&!(getRandomValues="undefined"!=typeof crypto&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto)))throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");return getRandomValues(rnds8)}const byteToHex=[];for(let e=0;e<256;++e)byteToHex.push((e+256).toString(16).slice(1));function unsafeStringify(e,t=0){return(byteToHex[e[t+0]]+byteToHex[e[t+1]]+byteToHex[e[t+2]]+byteToHex[e[t+3]]+"-"+byteToHex[e[t+4]]+byteToHex[e[t+5]]+"-"+byteToHex[e[t+6]]+byteToHex[e[t+7]]+"-"+byteToHex[e[t+8]]+byteToHex[e[t+9]]+"-"+byteToHex[e[t+10]]+byteToHex[e[t+11]]+byteToHex[e[t+12]]+byteToHex[e[t+13]]+byteToHex[e[t+14]]+byteToHex[e[t+15]]).toLowerCase()}const randomUUID="undefined"!=typeof crypto&&crypto.randomUUID&&crypto.randomUUID.bind(crypto);var native={randomUUID:randomUUID};function v4(e,t,n){if(native.randomUUID&&!t&&!e)return native.randomUUID();const r=(e=e||{}).random||(e.rng||rng)();if(r[6]=15&r[6]|64,r[8]=63&r[8]|128,t){n=n||0;for(let e=0;e<16;++e)t[n+e]=r[e];return t}return unsafeStringify(r)}const DefaultConfiguration={iceServers:[{urls:"stun:stun.l.google.com:19302"}]};class WetRTC{constructor(e){this.rtcConnectMap=new Map,this.constraints={video:!0,audio:{noiseSuppression:!0,echoCancellation:!0,suppressLocalAudioPlayback:!0}},this.streamControl=null,this.isUseAbles={audiooutput:!1,audioinput:!1,videoinput:!1},e&&(this.constraints=e),getUseAbleDevices().then(e=>{if(e){const t=e.map(e=>e.kind);this.isUseAbles.audioinput=t.includes("audioinput"),this.isUseAbles.videoinput=t.includes("videoinput"),this.isUseAbles.audiooutput=t.includes("audiooutput")}else this.isUseAbles.audioinput=!0,this.isUseAbles.videoinput=!0,this.isUseAbles.audiooutput=!0})}getUseAbleDevices(){return __awaiter(this,void 0,void 0,function*(){return yield getUseAbleDevices()})}captureStream(){return __awaiter(this,void 0,void 0,function*(){var e;return this.isUseAbles.audioinput||this.isUseAbles.videoinput?((e=yield getMediaStream("user")({video:!!this.isUseAbles.videoinput&&this.constraints.audio,audio:!!this.isUseAbles.audioinput&&this.constraints.audio}))&&(this.streamControl=e),e):null})}closeCaptureStream(){var e;null!==(e=this.streamControl)&&void 0!==e&&e.close(),this.streamControl=null}playLocalStream(e){this.streamControl&&e&&(e.setAttribute("autoPlay",""),e.setAttribute("playsInline",""),e.srcObject=this.streamControl.streams)}createConnectOne(e){let i="new";const{configuration:t,uuid:n,name:r,transDirect:d,iceCb:o}=e||{};e=t||DefaultConfiguration;const s=d||"sendrecv",a=n||v4(),c=new RTCPeerConnection(e),u={RTCPeerIns:c,state:"new",name:r||a,uuid:"",streams:null,transDirect:s};return{connect:(n,r)=>__awaiter(this,void 0,void 0,function*(){var e;if(["sendrecv","sendonly"].includes(s)&&!this.streamControl&&!(yield this.captureStream()))return null;if(u.uuid=a,this.rtcConnectMap.set(a,u),c.addEventListener("track",e=>{u.streams=e.streams[0]}),Object.defineProperty(u,"state",{get(){return i},set(e){i=e,r&&r(e)}}),c.addEventListener("icecandidate",e=>{e.candidate&&o&&o(e.candidate)}),c.addEventListener("connectionstatechange",e=>{e=e.target;u.state=e.connectionState}),["sendrecv","sendonly"].includes(s)){const t=null===(e=this.streamControl)||void 0===e?void 0:e.streams;null!==t&&void 0!==t&&t.getTracks().forEach(e=>{c.addTrack(e,t)})}else c.addTransceiver("video",{direction:"recvonly"}),c.addTransceiver("audio",{direction:"recvonly"});return n?(yield c.setRemoteDescription(n),e=yield c.createAnswer(),yield c.setLocalDescription(e),e):(e=yield c.createOffer(),yield c.setLocalDescription(e),e)}),play:"sendonly"===s?void 0:e=>{let t=0;if(u.uuid)if(u.streams)null!=e&&e.setAttribute("autoplay",""),null!=e&&e.setAttribute("playsinline",""),e&&(e.srcObject=u.streams);else{const n=setInterval(()=>{t+=100,u.streams&&(null!=e&&e.setAttribute("autoplay",""),null!=e&&e.setAttribute("playsinline",""),e&&(e.srcObject=u.streams),clearInterval(n)),1e4<=t&&(clearInterval(n),console.error("流媒体轨道错误,播放失败"))},100)}},self:u,setRemoteSdp:e=>{c.setRemoteDescription(e)},addIceCandidate:e=>{c.addIceCandidate(e)}}}getConnectById(e){return this.rtcConnectMap.get(e)}closeStream(e){if(e&&e.RTCPeerIns){const t={recvonly:()=>getRtcPeerTracks(e.RTCPeerIns,"receivers"),sendonly:()=>getRtcPeerTracks(e.RTCPeerIns,"senders"),sendrecv:()=>getRtcPeerTracks(e.RTCPeerIns)},n=t[e.transDirect]();n.forEach(e=>{null!=e&&e.stop()}),e.streams=null}}disconnect(e){if(e){if(this.rtcConnectMap.has(e)){const t=this.getConnectById(e);t.state="closed",this.closeStream(t),null!==t&&void 0!==t&&t.RTCPeerIns.close(),this.rtcConnectMap.delete(e)}}else this.rtcConnectMap.forEach(e=>{e.state="closed",this.closeStream(e),e.RTCPeerIns.close()}),this.rtcConnectMap.clear()}close(){this.disconnect(),this.closeCaptureStream()}}const useWetRTC=e=>{const{senderSdp:r,senderIce:i,connectionConfig:o,name:s,onError:a}=e,c=useRef(null),u=useRef(null),[t,l]=useState({audioinput:!1,audiooutput:!1,videoinput:!1}),d=useRef({audioinput:!1,audiooutput:!1,videoinput:!1}),[n,p]=useState("new");useEffect(()=>{c.current=new WetRTC(o&&(null===o||void 0===o?void 0:o.constraints)),c.current.getUseAbleDevices().then(e=>{const t={audioinput:!0,audiooutput:!0,videoinput:!0};if(e){const n=e.map(e=>e.kind);t.audioinput=n.includes("audioinput"),t.audiooutput=n.includes("audiooutput"),t.videoinput=n.includes("videoinput"),d.current=Object.assign({},t)}l(()=>t)})},[]);return{connect:useCallback((t="sendrecv",n)=>__awaiter(void 0,void 0,void 0,function*(){var e="object"==typeof s?s.current:s;c.current&&e&&(u.current=c.current.createConnectOne({transDirect:t,iceCb:i,configuration:o&&o.configuration}),(e=yield u.current.connect(n,e=>{p(()=>e)}))?r(e):(console.error("sdp获取失败,连接错误"),a&&a({code:"error",message:"sdp获取失败,连接错误"})))}),["object"==typeof s?s.current:s]),disconnect:()=>{var e;null!==(e=c.current)&&void 0!==e&&e.close()},play:(e,t)=>{"local"===e?null!==(e=c.current)&&void 0!==e&&e.playLocalStream(t):u.current&&u.current.play&&u.current.play(t)},answerAction:e=>{var t;null!==(t=u.current)&&void 0!==t&&t.setRemoteSdp(e)},connectState:n,useAblesState:t,useAbleRef:d}};export{concatStream,WetRTC as default,filterStream,getMediaStream,getRtcPeerTracks,getUseAbleDevices,streamToRecord,useWetRTC};
@@ -2,7 +2,7 @@
2
2
  * 获取可用设备
3
3
  * @returns Promise
4
4
  */
5
- export declare const getUseAbleDevices: () => Promise<MediaDeviceInfo[]>;
5
+ export declare const getUseAbleDevices: () => Promise<MediaDeviceInfo[] | null>;
6
6
  /**
7
7
  * 获取支持的约束
8
8
  */
@@ -11,10 +11,10 @@ export declare const getSupportedConsitains: () => MediaTrackSupportedConstraint
11
11
  * 选择分享流(本地视频流) / 捕获用户许可的输入信号流
12
12
  * @returns Promise
13
13
  */
14
- export declare const getMediaStream: (type?: 'user' | 'display') => (constraints?: DisplayMediaStreamConstraints | MediaStreamConstraints | undefined) => Promise<{
15
- stream: MediaStream;
16
- close: () => void;
17
- }>;
14
+ export declare const getMediaStream: (type?: 'user' | 'display') => (constraints?: MediaStreamConstraints | undefined) => Promise<{
15
+ streams: MediaStream;
16
+ close(): void;
17
+ } | null>;
18
18
  /**
19
19
  * 将多个stream 整合为一个stream
20
20
  * @param options
@@ -22,10 +22,10 @@ export declare const getMediaStream: (type?: 'user' | 'display') => (constraints
22
22
  */
23
23
  export declare const concatStream: (options: MediaStream[]) => MediaStream;
24
24
  /**
25
- * 将多个stream 按'audio' 或'video'进行过滤整合
25
+ * 将多个stream 按'audio' 或'video'进行过滤整合,当type没有输出的流类型时将不会过滤
26
26
  * @param options
27
27
  * @param type
28
28
  * @returns
29
29
  */
30
30
  export declare const filterStream: (options: MediaStream[], type?: "audio" | "video" | undefined) => MediaStream;
31
- export declare const getRemoteTracks: (peerConnection: RTCPeerConnection) => MediaStreamTrack[];
31
+ export declare const getRtcPeerTracks: (peerConnection: RTCPeerConnection, type?: "receivers" | "senders" | undefined) => (MediaStreamTrack | null)[];
@@ -1,5 +1,5 @@
1
1
  export declare const SaveFileToLocal: (blob: Blob, fileName: string) => void;
2
- export declare const createStreamToRecord: (stream: MediaStream, options?: MediaRecorderOptions) => {
2
+ export declare const streamToRecord: (stream: MediaStream, options?: MediaRecorderOptions) => {
3
3
  start: () => void;
4
4
  pause: () => void;
5
5
  save: (_fileName?: string | undefined) => void;
@@ -0,0 +1,34 @@
1
+ import { WetRTCPlayer } from './index';
2
+ import type { WetCreateConnectOneOption, ConnectionState } from './index';
3
+ import type { MutableRefObject } from 'react';
4
+ interface UseWebRtcParams {
5
+ name: string | number | MutableRefObject<string | number>;
6
+ senderSdp: (sdp: RTCSessionDescriptionInit) => void;
7
+ senderIce?: (ice: RTCIceCandidate) => void;
8
+ connectionConfig?: {
9
+ configuration?: RTCConfiguration;
10
+ constraints?: MediaStreamConstraints;
11
+ };
12
+ onError?: (err: {
13
+ code: string;
14
+ message: string;
15
+ }) => void;
16
+ }
17
+ declare const useWetRTC: (options: UseWebRtcParams) => {
18
+ connect: (transDirect?: WetCreateConnectOneOption['transDirect'], sdp?: RTCSessionDescriptionInit | undefined) => Promise<void>;
19
+ disconnect: () => void;
20
+ play: (type: 'remote' | 'local', player?: WetRTCPlayer) => void;
21
+ answerAction: (sdp: RTCSessionDescriptionInit) => void;
22
+ connectState: ConnectionState;
23
+ useAblesState: {
24
+ audioinput: boolean;
25
+ audiooutput: boolean;
26
+ videoinput: boolean;
27
+ };
28
+ useAbleRef: MutableRefObject<{
29
+ audioinput: boolean;
30
+ audiooutput: boolean;
31
+ videoinput: boolean;
32
+ }>;
33
+ };
34
+ export { useWetRTC };
@@ -5,51 +5,53 @@ export interface WetRTCConnectctItem {
5
5
  state: ConnectionState;
6
6
  uuid: string;
7
7
  name: string;
8
+ streams: MediaStream | null;
9
+ transDirect: 'recvonly' | 'sendonly' | 'sendrecv';
8
10
  }
9
- export interface WetRTCoptions {
11
+ export interface WetRTCItemType {
12
+ connect: (sdp?: RTCSessionDescriptionInit | undefined, stateChange?: ((state: ConnectionState) => void) | undefined) => Promise<RTCSessionDescriptionInit | null>;
13
+ play?: (player?: WetRTCPlayer) => void;
14
+ setRemoteSdp: (sdp: RTCSessionDescriptionInit) => void;
15
+ addIceCandidate: (sdp: RTCIceCandidate) => void;
16
+ self: WetRTCConnectctItem;
17
+ }
18
+ export interface WetCreateConnectOneOption {
10
19
  configuration?: RTCConfiguration;
11
- constraints?: MediaStreamConstraints;
12
- localPlayer?: WetRTCPlayer;
20
+ uuid?: string;
21
+ name?: string;
22
+ transDirect?: 'recvonly' | 'sendonly' | 'sendrecv';
23
+ iceCb?: (candidate: RTCIceCandidate) => void;
13
24
  }
14
25
  export declare class WetRTC {
15
- streamControl: {
16
- stream: MediaStream;
17
- close: () => void;
18
- } | null;
19
26
  rtcConnectMap: Map<string | number, WetRTCConnectctItem>;
20
- private _options;
27
+ private constraints;
28
+ private streamControl;
21
29
  private isUseAbles;
22
- constructor(configuration?: RTCConfiguration, constraints?: MediaStreamConstraints);
23
- private init;
30
+ constructor(options?: MediaStreamConstraints);
31
+ getUseAbleDevices(): Promise<MediaDeviceInfo[] | null>;
24
32
  private captureStream;
25
- /**
26
- * 创建连接
27
- */
28
- createConnectOne(option: {
29
- sdp?: RTCSessionDescriptionInit;
30
- player: WetRTCPlayer;
31
- uuid?: string;
32
- name?: string;
33
- }): {
34
- uuid: string;
35
- setRemote: (sdp: RTCSessionDescriptionInit) => void;
36
- addIceCandidate: (sdp: RTCIceCandidate) => void;
37
- next: (icecandidateCb: (candidate: RTCIceCandidate) => void, stateChange?: ((state: ConnectionState) => void) | undefined) => Promise<RTCSessionDescriptionInit>;
38
- };
39
- /**
40
- * 关闭连接
41
- */
42
- disconnect(uuid?: string): void;
33
+ closeCaptureStream(): void;
34
+ playLocalStream(player: WetRTCPlayer): void;
35
+ createConnectOne(option: Omit<WetCreateConnectOneOption, 'transDirect'> & {
36
+ transDirect: 'sendonly';
37
+ }): Omit<WetRTCItemType, 'play'>;
38
+ createConnectOne(option: Omit<WetCreateConnectOneOption, 'transDirect'> & {
39
+ transDirect?: 'recvonly' | 'sendrecv';
40
+ }): WetRTCItemType;
43
41
  /**
44
42
  * 获取特定的连接
45
43
  */
46
44
  getConnectById(uuid: string): WetRTCConnectctItem | undefined;
47
45
  /**
48
- * 设置远程sdp信息
46
+ * 关闭流的
49
47
  */
50
- setRemoteDescriptionById(uuid: string, sdp: RTCSessionDescriptionInit): Promise<unknown>;
48
+ private closeStream;
49
+ /**
50
+ * 关闭连接
51
+ */
52
+ disconnect(uuid?: string): void;
51
53
  /**
52
- * 设置远程IceCandidate信息
54
+ * 关闭所有的流
53
55
  */
54
- addIceCandidateById(uuid: string, sdp: RTCIceCandidateInit): Promise<unknown>;
56
+ close(): void;
55
57
  }
package/lib/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- import { getUseAbleDevices, getMediaStream } from './libs';
2
- import { SaveFileToLocal, createStreamToRecord } from './libs/record';
3
- import { WetRTC } from './core';
4
- export { getUseAbleDevices, getMediaStream, SaveFileToLocal, createStreamToRecord };
1
+ import { getUseAbleDevices, getMediaStream, concatStream, filterStream, getRtcPeerTracks } from './libs';
2
+ import { streamToRecord } from './libs/record';
3
+ import { WetRTC } from './core/index';
4
+ import { useWetRTC } from './core/hook';
5
+ export { getUseAbleDevices, getMediaStream, concatStream, filterStream, streamToRecord, getRtcPeerTracks, useWetRTC, };
5
6
  export default WetRTC;
package/lib/index.js CHANGED
@@ -1 +1 @@
1
- !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).index={})}(this,function(e){"use strict";function c(e,s,a,c){return new(a=a||Promise)(function(n,t){function i(e){try{r(c.next(e))}catch(e){t(e)}}function o(e){try{r(c.throw(e))}catch(e){t(e)}}function r(e){var t;e.done?n(e.value):((t=e.value)instanceof a?t:new a(function(e){e(t)})).then(i,o)}r((c=c.apply(e,s||[])).next())})}const t=()=>c(void 0,void 0,void 0,function*(){return navigator.mediaDevices.enumerateDevices?yield navigator.mediaDevices.enumerateDevices():Promise.reject({type:"CompatibilityError",message:"暂不支持-getUseAbleDevices"})}),n=(i="display")=>{const o="display"===i?"getDisplayMedia":"getUserMedia";return n=>c(void 0,void 0,void 0,function*(){if(!navigator.mediaDevices[o])return Promise.reject({type:"CompatibilityError",message:`暂不支持-${o},`});try{var e="display"===i?n:n||{video:!0,audio:{noiseSuppression:!0,echoCancellation:!0,enableBackground:!1,suppressLocalAudioPlayback:!0}};const t=yield navigator.mediaDevices[o](e);return{stream:t,close:()=>{t.getTracks().forEach(e=>{e.stop()})}}}catch(e){return"Permission denied"===e.message?Promise.reject({type:"CancelError",message:"请求已经取消"}):Promise.reject({type:"GeneralError",message:e.message||"未知错误"})}})},o=e=>e.getReceivers().map(e=>e.track),a=(e,o)=>{const t=e.getReader();let r=0;return new ReadableStream({start(i){return function n(){return t.read().then(e=>{var{done:e,value:t}=e;if(!e)return r+=(null==t?void 0:t.length)||0,console.log(r/o),i.enqueue(t),n();i.close()})}()}})},d=(e,t)=>{e=URL.createObjectURL(e);const n=document.createElement("a");n.href=e,n.target="_blank",n.style.display="none",document.body.appendChild(n),n.download=t,n.click(),URL.revokeObjectURL(e),document.body.removeChild(n)};let r;const l=new Uint8Array(16);const s=[];for(let e=0;e<256;++e)s.push((e+256).toString(16).slice(1));var u={randomUUID:"undefined"!=typeof crypto&&crypto.randomUUID&&crypto.randomUUID.bind(crypto)};function i(e,t,n){if(u.randomUUID&&!t&&!e)return u.randomUUID();const i=(e=e||{}).random||(e.rng||function(){if(!r&&!(r="undefined"!=typeof crypto&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto)))throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");return r(l)})();if(i[6]=15&i[6]|64,i[8]=63&i[8]|128,t){n=n||0;for(let e=0;e<16;++e)t[n+e]=i[e];return t}return e=i,o=0,(s[e[o+0]]+s[e[o+1]]+s[e[o+2]]+s[e[o+3]]+"-"+s[e[o+4]]+s[e[o+5]]+"-"+s[e[o+6]]+s[e[o+7]]+"-"+s[e[o+8]]+s[e[o+9]]+"-"+s[e[o+10]]+s[e[o+11]]+s[e[o+12]]+s[e[o+13]]+s[e[o+14]]+s[e[o+15]]).toLowerCase();var o}e.SaveFileToLocal=d,e.createStreamToRecord=(e,t={audioBitsPerSecond:128e3,videoBitsPerSecond:25e5,mimeType:"video/webm"})=>{const i=t.mimeType?t.mimeType.split("/"):["webm"];let o=(new Date).getTime().toString();const n=MediaRecorder.isTypeSupported(t.mimeType||"");if(!n)throw new Error(t.mimeType+"类型不支持");const r=new MediaRecorder(e,t);r.addEventListener("dataavailable",e=>{const t=e.data,n=t.size;e=URL.createObjectURL(t);fetch(e).then(e=>e.ok?e:Promise.reject("保存视频失败")).then(e=>e.body).then(e=>e?(d(t,o+"."+i[(null===i||void 0===i?void 0:i.length)-1]),a(e,n)):Promise.reject("没有可用的流"))});const s=()=>{n&&r.stop()};return{start:()=>{n&&r.start()},pause:()=>{n&&r.pause()},save:e=>{n&&(o=e||(new Date).getTime().toString(),s())},stop:s,resume:()=>{n&&r.resume()}}},e.default=class{constructor(e,t){this.streamControl=null,this.rtcConnectMap=new Map,this._options={configuration:{iceServers:[{urls:"stun:stun.l.google.com:19302"}]}},this.isUseAbles={audiooutput:!1,audioinput:!1,videoinput:!1},this.init({configuration:e,constraints:t})}init(e){this._options.constraints=null==e?void 0:e.constraints,this._options.configuration=Object.assign(Object.assign({},this._options.configuration),null==e?void 0:e.configuration),t().then(e=>{const t=e.map(e=>e.kind);this.isUseAbles.audioinput=t.includes("audioinput"),this.isUseAbles.videoinput=t.includes("videoinput"),this.isUseAbles.audiooutput=t.includes("audiooutput")}).catch(e=>{"CompatibilityError"===e.type&&(this.isUseAbles.audioinput=!0,this.isUseAbles.videoinput=!0,this.isUseAbles.audiooutput=!0)})}captureStream(){return c(this,void 0,void 0,function*(){var e=yield n("user")(this._options.constraints);this.streamControl=e})}createConnectOne(n){const o=null==n?void 0:n.sdp,r=new RTCPeerConnection(this._options.configuration),s=(null==n?void 0:n.uuid)||i(),a={RTCPeerIns:r,state:"new",name:(null==n?void 0:n.name)||s,uuid:s};return r.addEventListener("track",e=>{const t=n.player;t?(t.setAttribute("autoplay",""),t.setAttribute("playsinline",""),console.log(e.streams,t),t.srcObject=e.streams[0]):console.warn("缺少媒体播放元素video或者是audio")}),{uuid:s,setRemote:e=>{r.setRemoteDescription(e)},addIceCandidate:e=>{r.addIceCandidate(e)},next:(n,i)=>c(this,void 0,void 0,function*(){if(this.rtcConnectMap.set(s,a),r.addEventListener("icecandidate",e=>{e.candidate&&(console.log("icecandidate",e),n(e.candidate))}),r.addEventListener("connectionstatechange",e=>{e=e.target;a.state=e.connectionState,console.log(a.state),i&&i(a.state)}),this.streamControl||(yield this.captureStream()),this.streamControl){const t=((e,t)=>{let n=[];return e.forEach(e=>{n=[...n,...e.getTracks().filter(e=>t?e.kind===t:e)]}),new MediaStream(n)})([this.streamControl.stream],"video");t.getTracks().forEach(e=>{r.addTrack(e,t)})}var e;return o?(yield r.setRemoteDescription(o),e=yield r.createAnswer(),yield r.setLocalDescription(e),e):(e=yield r.createOffer(),yield r.setLocalDescription(e),e)})}}disconnect(e){var t;if(e){if(!this.rtcConnectMap.has(e))return;const n=this.getConnectById(e);if(n){const i=o(n.RTCPeerIns);i.forEach(e=>{null!=e&&e.stop()}),n.RTCPeerIns.close(),this.rtcConnectMap.delete(e)}}else this.rtcConnectMap.forEach(e=>{const t=o(e.RTCPeerIns);t.forEach(e=>{null!=e&&e.stop()}),e.RTCPeerIns.close()}),this.rtcConnectMap.clear();0===this.rtcConnectMap.size&&null!==(t=this.streamControl)&&void 0!==t&&t.close()}getConnectById(e){return this.rtcConnectMap.get(e)}setRemoteDescriptionById(t,n){return c(this,void 0,void 0,function*(){const e=this.getConnectById(t);try{yield null===e||void 0===e?void 0:e.RTCPeerIns.setRemoteDescription(n)}catch(e){return e}})}addIceCandidateById(t,n){return c(this,void 0,void 0,function*(){const e=this.getConnectById(t);try{yield null===e||void 0===e?void 0:e.RTCPeerIns.addIceCandidate(n)}catch(e){return e}})}},e.getMediaStream=n,e.getUseAbleDevices=t,Object.defineProperty(e,"__esModule",{value:!0})});
1
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("react")):"function"==typeof define&&define.amd?define(["exports","react"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).index={},e.react)}(this,function(e,v){"use strict";function m(e,o,a,c){return new(a=a||Promise)(function(n,t){function i(e){try{s(c.next(e))}catch(e){t(e)}}function r(e){try{s(c.throw(e))}catch(e){t(e)}}function s(e){var t;e.done?n(e.value):((t=e.value)instanceof a?t:new a(function(e){e(t)})).then(i,r)}s((c=c.apply(e,o||[])).next())})}const t=()=>m(void 0,void 0,void 0,function*(){return navigator.mediaDevices&&navigator.mediaDevices.enumerateDevices?yield navigator.mediaDevices.enumerateDevices():(console.error("navigator.mediaDevices.enumerateDevices"),null)}),n=(e="display")=>{const i="display"===e?"getDisplayMedia":"getUserMedia";return n=>m(void 0,void 0,void 0,function*(){if(navigator.mediaDevices[i]){var e=n||{video:!0,audio:{noiseSuppression:!0,echoCancellation:!0,enableBackground:!1,suppressLocalAudioPlayback:!0}};const t=yield navigator.mediaDevices[i](e);return{streams:t,close(){t.getTracks().forEach(e=>{e.stop()})}}}return console.error("不支持mediaDevices"),null})};const i=(e,t)=>{const n={receivers(){return e.getReceivers().map(e=>e.track)},senders(){return e.getSenders().map(e=>e.track)}};return t?n[t]():[...n.receivers(),...n.senders()]};let s;const c=new Uint8Array(16);const o=[];for(let e=0;e<256;++e)o.push((e+256).toString(16).slice(1));var a={randomUUID:"undefined"!=typeof crypto&&crypto.randomUUID&&crypto.randomUUID.bind(crypto)};function l(e,t,n){if(a.randomUUID&&!t&&!e)return a.randomUUID();const i=(e=e||{}).random||(e.rng||function(){if(!s&&!(s="undefined"!=typeof crypto&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto)))throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");return s(c)})();if(i[6]=15&i[6]|64,i[8]=63&i[8]|128,t){n=n||0;for(let e=0;e<16;++e)t[n+e]=i[e];return t}return e=i,r=0,(o[e[r+0]]+o[e[r+1]]+o[e[r+2]]+o[e[r+3]]+"-"+o[e[r+4]]+o[e[r+5]]+"-"+o[e[r+6]]+o[e[r+7]]+"-"+o[e[r+8]]+o[e[r+9]]+"-"+o[e[r+10]]+o[e[r+11]]+o[e[r+12]]+o[e[r+13]]+o[e[r+14]]+o[e[r+15]]).toLowerCase();var r}const p={iceServers:[{urls:"stun:stun.l.google.com:19302"}]};class f{constructor(e){this.rtcConnectMap=new Map,this.constraints={video:!0,audio:{noiseSuppression:!0,echoCancellation:!0,suppressLocalAudioPlayback:!0}},this.streamControl=null,this.isUseAbles={audiooutput:!1,audioinput:!1,videoinput:!1},e&&(this.constraints=e),t().then(e=>{if(e){const t=e.map(e=>e.kind);this.isUseAbles.audioinput=t.includes("audioinput"),this.isUseAbles.videoinput=t.includes("videoinput"),this.isUseAbles.audiooutput=t.includes("audiooutput")}else this.isUseAbles.audioinput=!0,this.isUseAbles.videoinput=!0,this.isUseAbles.audiooutput=!0})}getUseAbleDevices(){return m(this,void 0,void 0,function*(){return yield t()})}captureStream(){return m(this,void 0,void 0,function*(){var e;return this.isUseAbles.audioinput||this.isUseAbles.videoinput?((e=yield n("user")({video:!!this.isUseAbles.videoinput&&this.constraints.audio,audio:!!this.isUseAbles.audioinput&&this.constraints.audio}))&&(this.streamControl=e),e):null})}closeCaptureStream(){var e;null!==(e=this.streamControl)&&void 0!==e&&e.close(),this.streamControl=null}playLocalStream(e){this.streamControl&&e&&(e.setAttribute("autoPlay",""),e.setAttribute("playsInline",""),e.srcObject=this.streamControl.streams)}createConnectOne(e){let r="new";const{configuration:t,uuid:n,name:i,transDirect:d,iceCb:s}=e||{};e=t||p;const o=d||"sendrecv",a=n||l(),c=new RTCPeerConnection(e),u={RTCPeerIns:c,state:"new",name:i||a,uuid:"",streams:null,transDirect:o};return{connect:(n,i)=>m(this,void 0,void 0,function*(){var e;if(["sendrecv","sendonly"].includes(o)&&!this.streamControl&&!(yield this.captureStream()))return null;if(u.uuid=a,this.rtcConnectMap.set(a,u),c.addEventListener("track",e=>{u.streams=e.streams[0]}),Object.defineProperty(u,"state",{get(){return r},set(e){r=e,i&&i(e)}}),c.addEventListener("icecandidate",e=>{e.candidate&&s&&s(e.candidate)}),c.addEventListener("connectionstatechange",e=>{e=e.target;u.state=e.connectionState}),["sendrecv","sendonly"].includes(o)){const t=null===(e=this.streamControl)||void 0===e?void 0:e.streams;null!==t&&void 0!==t&&t.getTracks().forEach(e=>{c.addTrack(e,t)})}else c.addTransceiver("video",{direction:"recvonly"}),c.addTransceiver("audio",{direction:"recvonly"});return n?(yield c.setRemoteDescription(n),e=yield c.createAnswer(),yield c.setLocalDescription(e),e):(e=yield c.createOffer(),yield c.setLocalDescription(e),e)}),play:"sendonly"===o?void 0:e=>{let t=0;if(u.uuid)if(u.streams)null!=e&&e.setAttribute("autoplay",""),null!=e&&e.setAttribute("playsinline",""),e&&(e.srcObject=u.streams);else{const n=setInterval(()=>{t+=100,u.streams&&(null!=e&&e.setAttribute("autoplay",""),null!=e&&e.setAttribute("playsinline",""),e&&(e.srcObject=u.streams),clearInterval(n)),1e4<=t&&(clearInterval(n),console.error("流媒体轨道错误,播放失败"))},100)}},self:u,setRemoteSdp:e=>{c.setRemoteDescription(e)},addIceCandidate:e=>{c.addIceCandidate(e)}}}getConnectById(e){return this.rtcConnectMap.get(e)}closeStream(e){if(e&&e.RTCPeerIns){const t={recvonly:()=>i(e.RTCPeerIns,"receivers"),sendonly:()=>i(e.RTCPeerIns,"senders"),sendrecv:()=>i(e.RTCPeerIns)},n=t[e.transDirect]();n.forEach(e=>{null!=e&&e.stop()}),e.streams=null}}disconnect(e){if(e){if(this.rtcConnectMap.has(e)){const t=this.getConnectById(e);t.state="closed",this.closeStream(t),null!==t&&void 0!==t&&t.RTCPeerIns.close(),this.rtcConnectMap.delete(e)}}else this.rtcConnectMap.forEach(e=>{e.state="closed",this.closeStream(e),e.RTCPeerIns.close()}),this.rtcConnectMap.clear()}close(){this.disconnect(),this.closeCaptureStream()}}e.concatStream=e=>{let t=[];return e.forEach(e=>{t=[...t,...e.getTracks()]}),new MediaStream(t)},e.default=f,e.filterStream=(e,t)=>{let n=[];return e.forEach(e=>{n=[...n,...e.getTracks().filter(e=>t?e.kind===t:e)]}),new MediaStream(n)},e.getMediaStream=n,e.getRtcPeerTracks=i,e.getUseAbleDevices=t,e.streamToRecord=(e,t={audioBitsPerSecond:128e3,videoBitsPerSecond:25e5,mimeType:"video/webm"})=>{const i=t.mimeType?t.mimeType.split("/"):["webm"];let r=(new Date).getTime().toString();const n=MediaRecorder.isTypeSupported(t.mimeType||"");if(!n)throw new Error(t.mimeType+"类型不支持");const s=new MediaRecorder(e,t);s.addEventListener("dataavailable",e=>{{e=e.data;var t=r+"."+i[(null===i||void 0===i?void 0:i.length)-1];e=URL.createObjectURL(e);const n=document.createElement("a");return n.href=e,n.target="_blank",n.style.display="none",document.body.appendChild(n),n.download=t,n.click(),URL.revokeObjectURL(e),void document.body.removeChild(n)}});const o=()=>{n&&s.stop()};return{start:()=>{n&&s.start()},pause:()=>{n&&s.pause()},save:e=>{n&&(r=e||(new Date).getTime().toString(),o())},stop:o,resume:()=>{n&&s.resume()}}},e.useWetRTC=e=>{const{senderSdp:i,senderIce:r,connectionConfig:s,name:o,onError:a}=e,c=v.useRef(null),u=v.useRef(null),[t,l]=v.useState({audioinput:!1,audiooutput:!1,videoinput:!1}),d=v.useRef({audioinput:!1,audiooutput:!1,videoinput:!1}),[n,p]=v.useState("new");v.useEffect(()=>{c.current=new f(s&&(null===s||void 0===s?void 0:s.constraints)),c.current.getUseAbleDevices().then(e=>{const t={audioinput:!0,audiooutput:!0,videoinput:!0};if(e){const n=e.map(e=>e.kind);t.audioinput=n.includes("audioinput"),t.audiooutput=n.includes("audiooutput"),t.videoinput=n.includes("videoinput"),d.current=Object.assign({},t)}l(()=>t)})},[]);return{connect:v.useCallback((t="sendrecv",n)=>m(void 0,void 0,void 0,function*(){var e="object"==typeof o?o.current:o;c.current&&e&&(u.current=c.current.createConnectOne({transDirect:t,iceCb:r,configuration:s&&s.configuration}),(e=yield u.current.connect(n,e=>{p(()=>e)}))?i(e):(console.error("sdp获取失败,连接错误"),a&&a({code:"error",message:"sdp获取失败,连接错误"})))}),["object"==typeof o?o.current:o]),disconnect:()=>{var e;null!==(e=c.current)&&void 0!==e&&e.close()},play:(e,t)=>{"local"===e?null!==(e=c.current)&&void 0!==e&&e.playLocalStream(t):u.current&&u.current.play&&u.current.play(t)},answerAction:e=>{var t;null!==(t=u.current)&&void 0!==t&&t.setRemoteSdp(e)},connectState:n,useAblesState:t,useAbleRef:d}},Object.defineProperty(e,"__esModule",{value:!0})});
@@ -2,7 +2,7 @@
2
2
  * 获取可用设备
3
3
  * @returns Promise
4
4
  */
5
- export declare const getUseAbleDevices: () => Promise<MediaDeviceInfo[]>;
5
+ export declare const getUseAbleDevices: () => Promise<MediaDeviceInfo[] | null>;
6
6
  /**
7
7
  * 获取支持的约束
8
8
  */
@@ -11,10 +11,10 @@ export declare const getSupportedConsitains: () => MediaTrackSupportedConstraint
11
11
  * 选择分享流(本地视频流) / 捕获用户许可的输入信号流
12
12
  * @returns Promise
13
13
  */
14
- export declare const getMediaStream: (type?: 'user' | 'display') => (constraints?: DisplayMediaStreamConstraints | MediaStreamConstraints | undefined) => Promise<{
15
- stream: MediaStream;
16
- close: () => void;
17
- }>;
14
+ export declare const getMediaStream: (type?: 'user' | 'display') => (constraints?: MediaStreamConstraints | undefined) => Promise<{
15
+ streams: MediaStream;
16
+ close(): void;
17
+ } | null>;
18
18
  /**
19
19
  * 将多个stream 整合为一个stream
20
20
  * @param options
@@ -22,10 +22,10 @@ export declare const getMediaStream: (type?: 'user' | 'display') => (constraints
22
22
  */
23
23
  export declare const concatStream: (options: MediaStream[]) => MediaStream;
24
24
  /**
25
- * 将多个stream 按'audio' 或'video'进行过滤整合
25
+ * 将多个stream 按'audio' 或'video'进行过滤整合,当type没有输出的流类型时将不会过滤
26
26
  * @param options
27
27
  * @param type
28
28
  * @returns
29
29
  */
30
30
  export declare const filterStream: (options: MediaStream[], type?: "audio" | "video" | undefined) => MediaStream;
31
- export declare const getRemoteTracks: (peerConnection: RTCPeerConnection) => MediaStreamTrack[];
31
+ export declare const getRtcPeerTracks: (peerConnection: RTCPeerConnection, type?: "receivers" | "senders" | undefined) => (MediaStreamTrack | null)[];
@@ -1,5 +1,5 @@
1
1
  export declare const SaveFileToLocal: (blob: Blob, fileName: string) => void;
2
- export declare const createStreamToRecord: (stream: MediaStream, options?: MediaRecorderOptions) => {
2
+ export declare const streamToRecord: (stream: MediaStream, options?: MediaRecorderOptions) => {
3
3
  start: () => void;
4
4
  pause: () => void;
5
5
  save: (_fileName?: string | undefined) => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wetspace/wetrtc",
3
- "version": "2.0.1",
3
+ "version": "2.0.2",
4
4
  "description": "wetrtc",
5
5
  "author": "tangjie <981955667@qq.com>",
6
6
  "license": "ISC",