yjz-web-sdk 1.0.2 → 1.0.3-beta.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.
@@ -198,6 +198,7 @@ var MessageType = /* @__PURE__ */ ((MessageType2) => {
198
198
  MessageType2["NotAvailable"] = "NotAvailable";
199
199
  MessageType2["Ping"] = "Ping";
200
200
  MessageType2["Pong"] = "Pong";
201
+ MessageType2["SendScreenshot"] = "SendScreenshot";
201
202
  return MessageType2;
202
203
  })(MessageType || {});
203
204
  var SendType = /* @__PURE__ */ ((SendType2) => {
@@ -208,6 +209,7 @@ var SendType = /* @__PURE__ */ ((SendType2) => {
208
209
  SendType2["IceCandidates"] = "IceCandidates";
209
210
  SendType2["Pong"] = "Pong";
210
211
  SendType2["Identity"] = "Web";
212
+ SendType2["RequestScreenshot"] = "RequestScreenshot";
211
213
  return SendType2;
212
214
  })(SendType || {});
213
215
  var FailCode = /* @__PURE__ */ ((FailCode2) => {
@@ -304,6 +306,8 @@ var EmitType = /* @__PURE__ */ ((EmitType2) => {
304
306
  EmitType2["iceConnectionState"] = "iceConnectionState";
305
307
  EmitType2["cloudStatusChanged"] = "cloudStatusChanged";
306
308
  EmitType2["statisticInfo"] = "statisticInfo";
309
+ EmitType2["cloudClipData"] = "cloudClipData";
310
+ EmitType2["screenshot"] = "screenshot";
307
311
  return EmitType2;
308
312
  })(EmitType || {});
309
313
  class SignalingClient extends EventEmitter {
@@ -323,7 +327,6 @@ class SignalingClient extends EventEmitter {
323
327
  start() {
324
328
  this.webSocket = new WebSocket(this.config.signalServerUrl);
325
329
  this.webSocket.onopen = () => {
326
- console.log("sendSignInMessagesendSignInMessagesendSignInMessage");
327
330
  this.sendSignInMessage();
328
331
  if (this.timeout === null) {
329
332
  this.timeout = setTimeout(() => {
@@ -379,6 +382,23 @@ class SignalingClient extends EventEmitter {
379
382
  type: SendType.SignIn,
380
383
  identity: SendType.Identity,
381
384
  turnServerUri: this.config.turnServerUri,
385
+ roomId: this.config.roomId,
386
+ isControl: this.config.isControl ? "true" : "false",
387
+ screenshotWidth: this.config.screenshotWidth,
388
+ screenshotHeight: this.config.screenshotHeight,
389
+ screenshotQuality: this.config.screenshotQuality
390
+ };
391
+ const jsonMessage = JSON.stringify(message);
392
+ this.sendMessage(jsonMessage);
393
+ }
394
+ /**
395
+ * 用于从控请求当前截屏
396
+ * @param visible 当前从控page控件是否可见
397
+ */
398
+ sendRequestScreenshot(visible) {
399
+ const message = {
400
+ type: SendType.RequestScreenshot,
401
+ visible,
382
402
  roomId: this.config.roomId
383
403
  };
384
404
  const jsonMessage = JSON.stringify(message);
@@ -2982,6 +3002,10 @@ class WebRTCConfig {
2982
3002
  __publicField(this, "turnServerUri");
2983
3003
  __publicField(this, "turnServerUserName");
2984
3004
  __publicField(this, "turnServerPassword");
3005
+ __publicField(this, "isControl");
3006
+ __publicField(this, "screenshotWidth");
3007
+ __publicField(this, "screenshotHeight");
3008
+ __publicField(this, "screenshotQuality");
2985
3009
  this.signalServerUrl = options.signalServerUrl || "";
2986
3010
  this.myId = options.myId || "";
2987
3011
  this.roomId = options.roomId || "";
@@ -2992,23 +3016,783 @@ class WebRTCConfig {
2992
3016
  this.turnServerUri = options.turnServerUri || "turn:btweb.yajuzhen.com:3478";
2993
3017
  this.turnServerUserName = options.turnServerUserName || "yangyj";
2994
3018
  this.turnServerPassword = options.turnServerPassword || "hb@2025@168";
3019
+ this.isControl = options.isControl ?? true;
3020
+ this.screenshotWidth = options.screenshotWidth || 144;
3021
+ this.screenshotHeight = options.screenshotHeight || 256;
3022
+ this.screenshotQuality = options.screenshotQuality || 20;
2995
3023
  }
2996
3024
  }
3025
+ var lib = {};
3026
+ var parser = {};
3027
+ var grammar = { exports: {} };
3028
+ var hasRequiredGrammar;
3029
+ function requireGrammar() {
3030
+ if (hasRequiredGrammar) return grammar.exports;
3031
+ hasRequiredGrammar = 1;
3032
+ var grammar$1 = grammar.exports = {
3033
+ v: [{
3034
+ name: "version",
3035
+ reg: /^(\d*)$/
3036
+ }],
3037
+ o: [{
3038
+ // o=- 20518 0 IN IP4 203.0.113.1
3039
+ // NB: sessionId will be a String in most cases because it is huge
3040
+ name: "origin",
3041
+ reg: /^(\S*) (\d*) (\d*) (\S*) IP(\d) (\S*)/,
3042
+ names: ["username", "sessionId", "sessionVersion", "netType", "ipVer", "address"],
3043
+ format: "%s %s %d %s IP%d %s"
3044
+ }],
3045
+ // default parsing of these only (though some of these feel outdated)
3046
+ s: [{ name: "name" }],
3047
+ i: [{ name: "description" }],
3048
+ u: [{ name: "uri" }],
3049
+ e: [{ name: "email" }],
3050
+ p: [{ name: "phone" }],
3051
+ z: [{ name: "timezones" }],
3052
+ // TODO: this one can actually be parsed properly...
3053
+ r: [{ name: "repeats" }],
3054
+ // TODO: this one can also be parsed properly
3055
+ // k: [{}], // outdated thing ignored
3056
+ t: [{
3057
+ // t=0 0
3058
+ name: "timing",
3059
+ reg: /^(\d*) (\d*)/,
3060
+ names: ["start", "stop"],
3061
+ format: "%d %d"
3062
+ }],
3063
+ c: [{
3064
+ // c=IN IP4 10.47.197.26
3065
+ name: "connection",
3066
+ reg: /^IN IP(\d) (\S*)/,
3067
+ names: ["version", "ip"],
3068
+ format: "IN IP%d %s"
3069
+ }],
3070
+ b: [{
3071
+ // b=AS:4000
3072
+ push: "bandwidth",
3073
+ reg: /^(TIAS|AS|CT|RR|RS):(\d*)/,
3074
+ names: ["type", "limit"],
3075
+ format: "%s:%s"
3076
+ }],
3077
+ m: [{
3078
+ // m=video 51744 RTP/AVP 126 97 98 34 31
3079
+ // NB: special - pushes to session
3080
+ // TODO: rtp/fmtp should be filtered by the payloads found here?
3081
+ reg: /^(\w*) (\d*) ([\w/]*)(?: (.*))?/,
3082
+ names: ["type", "port", "protocol", "payloads"],
3083
+ format: "%s %d %s %s"
3084
+ }],
3085
+ a: [
3086
+ {
3087
+ // a=rtpmap:110 opus/48000/2
3088
+ push: "rtp",
3089
+ reg: /^rtpmap:(\d*) ([\w\-.]*)(?:\s*\/(\d*)(?:\s*\/(\S*))?)?/,
3090
+ names: ["payload", "codec", "rate", "encoding"],
3091
+ format: function(o) {
3092
+ return o.encoding ? "rtpmap:%d %s/%s/%s" : o.rate ? "rtpmap:%d %s/%s" : "rtpmap:%d %s";
3093
+ }
3094
+ },
3095
+ {
3096
+ // a=fmtp:108 profile-level-id=24;object=23;bitrate=64000
3097
+ // a=fmtp:111 minptime=10; useinbandfec=1
3098
+ push: "fmtp",
3099
+ reg: /^fmtp:(\d*) ([\S| ]*)/,
3100
+ names: ["payload", "config"],
3101
+ format: "fmtp:%d %s"
3102
+ },
3103
+ {
3104
+ // a=control:streamid=0
3105
+ name: "control",
3106
+ reg: /^control:(.*)/,
3107
+ format: "control:%s"
3108
+ },
3109
+ {
3110
+ // a=rtcp:65179 IN IP4 193.84.77.194
3111
+ name: "rtcp",
3112
+ reg: /^rtcp:(\d*)(?: (\S*) IP(\d) (\S*))?/,
3113
+ names: ["port", "netType", "ipVer", "address"],
3114
+ format: function(o) {
3115
+ return o.address != null ? "rtcp:%d %s IP%d %s" : "rtcp:%d";
3116
+ }
3117
+ },
3118
+ {
3119
+ // a=rtcp-fb:98 trr-int 100
3120
+ push: "rtcpFbTrrInt",
3121
+ reg: /^rtcp-fb:(\*|\d*) trr-int (\d*)/,
3122
+ names: ["payload", "value"],
3123
+ format: "rtcp-fb:%s trr-int %d"
3124
+ },
3125
+ {
3126
+ // a=rtcp-fb:98 nack rpsi
3127
+ push: "rtcpFb",
3128
+ reg: /^rtcp-fb:(\*|\d*) ([\w-_]*)(?: ([\w-_]*))?/,
3129
+ names: ["payload", "type", "subtype"],
3130
+ format: function(o) {
3131
+ return o.subtype != null ? "rtcp-fb:%s %s %s" : "rtcp-fb:%s %s";
3132
+ }
3133
+ },
3134
+ {
3135
+ // a=extmap:2 urn:ietf:params:rtp-hdrext:toffset
3136
+ // a=extmap:1/recvonly URI-gps-string
3137
+ // a=extmap:3 urn:ietf:params:rtp-hdrext:encrypt urn:ietf:params:rtp-hdrext:smpte-tc 25@600/24
3138
+ push: "ext",
3139
+ reg: /^extmap:(\d+)(?:\/(\w+))?(?: (urn:ietf:params:rtp-hdrext:encrypt))? (\S*)(?: (\S*))?/,
3140
+ names: ["value", "direction", "encrypt-uri", "uri", "config"],
3141
+ format: function(o) {
3142
+ return "extmap:%d" + (o.direction ? "/%s" : "%v") + (o["encrypt-uri"] ? " %s" : "%v") + " %s" + (o.config ? " %s" : "");
3143
+ }
3144
+ },
3145
+ {
3146
+ // a=extmap-allow-mixed
3147
+ name: "extmapAllowMixed",
3148
+ reg: /^(extmap-allow-mixed)/
3149
+ },
3150
+ {
3151
+ // a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:PS1uQCVeeCFCanVmcjkpPywjNWhcYD0mXXtxaVBR|2^20|1:32
3152
+ push: "crypto",
3153
+ reg: /^crypto:(\d*) ([\w_]*) (\S*)(?: (\S*))?/,
3154
+ names: ["id", "suite", "config", "sessionConfig"],
3155
+ format: function(o) {
3156
+ return o.sessionConfig != null ? "crypto:%d %s %s %s" : "crypto:%d %s %s";
3157
+ }
3158
+ },
3159
+ {
3160
+ // a=setup:actpass
3161
+ name: "setup",
3162
+ reg: /^setup:(\w*)/,
3163
+ format: "setup:%s"
3164
+ },
3165
+ {
3166
+ // a=connection:new
3167
+ name: "connectionType",
3168
+ reg: /^connection:(new|existing)/,
3169
+ format: "connection:%s"
3170
+ },
3171
+ {
3172
+ // a=mid:1
3173
+ name: "mid",
3174
+ reg: /^mid:([^\s]*)/,
3175
+ format: "mid:%s"
3176
+ },
3177
+ {
3178
+ // a=msid:0c8b064d-d807-43b4-b434-f92a889d8587 98178685-d409-46e0-8e16-7ef0db0db64a
3179
+ name: "msid",
3180
+ reg: /^msid:(.*)/,
3181
+ format: "msid:%s"
3182
+ },
3183
+ {
3184
+ // a=ptime:20
3185
+ name: "ptime",
3186
+ reg: /^ptime:(\d*(?:\.\d*)*)/,
3187
+ format: "ptime:%d"
3188
+ },
3189
+ {
3190
+ // a=maxptime:60
3191
+ name: "maxptime",
3192
+ reg: /^maxptime:(\d*(?:\.\d*)*)/,
3193
+ format: "maxptime:%d"
3194
+ },
3195
+ {
3196
+ // a=sendrecv
3197
+ name: "direction",
3198
+ reg: /^(sendrecv|recvonly|sendonly|inactive)/
3199
+ },
3200
+ {
3201
+ // a=ice-lite
3202
+ name: "icelite",
3203
+ reg: /^(ice-lite)/
3204
+ },
3205
+ {
3206
+ // a=ice-ufrag:F7gI
3207
+ name: "iceUfrag",
3208
+ reg: /^ice-ufrag:(\S*)/,
3209
+ format: "ice-ufrag:%s"
3210
+ },
3211
+ {
3212
+ // a=ice-pwd:x9cml/YzichV2+XlhiMu8g
3213
+ name: "icePwd",
3214
+ reg: /^ice-pwd:(\S*)/,
3215
+ format: "ice-pwd:%s"
3216
+ },
3217
+ {
3218
+ // a=fingerprint:SHA-1 00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33
3219
+ name: "fingerprint",
3220
+ reg: /^fingerprint:(\S*) (\S*)/,
3221
+ names: ["type", "hash"],
3222
+ format: "fingerprint:%s %s"
3223
+ },
3224
+ {
3225
+ // a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host
3226
+ // a=candidate:1162875081 1 udp 2113937151 192.168.34.75 60017 typ host generation 0 network-id 3 network-cost 10
3227
+ // a=candidate:3289912957 2 udp 1845501695 193.84.77.194 60017 typ srflx raddr 192.168.34.75 rport 60017 generation 0 network-id 3 network-cost 10
3228
+ // a=candidate:229815620 1 tcp 1518280447 192.168.150.19 60017 typ host tcptype active generation 0 network-id 3 network-cost 10
3229
+ // a=candidate:3289912957 2 tcp 1845501695 193.84.77.194 60017 typ srflx raddr 192.168.34.75 rport 60017 tcptype passive generation 0 network-id 3 network-cost 10
3230
+ push: "candidates",
3231
+ reg: /^candidate:(\S*) (\d*) (\S*) (\d*) (\S*) (\d*) typ (\S*)(?: raddr (\S*) rport (\d*))?(?: tcptype (\S*))?(?: generation (\d*))?(?: network-id (\d*))?(?: network-cost (\d*))?/,
3232
+ names: ["foundation", "component", "transport", "priority", "ip", "port", "type", "raddr", "rport", "tcptype", "generation", "network-id", "network-cost"],
3233
+ format: function(o) {
3234
+ var str = "candidate:%s %d %s %d %s %d typ %s";
3235
+ str += o.raddr != null ? " raddr %s rport %d" : "%v%v";
3236
+ str += o.tcptype != null ? " tcptype %s" : "%v";
3237
+ if (o.generation != null) {
3238
+ str += " generation %d";
3239
+ }
3240
+ str += o["network-id"] != null ? " network-id %d" : "%v";
3241
+ str += o["network-cost"] != null ? " network-cost %d" : "%v";
3242
+ return str;
3243
+ }
3244
+ },
3245
+ {
3246
+ // a=end-of-candidates (keep after the candidates line for readability)
3247
+ name: "endOfCandidates",
3248
+ reg: /^(end-of-candidates)/
3249
+ },
3250
+ {
3251
+ // a=remote-candidates:1 203.0.113.1 54400 2 203.0.113.1 54401 ...
3252
+ name: "remoteCandidates",
3253
+ reg: /^remote-candidates:(.*)/,
3254
+ format: "remote-candidates:%s"
3255
+ },
3256
+ {
3257
+ // a=ice-options:google-ice
3258
+ name: "iceOptions",
3259
+ reg: /^ice-options:(\S*)/,
3260
+ format: "ice-options:%s"
3261
+ },
3262
+ {
3263
+ // a=ssrc:2566107569 cname:t9YU8M1UxTF8Y1A1
3264
+ push: "ssrcs",
3265
+ reg: /^ssrc:(\d*) ([\w_-]*)(?::(.*))?/,
3266
+ names: ["id", "attribute", "value"],
3267
+ format: function(o) {
3268
+ var str = "ssrc:%d";
3269
+ if (o.attribute != null) {
3270
+ str += " %s";
3271
+ if (o.value != null) {
3272
+ str += ":%s";
3273
+ }
3274
+ }
3275
+ return str;
3276
+ }
3277
+ },
3278
+ {
3279
+ // a=ssrc-group:FEC 1 2
3280
+ // a=ssrc-group:FEC-FR 3004364195 1080772241
3281
+ push: "ssrcGroups",
3282
+ // token-char = %x21 / %x23-27 / %x2A-2B / %x2D-2E / %x30-39 / %x41-5A / %x5E-7E
3283
+ reg: /^ssrc-group:([\x21\x23\x24\x25\x26\x27\x2A\x2B\x2D\x2E\w]*) (.*)/,
3284
+ names: ["semantics", "ssrcs"],
3285
+ format: "ssrc-group:%s %s"
3286
+ },
3287
+ {
3288
+ // a=msid-semantic: WMS Jvlam5X3SX1OP6pn20zWogvaKJz5Hjf9OnlV
3289
+ name: "msidSemantic",
3290
+ reg: /^msid-semantic:\s?(\w*) (\S*)/,
3291
+ names: ["semantic", "token"],
3292
+ format: "msid-semantic: %s %s"
3293
+ // space after ':' is not accidental
3294
+ },
3295
+ {
3296
+ // a=group:BUNDLE audio video
3297
+ push: "groups",
3298
+ reg: /^group:(\w*) (.*)/,
3299
+ names: ["type", "mids"],
3300
+ format: "group:%s %s"
3301
+ },
3302
+ {
3303
+ // a=rtcp-mux
3304
+ name: "rtcpMux",
3305
+ reg: /^(rtcp-mux)/
3306
+ },
3307
+ {
3308
+ // a=rtcp-rsize
3309
+ name: "rtcpRsize",
3310
+ reg: /^(rtcp-rsize)/
3311
+ },
3312
+ {
3313
+ // a=sctpmap:5000 webrtc-datachannel 1024
3314
+ name: "sctpmap",
3315
+ reg: /^sctpmap:([\w_/]*) (\S*)(?: (\S*))?/,
3316
+ names: ["sctpmapNumber", "app", "maxMessageSize"],
3317
+ format: function(o) {
3318
+ return o.maxMessageSize != null ? "sctpmap:%s %s %s" : "sctpmap:%s %s";
3319
+ }
3320
+ },
3321
+ {
3322
+ // a=x-google-flag:conference
3323
+ name: "xGoogleFlag",
3324
+ reg: /^x-google-flag:([^\s]*)/,
3325
+ format: "x-google-flag:%s"
3326
+ },
3327
+ {
3328
+ // a=rid:1 send max-width=1280;max-height=720;max-fps=30;depend=0
3329
+ push: "rids",
3330
+ reg: /^rid:([\d\w]+) (\w+)(?: ([\S| ]*))?/,
3331
+ names: ["id", "direction", "params"],
3332
+ format: function(o) {
3333
+ return o.params ? "rid:%s %s %s" : "rid:%s %s";
3334
+ }
3335
+ },
3336
+ {
3337
+ // a=imageattr:97 send [x=800,y=640,sar=1.1,q=0.6] [x=480,y=320] recv [x=330,y=250]
3338
+ // a=imageattr:* send [x=800,y=640] recv *
3339
+ // a=imageattr:100 recv [x=320,y=240]
3340
+ push: "imageattrs",
3341
+ reg: new RegExp(
3342
+ // a=imageattr:97
3343
+ "^imageattr:(\\d+|\\*)[\\s\\t]+(send|recv)[\\s\\t]+(\\*|\\[\\S+\\](?:[\\s\\t]+\\[\\S+\\])*)(?:[\\s\\t]+(recv|send)[\\s\\t]+(\\*|\\[\\S+\\](?:[\\s\\t]+\\[\\S+\\])*))?"
3344
+ ),
3345
+ names: ["pt", "dir1", "attrs1", "dir2", "attrs2"],
3346
+ format: function(o) {
3347
+ return "imageattr:%s %s %s" + (o.dir2 ? " %s %s" : "");
3348
+ }
3349
+ },
3350
+ {
3351
+ // a=simulcast:send 1,2,3;~4,~5 recv 6;~7,~8
3352
+ // a=simulcast:recv 1;4,5 send 6;7
3353
+ name: "simulcast",
3354
+ reg: new RegExp(
3355
+ // a=simulcast:
3356
+ "^simulcast:(send|recv) ([a-zA-Z0-9\\-_~;,]+)(?:\\s?(send|recv) ([a-zA-Z0-9\\-_~;,]+))?$"
3357
+ ),
3358
+ names: ["dir1", "list1", "dir2", "list2"],
3359
+ format: function(o) {
3360
+ return "simulcast:%s %s" + (o.dir2 ? " %s %s" : "");
3361
+ }
3362
+ },
3363
+ {
3364
+ // old simulcast draft 03 (implemented by Firefox)
3365
+ // https://tools.ietf.org/html/draft-ietf-mmusic-sdp-simulcast-03
3366
+ // a=simulcast: recv pt=97;98 send pt=97
3367
+ // a=simulcast: send rid=5;6;7 paused=6,7
3368
+ name: "simulcast_03",
3369
+ reg: /^simulcast:[\s\t]+([\S+\s\t]+)$/,
3370
+ names: ["value"],
3371
+ format: "simulcast: %s"
3372
+ },
3373
+ {
3374
+ // a=framerate:25
3375
+ // a=framerate:29.97
3376
+ name: "framerate",
3377
+ reg: /^framerate:(\d+(?:$|\.\d+))/,
3378
+ format: "framerate:%s"
3379
+ },
3380
+ {
3381
+ // RFC4570
3382
+ // a=source-filter: incl IN IP4 239.5.2.31 10.1.15.5
3383
+ name: "sourceFilter",
3384
+ reg: /^source-filter: *(excl|incl) (\S*) (IP4|IP6|\*) (\S*) (.*)/,
3385
+ names: ["filterMode", "netType", "addressTypes", "destAddress", "srcList"],
3386
+ format: "source-filter: %s %s %s %s %s"
3387
+ },
3388
+ {
3389
+ // a=bundle-only
3390
+ name: "bundleOnly",
3391
+ reg: /^(bundle-only)/
3392
+ },
3393
+ {
3394
+ // a=label:1
3395
+ name: "label",
3396
+ reg: /^label:(.+)/,
3397
+ format: "label:%s"
3398
+ },
3399
+ {
3400
+ // RFC version 26 for SCTP over DTLS
3401
+ // https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-26#section-5
3402
+ name: "sctpPort",
3403
+ reg: /^sctp-port:(\d+)$/,
3404
+ format: "sctp-port:%s"
3405
+ },
3406
+ {
3407
+ // RFC version 26 for SCTP over DTLS
3408
+ // https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-26#section-6
3409
+ name: "maxMessageSize",
3410
+ reg: /^max-message-size:(\d+)$/,
3411
+ format: "max-message-size:%s"
3412
+ },
3413
+ {
3414
+ // RFC7273
3415
+ // a=ts-refclk:ptp=IEEE1588-2008:39-A7-94-FF-FE-07-CB-D0:37
3416
+ push: "tsRefClocks",
3417
+ reg: /^ts-refclk:([^\s=]*)(?:=(\S*))?/,
3418
+ names: ["clksrc", "clksrcExt"],
3419
+ format: function(o) {
3420
+ return "ts-refclk:%s" + (o.clksrcExt != null ? "=%s" : "");
3421
+ }
3422
+ },
3423
+ {
3424
+ // RFC7273
3425
+ // a=mediaclk:direct=963214424
3426
+ name: "mediaClk",
3427
+ reg: /^mediaclk:(?:id=(\S*))? *([^\s=]*)(?:=(\S*))?(?: *rate=(\d+)\/(\d+))?/,
3428
+ names: ["id", "mediaClockName", "mediaClockValue", "rateNumerator", "rateDenominator"],
3429
+ format: function(o) {
3430
+ var str = "mediaclk:";
3431
+ str += o.id != null ? "id=%s %s" : "%v%s";
3432
+ str += o.mediaClockValue != null ? "=%s" : "";
3433
+ str += o.rateNumerator != null ? " rate=%s" : "";
3434
+ str += o.rateDenominator != null ? "/%s" : "";
3435
+ return str;
3436
+ }
3437
+ },
3438
+ {
3439
+ // a=keywds:keywords
3440
+ name: "keywords",
3441
+ reg: /^keywds:(.+)$/,
3442
+ format: "keywds:%s"
3443
+ },
3444
+ {
3445
+ // a=content:main
3446
+ name: "content",
3447
+ reg: /^content:(.+)/,
3448
+ format: "content:%s"
3449
+ },
3450
+ // BFCP https://tools.ietf.org/html/rfc4583
3451
+ {
3452
+ // a=floorctrl:c-s
3453
+ name: "bfcpFloorCtrl",
3454
+ reg: /^floorctrl:(c-only|s-only|c-s)/,
3455
+ format: "floorctrl:%s"
3456
+ },
3457
+ {
3458
+ // a=confid:1
3459
+ name: "bfcpConfId",
3460
+ reg: /^confid:(\d+)/,
3461
+ format: "confid:%s"
3462
+ },
3463
+ {
3464
+ // a=userid:1
3465
+ name: "bfcpUserId",
3466
+ reg: /^userid:(\d+)/,
3467
+ format: "userid:%s"
3468
+ },
3469
+ {
3470
+ // a=floorid:1
3471
+ name: "bfcpFloorId",
3472
+ reg: /^floorid:(.+) (?:m-stream|mstrm):(.+)/,
3473
+ names: ["id", "mStream"],
3474
+ format: "floorid:%s mstrm:%s"
3475
+ },
3476
+ {
3477
+ // any a= that we don't understand is kept verbatim on media.invalid
3478
+ push: "invalid",
3479
+ names: ["value"]
3480
+ }
3481
+ ]
3482
+ };
3483
+ Object.keys(grammar$1).forEach(function(key) {
3484
+ var objs = grammar$1[key];
3485
+ objs.forEach(function(obj) {
3486
+ if (!obj.reg) {
3487
+ obj.reg = /(.*)/;
3488
+ }
3489
+ if (!obj.format) {
3490
+ obj.format = "%s";
3491
+ }
3492
+ });
3493
+ });
3494
+ return grammar.exports;
3495
+ }
3496
+ var hasRequiredParser;
3497
+ function requireParser() {
3498
+ if (hasRequiredParser) return parser;
3499
+ hasRequiredParser = 1;
3500
+ (function(exports) {
3501
+ var toIntIfInt = function(v) {
3502
+ return String(Number(v)) === v ? Number(v) : v;
3503
+ };
3504
+ var attachProperties = function(match, location, names, rawName) {
3505
+ if (rawName && !names) {
3506
+ location[rawName] = toIntIfInt(match[1]);
3507
+ } else {
3508
+ for (var i = 0; i < names.length; i += 1) {
3509
+ if (match[i + 1] != null) {
3510
+ location[names[i]] = toIntIfInt(match[i + 1]);
3511
+ }
3512
+ }
3513
+ }
3514
+ };
3515
+ var parseReg = function(obj, location, content) {
3516
+ var needsBlank = obj.name && obj.names;
3517
+ if (obj.push && !location[obj.push]) {
3518
+ location[obj.push] = [];
3519
+ } else if (needsBlank && !location[obj.name]) {
3520
+ location[obj.name] = {};
3521
+ }
3522
+ var keyLocation = obj.push ? {} : (
3523
+ // blank object that will be pushed
3524
+ needsBlank ? location[obj.name] : location
3525
+ );
3526
+ attachProperties(content.match(obj.reg), keyLocation, obj.names, obj.name);
3527
+ if (obj.push) {
3528
+ location[obj.push].push(keyLocation);
3529
+ }
3530
+ };
3531
+ var grammar2 = requireGrammar();
3532
+ var validLine = RegExp.prototype.test.bind(/^([a-z])=(.*)/);
3533
+ exports.parse = function(sdp2) {
3534
+ var session = {}, media = [], location = session;
3535
+ sdp2.split(/(\r\n|\r|\n)/).filter(validLine).forEach(function(l) {
3536
+ var type = l[0];
3537
+ var content = l.slice(2);
3538
+ if (type === "m") {
3539
+ media.push({ rtp: [], fmtp: [] });
3540
+ location = media[media.length - 1];
3541
+ }
3542
+ for (var j = 0; j < (grammar2[type] || []).length; j += 1) {
3543
+ var obj = grammar2[type][j];
3544
+ if (obj.reg.test(content)) {
3545
+ return parseReg(obj, location, content);
3546
+ }
3547
+ }
3548
+ });
3549
+ session.media = media;
3550
+ return session;
3551
+ };
3552
+ var paramReducer = function(acc, expr) {
3553
+ var s = expr.split(/=(.+)/, 2);
3554
+ if (s.length === 2) {
3555
+ acc[s[0]] = toIntIfInt(s[1]);
3556
+ } else if (s.length === 1 && expr.length > 1) {
3557
+ acc[s[0]] = void 0;
3558
+ }
3559
+ return acc;
3560
+ };
3561
+ exports.parseParams = function(str) {
3562
+ return str.split(/;\s?/).reduce(paramReducer, {});
3563
+ };
3564
+ exports.parseFmtpConfig = exports.parseParams;
3565
+ exports.parsePayloads = function(str) {
3566
+ return str.toString().split(" ").map(Number);
3567
+ };
3568
+ exports.parseRemoteCandidates = function(str) {
3569
+ var candidates = [];
3570
+ var parts = str.split(" ").map(toIntIfInt);
3571
+ for (var i = 0; i < parts.length; i += 3) {
3572
+ candidates.push({
3573
+ component: parts[i],
3574
+ ip: parts[i + 1],
3575
+ port: parts[i + 2]
3576
+ });
3577
+ }
3578
+ return candidates;
3579
+ };
3580
+ exports.parseImageAttributes = function(str) {
3581
+ return str.split(" ").map(function(item) {
3582
+ return item.substring(1, item.length - 1).split(",").reduce(paramReducer, {});
3583
+ });
3584
+ };
3585
+ exports.parseSimulcastStreamList = function(str) {
3586
+ return str.split(";").map(function(stream) {
3587
+ return stream.split(",").map(function(format) {
3588
+ var scid, paused = false;
3589
+ if (format[0] !== "~") {
3590
+ scid = toIntIfInt(format);
3591
+ } else {
3592
+ scid = toIntIfInt(format.substring(1, format.length));
3593
+ paused = true;
3594
+ }
3595
+ return {
3596
+ scid,
3597
+ paused
3598
+ };
3599
+ });
3600
+ });
3601
+ };
3602
+ })(parser);
3603
+ return parser;
3604
+ }
3605
+ var writer;
3606
+ var hasRequiredWriter;
3607
+ function requireWriter() {
3608
+ if (hasRequiredWriter) return writer;
3609
+ hasRequiredWriter = 1;
3610
+ var grammar2 = requireGrammar();
3611
+ var formatRegExp = /%[sdv%]/g;
3612
+ var format = function(formatStr) {
3613
+ var i = 1;
3614
+ var args = arguments;
3615
+ var len = args.length;
3616
+ return formatStr.replace(formatRegExp, function(x) {
3617
+ if (i >= len) {
3618
+ return x;
3619
+ }
3620
+ var arg = args[i];
3621
+ i += 1;
3622
+ switch (x) {
3623
+ case "%%":
3624
+ return "%";
3625
+ case "%s":
3626
+ return String(arg);
3627
+ case "%d":
3628
+ return Number(arg);
3629
+ case "%v":
3630
+ return "";
3631
+ }
3632
+ });
3633
+ };
3634
+ var makeLine = function(type, obj, location) {
3635
+ var str = obj.format instanceof Function ? obj.format(obj.push ? location : location[obj.name]) : obj.format;
3636
+ var args = [type + "=" + str];
3637
+ if (obj.names) {
3638
+ for (var i = 0; i < obj.names.length; i += 1) {
3639
+ var n = obj.names[i];
3640
+ if (obj.name) {
3641
+ args.push(location[obj.name][n]);
3642
+ } else {
3643
+ args.push(location[obj.names[i]]);
3644
+ }
3645
+ }
3646
+ } else {
3647
+ args.push(location[obj.name]);
3648
+ }
3649
+ return format.apply(null, args);
3650
+ };
3651
+ var defaultOuterOrder = [
3652
+ "v",
3653
+ "o",
3654
+ "s",
3655
+ "i",
3656
+ "u",
3657
+ "e",
3658
+ "p",
3659
+ "c",
3660
+ "b",
3661
+ "t",
3662
+ "r",
3663
+ "z",
3664
+ "a"
3665
+ ];
3666
+ var defaultInnerOrder = ["i", "c", "b", "a"];
3667
+ writer = function(session, opts) {
3668
+ opts = opts || {};
3669
+ if (session.version == null) {
3670
+ session.version = 0;
3671
+ }
3672
+ if (session.name == null) {
3673
+ session.name = " ";
3674
+ }
3675
+ session.media.forEach(function(mLine) {
3676
+ if (mLine.payloads == null) {
3677
+ mLine.payloads = "";
3678
+ }
3679
+ });
3680
+ var outerOrder = opts.outerOrder || defaultOuterOrder;
3681
+ var innerOrder = opts.innerOrder || defaultInnerOrder;
3682
+ var sdp2 = [];
3683
+ outerOrder.forEach(function(type) {
3684
+ grammar2[type].forEach(function(obj) {
3685
+ if (obj.name in session && session[obj.name] != null) {
3686
+ sdp2.push(makeLine(type, obj, session));
3687
+ } else if (obj.push in session && session[obj.push] != null) {
3688
+ session[obj.push].forEach(function(el) {
3689
+ sdp2.push(makeLine(type, obj, el));
3690
+ });
3691
+ }
3692
+ });
3693
+ });
3694
+ session.media.forEach(function(mLine) {
3695
+ sdp2.push(makeLine("m", grammar2.m[0], mLine));
3696
+ innerOrder.forEach(function(type) {
3697
+ grammar2[type].forEach(function(obj) {
3698
+ if (obj.name in mLine && mLine[obj.name] != null) {
3699
+ sdp2.push(makeLine(type, obj, mLine));
3700
+ } else if (obj.push in mLine && mLine[obj.push] != null) {
3701
+ mLine[obj.push].forEach(function(el) {
3702
+ sdp2.push(makeLine(type, obj, el));
3703
+ });
3704
+ }
3705
+ });
3706
+ });
3707
+ });
3708
+ return sdp2.join("\r\n") + "\r\n";
3709
+ };
3710
+ return writer;
3711
+ }
3712
+ var hasRequiredLib;
3713
+ function requireLib() {
3714
+ if (hasRequiredLib) return lib;
3715
+ hasRequiredLib = 1;
3716
+ var parser2 = requireParser();
3717
+ var writer2 = requireWriter();
3718
+ var grammar2 = requireGrammar();
3719
+ lib.grammar = grammar2;
3720
+ lib.write = writer2;
3721
+ lib.parse = parser2.parse;
3722
+ lib.parseParams = parser2.parseParams;
3723
+ lib.parseFmtpConfig = parser2.parseFmtpConfig;
3724
+ lib.parsePayloads = parser2.parsePayloads;
3725
+ lib.parseRemoteCandidates = parser2.parseRemoteCandidates;
3726
+ lib.parseImageAttributes = parser2.parseImageAttributes;
3727
+ lib.parseSimulcastStreamList = parser2.parseSimulcastStreamList;
3728
+ return lib;
3729
+ }
3730
+ var libExports = requireLib();
3731
+ const sdpTransform = /* @__PURE__ */ getDefaultExportFromCjs(libExports);
2997
3732
  const setRemoteDescriptionWithHandleOffer = (peerConnection, sdp2, sendAnswer, onError) => {
2998
3733
  const description = new RTCSessionDescription({ type: "offer", sdp: sdp2 });
2999
3734
  peerConnection.setRemoteDescription(description).then(() => createAnswer(peerConnection, sendAnswer, onError)).catch((error) => onError == null ? void 0 : onError(createWebRtcError(FailCode.HANDLE_OFFER, error)));
3000
3735
  };
3001
3736
  const createAnswer = (peerConnection, sendAnswer, onError) => {
3002
- peerConnection.createAnswer().then((answer) => setLocalDescriptionWithCreateAnswer(peerConnection, answer, sendAnswer, onError)).catch((error) => onError == null ? void 0 : onError(createWebRtcError(FailCode.CREATE_ANSWER, error)));
3737
+ peerConnection.createAnswer().then((answer) => {
3738
+ const modifiedSdp = modifySdp(answer.sdp ?? "");
3739
+ setLocalDescriptionWithCreateAnswer(peerConnection, modifiedSdp, sendAnswer, onError);
3740
+ }).catch((error) => onError == null ? void 0 : onError(createWebRtcError(FailCode.CREATE_ANSWER, error)));
3003
3741
  };
3004
- const setLocalDescriptionWithCreateAnswer = (peerConnection, answer, sendAnswer, onError) => {
3742
+ const setLocalDescriptionWithCreateAnswer = (peerConnection, sdp2, sendAnswer, onError) => {
3743
+ const answer = new RTCSessionDescription({ type: "answer", sdp: sdp2 });
3005
3744
  peerConnection.setLocalDescription(answer).then(() => {
3006
- sendAnswer == null ? void 0 : sendAnswer(answer.sdp ?? "");
3745
+ sendAnswer == null ? void 0 : sendAnswer(sdp2 ?? "");
3007
3746
  }).catch((error) => {
3008
3747
  onError == null ? void 0 : onError(createWebRtcError(FailCode.LOCAL_DES, error));
3009
- console.log("21321322212213");
3010
3748
  });
3011
3749
  };
3750
+ const modifySdp = (sdp2) => {
3751
+ let parsedSdp = sdpTransform.parse(sdp2);
3752
+ parsedSdp.media.forEach((media) => {
3753
+ var _a, _b;
3754
+ if (media.type === "video") {
3755
+ const allowedCodec = "H264";
3756
+ const h264Payloads = media.rtp.filter((rtp) => rtp.codec.toUpperCase() === allowedCodec).map((rtp) => rtp.payload);
3757
+ media.rtp = media.rtp.filter((rtp) => h264Payloads.includes(rtp.payload));
3758
+ media.fmtp = ((_a = media.fmtp) == null ? void 0 : _a.filter((fmtp) => h264Payloads.includes(fmtp.payload))) || [];
3759
+ media.rtcpFb = ((_b = media.rtcpFb) == null ? void 0 : _b.filter((fb) => h264Payloads.includes(fb.payload))) || [];
3760
+ media.payloads = h264Payloads.join(" ");
3761
+ const targetBitrate = 800;
3762
+ if (media.fmtp.length > 0) {
3763
+ media.fmtp.forEach((fmtp) => {
3764
+ if (!fmtp.config.includes("x-google-start-bitrate")) {
3765
+ fmtp.config += `;x-google-start-bitrate=${targetBitrate}`;
3766
+ }
3767
+ if (!fmtp.config.includes("x-google-max-bitrate")) {
3768
+ fmtp.config += `;x-google-max-bitrate=${targetBitrate}`;
3769
+ }
3770
+ if (!fmtp.config.includes("x-google-min-bitrate")) {
3771
+ fmtp.config += `;x-google-min-bitrate=${targetBitrate}`;
3772
+ }
3773
+ });
3774
+ }
3775
+ }
3776
+ if (!media.rtcpFb) media.rtcpFb = [];
3777
+ const payloads = (media.payloads || "").split(" ").map(Number).filter((n) => !isNaN(n));
3778
+ payloads.forEach((pt) => {
3779
+ if (!media.rtcpFb.some((fb) => fb.payload === pt && fb.type === "nack")) {
3780
+ media.rtcpFb.push({ payload: pt, type: "nack" });
3781
+ }
3782
+ if (!media.rtcpFb.some((fb) => fb.payload === pt && fb.type === "nack" && fb.subtype === "pli")) {
3783
+ media.rtcpFb.push({ payload: pt, type: "nack", subtype: "pli" });
3784
+ }
3785
+ });
3786
+ if (media.fmtp) {
3787
+ media.fmtp.forEach((fmtp) => {
3788
+ if (!fmtp.config.includes("useinbandfec=1")) {
3789
+ fmtp.config += ";useinbandfec=1";
3790
+ }
3791
+ });
3792
+ }
3793
+ });
3794
+ return sdpTransform.write(parsedSdp);
3795
+ };
3012
3796
  const createPeerConnection = (config) => {
3013
3797
  const iceServers = [
3014
3798
  { urls: config.stunServerUri },
@@ -3023,8 +3807,7 @@ const createPeerConnection = (config) => {
3023
3807
  iceServers,
3024
3808
  iceTransportPolicy: "all",
3025
3809
  bundlePolicy: "max-bundle",
3026
- rtcpMuxPolicy: "require",
3027
- iceCandidatePoolSize: 10
3810
+ rtcpMuxPolicy: "require"
3028
3811
  };
3029
3812
  return new RTCPeerConnection(peerConnectionConfig);
3030
3813
  };
@@ -3045,14 +3828,14 @@ const configPeerConnection = (peerConnection, onICEMessage, onTrack, onConnectSt
3045
3828
  if (!state) {
3046
3829
  return;
3047
3830
  }
3048
- if (state === "failed") {
3831
+ if (state === "failed" || state === "disconnected") {
3049
3832
  onError == null ? void 0 : onError(createWebRtcError(FailCode.ICE_STATE, "failed"));
3050
3833
  }
3051
3834
  onConnectState == null ? void 0 : onConnectState(state);
3052
3835
  };
3053
3836
  peerConnection.ontrack = (event) => {
3054
3837
  const track = event.track;
3055
- track.contentHint = "detail";
3838
+ track.contentHint = "motion";
3056
3839
  onTrack == null ? void 0 : onTrack(track);
3057
3840
  };
3058
3841
  };
@@ -3078,8 +3861,20 @@ var ChannelDataType = /* @__PURE__ */ ((ChannelDataType2) => {
3078
3861
  ChannelDataType2["ActionRequestCloudDeviceInfo"] = "ActionRequestCloudDeviceInfo";
3079
3862
  ChannelDataType2["ActionClarity"] = "ActionClarity";
3080
3863
  ChannelDataType2["ActionWheel"] = "ActionWheel";
3864
+ ChannelDataType2["CloudClipData"] = "CloudClipData";
3865
+ ChannelDataType2["ActionCommandEvent"] = "ActionCommandEvent";
3866
+ ChannelDataType2["ActionUpdateCloudStatus"] = "ActionUpdateCloudStatus";
3867
+ ChannelDataType2["ActionGesture"] = "ActionGesture";
3081
3868
  return ChannelDataType2;
3082
3869
  })(ChannelDataType || {});
3870
+ var ActionCommandType = /* @__PURE__ */ ((ActionCommandType2) => {
3871
+ ActionCommandType2["ActionBack"] = "ActionBack";
3872
+ ActionCommandType2["ActionHome"] = "ActionHome";
3873
+ ActionCommandType2["ActionRecent"] = "ActionRecent";
3874
+ ActionCommandType2["ActionSwitchNavButtons"] = "ActionSwitchNavButtons";
3875
+ ActionCommandType2["ActionSwitchNavGestural"] = "ActionSwitchNavGestural";
3876
+ return ActionCommandType2;
3877
+ })(ActionCommandType || {});
3083
3878
  const ActionType = {
3084
3879
  ACTION_DOWN: 0,
3085
3880
  ACTION_MOVE: 2,
@@ -3129,6 +3924,12 @@ class KeyEventData {
3129
3924
  this.meta = meta;
3130
3925
  }
3131
3926
  }
3927
+ class GestureData {
3928
+ constructor(mode) {
3929
+ __publicField(this, "mode");
3930
+ this.mode = mode;
3931
+ }
3932
+ }
3132
3933
  class ChannelData {
3133
3934
  constructor(type, data = null) {
3134
3935
  __publicField(this, "type");
@@ -3155,6 +3956,9 @@ class ChannelData {
3155
3956
  static click(touchData) {
3156
3957
  return new ChannelData("ClickData", this.formatData(touchData));
3157
3958
  }
3959
+ static action(actionData) {
3960
+ return new ChannelData("ActionCommand", this.formatData(actionData));
3961
+ }
3158
3962
  /**
3159
3963
  * 生成剪贴板数据
3160
3964
  * @param data 剪贴板数据,可以是字符串或其他类型
@@ -3176,6 +3980,13 @@ class ChannelData {
3176
3980
  static wheel(data) {
3177
3981
  return new ChannelData("ActionWheel", this.formatData(data));
3178
3982
  }
3983
+ /**
3984
+ * 切换手势模式数据
3985
+ * @param data 输入数据对象
3986
+ */
3987
+ static gesture(data) {
3988
+ return new ChannelData("ActionGesture", this.formatData(data));
3989
+ }
3179
3990
  /**
3180
3991
  * 生成中文输入数据
3181
3992
  * @param data 中文输入数据
@@ -3262,6 +4073,12 @@ class WebRTCClient extends EventEmitter {
3262
4073
  case ChannelDataType.ActionWheel:
3263
4074
  channelData = ChannelData.wheel(data);
3264
4075
  break;
4076
+ case ChannelDataType.ActionGesture:
4077
+ channelData = ChannelData.gesture(data);
4078
+ break;
4079
+ case ChannelDataType.ActionCommand:
4080
+ channelData = ChannelData.action(data);
4081
+ break;
3265
4082
  }
3266
4083
  if (channelData) {
3267
4084
  const jsonString = JSON.stringify(channelData);
@@ -3409,20 +4226,23 @@ class WebRTCClient extends EventEmitter {
3409
4226
  }
3410
4227
  handleDataChannelMessage(event) {
3411
4228
  const data = JSON.parse(event.data);
3412
- if (data.type === "ActionCommandEvent") {
4229
+ if (data.type === ChannelDataType.ActionCommandEvent) {
3413
4230
  const { action, value } = JSON.parse(data.data);
3414
4231
  if (action === "ACTION_CONTROL_VIDEO") {
3415
4232
  value === "ENABLE" ? this.startPush() : this.stopPush();
3416
4233
  }
3417
- } else if (data.type === "ActionUpdateCloudStatus") {
3418
- const { rotation, screenWidth, screenHeight } = JSON.parse(data.data);
4234
+ } else if (data.type === ChannelDataType.ActionUpdateCloudStatus) {
4235
+ const { rotation, screenWidth, screenHeight, gestureMode } = JSON.parse(data.data);
3419
4236
  const direction = [StreamRotation.ROTATION_0, StreamRotation.ROTATION_180].includes(rotation) ? ContainerDirection.Vertical : ContainerDirection.Horizontal;
3420
4237
  const cloudStatus = {
3421
4238
  direction,
3422
4239
  screenWidth,
3423
- screenHeight
4240
+ screenHeight,
4241
+ gestureMode
3424
4242
  };
3425
4243
  this.emit(EmitType.cloudStatusChanged, cloudStatus);
4244
+ } else if (data.type === ChannelDataType.CloudClipData) {
4245
+ this.emit(EmitType.cloudClipData, data.data);
3426
4246
  }
3427
4247
  }
3428
4248
  checkStats() {
@@ -3441,6 +4261,7 @@ class WebRTCClient extends EventEmitter {
3441
4261
  let bytesReceived = 0;
3442
4262
  let framesDecoded = 0;
3443
4263
  let pliCount = 0;
4264
+ let framesReceived = 0;
3444
4265
  let connectionType = "";
3445
4266
  const currentTime = Date.now();
3446
4267
  statsReport.forEach((report) => {
@@ -3452,6 +4273,7 @@ class WebRTCClient extends EventEmitter {
3452
4273
  videoFps = report.framesPerSecond || 0;
3453
4274
  totalDecodeTime = report.totalDecodeTime || 0;
3454
4275
  framesDecoded = report.framesDecoded || 0;
4276
+ framesReceived = report.framesReceived || 0;
3455
4277
  pliCount = (report.pliCount || 0) + (report.firCount || 0);
3456
4278
  }
3457
4279
  }
@@ -3494,7 +4316,9 @@ class WebRTCClient extends EventEmitter {
3494
4316
  // percent
3495
4317
  bitrate,
3496
4318
  pliCount,
3497
- averageDecodeTime
4319
+ averageDecodeTime,
4320
+ framesDecoded,
4321
+ framesReceived
3498
4322
  };
3499
4323
  this.emit(EmitType.statisticInfo, screenInfo);
3500
4324
  }).catch((error) => {
@@ -3523,9 +4347,9 @@ class WebRTCSdk extends EventEmitter {
3523
4347
  this.config.myId = message.myId;
3524
4348
  break;
3525
4349
  case MessageType.Offer:
3526
- console.log("handleSignaling===>", message);
3527
4350
  if (message.senderId && message.sdp) {
3528
4351
  this.config.targetId = message.senderId;
4352
+ console.log("MessageType.Offer===>", message.senderId);
3529
4353
  this.webRTCClient.handleOffer(message.sdp);
3530
4354
  }
3531
4355
  break;
@@ -3558,6 +4382,10 @@ class WebRTCSdk extends EventEmitter {
3558
4382
  case MessageType.Ping:
3559
4383
  this.sendPong();
3560
4384
  break;
4385
+ case MessageType.SendScreenshot:
4386
+ const base64Str = `data:image/png;base64,${message.screenshot}`;
4387
+ this.emit(EmitType.screenshot, { "room_id": this.config.roomId, "base64": base64Str });
4388
+ break;
3561
4389
  }
3562
4390
  });
3563
4391
  /** 发送 Offer 信令 */
@@ -3621,6 +4449,10 @@ class WebRTCSdk extends EventEmitter {
3621
4449
  EmitType.cloudStatusChanged,
3622
4450
  (info) => this.emit(EmitType.cloudStatusChanged, info)
3623
4451
  );
4452
+ this.webRTCClient.on(
4453
+ EmitType.cloudClipData,
4454
+ (clipData) => this.emit(EmitType.cloudClipData, clipData)
4455
+ );
3624
4456
  this.webRTCClient.on(EmitType.webrtcError, (err) => {
3625
4457
  this.emit(EmitType.webrtcError, err);
3626
4458
  });
@@ -3640,16 +4472,14 @@ class WebRTCSdk extends EventEmitter {
3640
4472
  }
3641
4473
  /** 开始推流:触发媒体采集与轨道添加 */
3642
4474
  async startPush() {
3643
- try {
3644
- await this.webRTCClient.readyCapture();
3645
- } catch (error) {
3646
- this.emit("error", { type: "camera", error });
3647
- }
3648
4475
  }
3649
4476
  /** 发送信道数据 */
3650
4477
  sendChannelData(type, data) {
3651
4478
  this.webRTCClient.sendChannelData(type, data);
3652
4479
  }
4480
+ sendRequestScreenshot(visible) {
4481
+ this.signalingClient.sendRequestScreenshot(visible);
4482
+ }
3653
4483
  sendPong() {
3654
4484
  const message = {
3655
4485
  type: SendType.Pong
@@ -3794,10 +4624,10 @@ const KeyCodeMap = {
3794
4624
  };
3795
4625
  const getKeyEventData = (event) => {
3796
4626
  const keyCode = KeyCodeMap[event.code] ?? -1;
3797
- const metaState = computeAndroidMetaState(event);
4627
+ const meta = computeAndroidMetaState(event);
3798
4628
  return {
3799
- androidKeyCode: keyCode,
3800
- metaState
4629
+ keyCode,
4630
+ meta
3801
4631
  };
3802
4632
  };
3803
4633
  function transformCoordinate(viewWidth, viewHeight, cloudWidth, cloudHeight, viewAngle, streamAngle, inputX, inputY) {
@@ -3870,6 +4700,85 @@ function rotatePoint90(width, height, inputX, inputY) {
3870
4700
  const yRotated = -x0 + offsetShortSide;
3871
4701
  return [xRotated, yRotated];
3872
4702
  }
4703
+ class GroupControllerManager extends EventEmitter {
4704
+ constructor() {
4705
+ super(...arguments);
4706
+ __publicField(this, "webRTCConfigList", []);
4707
+ __publicField(this, "sdkList", []);
4708
+ __publicField(this, "loopTimer", null);
4709
+ __publicField(this, "visibilityMap", /* @__PURE__ */ new Map());
4710
+ __publicField(this, "previousVisibilityMap", /* @__PURE__ */ new Map());
4711
+ }
4712
+ startGroupControl(configList) {
4713
+ if (!Array.isArray(configList) || configList.length === 0) {
4714
+ throw new Error("群控列表为空");
4715
+ }
4716
+ const controlCount = configList.filter((config) => config.isControl).length;
4717
+ if (controlCount !== 1) {
4718
+ throw new Error(`一次群控发起,有且只有一个主控,当前主控个数为 ${controlCount}。`);
4719
+ }
4720
+ this.webRTCConfigList = configList;
4721
+ configList.forEach((config) => {
4722
+ const sdk = new WebRTCSdk(config);
4723
+ sdk.startConnection();
4724
+ sdk.on(EmitType.screenshot, (screenshot) => {
4725
+ this.emit(EmitType.screenshot, screenshot);
4726
+ });
4727
+ this.sdkList.push(sdk);
4728
+ });
4729
+ this.startLoop();
4730
+ }
4731
+ stopGroupControl() {
4732
+ this.sdkList.forEach((sdk) => sdk.stop());
4733
+ this.sdkList = [];
4734
+ this.visibilityMap.clear();
4735
+ this.previousVisibilityMap.clear();
4736
+ this.removeAllListeners();
4737
+ this.stopLoop();
4738
+ }
4739
+ getConnectionList() {
4740
+ return this.webRTCConfigList;
4741
+ }
4742
+ /**
4743
+ * 设置某个视图的可见状态
4744
+ * @param viewId 视图 ID
4745
+ * @param visible 是否可见
4746
+ */
4747
+ setViewVisibility(viewId, visible) {
4748
+ this.visibilityMap.set(viewId, visible);
4749
+ }
4750
+ sendChannelData(type, data) {
4751
+ this.sdkList.forEach((sdk) => {
4752
+ sdk.sendChannelData(type, data);
4753
+ });
4754
+ }
4755
+ startLoop() {
4756
+ if (this.loopTimer !== null) return;
4757
+ this.loopTimer = setInterval(() => {
4758
+ try {
4759
+ this.sdkList.forEach((sdk) => {
4760
+ const viewId = sdk.config.roomId;
4761
+ const isVisibleNow = this.visibilityMap.get(viewId) ?? false;
4762
+ const wasVisible = this.previousVisibilityMap.get(viewId) ?? false;
4763
+ if (isVisibleNow) {
4764
+ sdk.sendRequestScreenshot(true);
4765
+ } else if (wasVisible && !isVisibleNow) {
4766
+ sdk.sendRequestScreenshot(false);
4767
+ }
4768
+ this.previousVisibilityMap.set(viewId, isVisibleNow);
4769
+ });
4770
+ } catch (err) {
4771
+ console.error("Error during loop execution:", err);
4772
+ }
4773
+ }, 1e3);
4774
+ }
4775
+ stopLoop() {
4776
+ if (this.loopTimer !== null) {
4777
+ clearInterval(this.loopTimer);
4778
+ this.loopTimer = null;
4779
+ }
4780
+ }
4781
+ }
3873
4782
  function useDeviceMode() {
3874
4783
  const isMobile = ref(false);
3875
4784
  const checkDeviceMode = () => {
@@ -3926,6 +4835,7 @@ function useRemoteVideo(videoContainer, remoteVideoElement, videoAngle) {
3926
4835
  const widthRadio = ref(0);
3927
4836
  const heightRadio = ref(0);
3928
4837
  const resizeObserver = ref(null);
4838
+ const id = ref(0);
3929
4839
  const videoSize = computed(() => {
3930
4840
  let width = 0;
3931
4841
  let height = 0;
@@ -3944,6 +4854,16 @@ function useRemoteVideo(videoContainer, remoteVideoElement, videoAngle) {
3944
4854
  }
3945
4855
  widthRadio.value = remoteVideo.value.width / width;
3946
4856
  heightRadio.value = remoteVideo.value.height / height;
4857
+ } else {
4858
+ const aspect = 720 / 1280;
4859
+ const videoHeight = containerWidth / aspect;
4860
+ if (videoHeight > containerHeight) {
4861
+ height = containerHeight;
4862
+ width = height * aspect;
4863
+ } else {
4864
+ width = containerWidth;
4865
+ height = videoHeight;
4866
+ }
3947
4867
  }
3948
4868
  return { width, height };
3949
4869
  });
@@ -3966,8 +4886,18 @@ function useRemoteVideo(videoContainer, remoteVideoElement, videoAngle) {
3966
4886
  };
3967
4887
  screenStatus.value = true;
3968
4888
  });
4889
+ remoteVideoElement.value.addEventListener("loadedmetadata", () => {
4890
+ scheduleFrame();
4891
+ });
3969
4892
  }
3970
4893
  };
4894
+ const scheduleFrame = () => {
4895
+ if (!remoteVideoElement.value) return;
4896
+ id.value = remoteVideoElement.value.requestVideoFrameCallback((now, metadata) => {
4897
+ console.log("DOMHighResTimeStamp==>", now, "Frame at", metadata.presentationTime.toFixed(2), "ms");
4898
+ scheduleFrame();
4899
+ });
4900
+ };
3971
4901
  const startPlay = (track) => {
3972
4902
  if (!remoteVideoElement.value) return;
3973
4903
  if (!remoteVideoElement.value.srcObject) {
@@ -3982,6 +4912,7 @@ function useRemoteVideo(videoContainer, remoteVideoElement, videoAngle) {
3982
4912
  if (remoteVideoElement.value && remoteVideoElement.value.srcObject) {
3983
4913
  remoteVideoElement.value.srcObject.getTracks().forEach((track) => track.stop());
3984
4914
  remoteVideoElement.value.srcObject = null;
4915
+ remoteVideoElement.value.cancelVideoFrameCallback(id.value);
3985
4916
  }
3986
4917
  };
3987
4918
  return {
@@ -4014,7 +4945,7 @@ function useMouseTouchControl(options) {
4014
4945
  const endY = ref(0);
4015
4946
  const handlePointerEvent = (event, action) => {
4016
4947
  if (!remoteVideoElement.value) return;
4017
- const offsetTime = Math.trunc((event.timeStamp - pointerDownTime.value[0]) / 2);
4948
+ const offsetTime = Math.trunc(event.timeStamp - pointerDownTime.value[0]);
4018
4949
  const rect = remoteVideoElement.value.getBoundingClientRect();
4019
4950
  let x = event.clientX - rect.left;
4020
4951
  let y = event.clientY - rect.top;
@@ -4153,19 +5084,27 @@ function useMouseTouchControl(options) {
4153
5084
  handleWheel
4154
5085
  };
4155
5086
  }
4156
- function useKeyboardControl(emit) {
5087
+ function useKeyboardControl(disabled, emit) {
5088
+ const listening = ref(false);
4157
5089
  const handleKeyDown = (e) => {
4158
5090
  const data = getKeyEventData(e);
4159
5091
  emit("channelEvent", ChannelDataType.ActionInput, data);
4160
5092
  };
4161
- const startListening = (e) => {
4162
- const target = e.target;
4163
- target.focus();
5093
+ const startListening = () => {
5094
+ if (!disabled) {
5095
+ return;
5096
+ }
5097
+ listening.value = true;
5098
+ document.addEventListener("keydown", handleKeyDown);
4164
5099
  };
4165
5100
  const stopListening = () => {
5101
+ if (!disabled) {
5102
+ return;
5103
+ }
5104
+ listening.value = false;
5105
+ document.removeEventListener("keydown", handleKeyDown);
4166
5106
  };
4167
5107
  return {
4168
- handleKeyDown,
4169
5108
  startListening,
4170
5109
  stopListening
4171
5110
  };
@@ -4173,10 +5112,10 @@ function useKeyboardControl(emit) {
4173
5112
  const _sfc_main = /* @__PURE__ */ defineComponent({
4174
5113
  __name: "index",
4175
5114
  props: {
4176
- streamAngle: { type: Number, default: 0 },
4177
- videoAngle: { type: Number, default: 0 },
4178
- cursorType: { type: Number, default: 0 },
4179
- cloudDeviceSize: { type: Object, default: () => ({ width: 0, height: 0 }) },
5115
+ streamAngle: { default: 0 },
5116
+ videoAngle: { default: 0 },
5117
+ cursorType: { default: 0 },
5118
+ cloudDeviceSize: { default: () => ({ width: 0, height: 0 }) },
4180
5119
  disabled: { type: Boolean, default: true }
4181
5120
  },
4182
5121
  emits: ["channelEvent"],
@@ -4221,22 +5160,29 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
4221
5160
  emit
4222
5161
  });
4223
5162
  const {
4224
- handleKeyDown,
4225
5163
  startListening,
4226
5164
  stopListening
4227
- } = useKeyboardControl(emit);
5165
+ } = useKeyboardControl(disabled, emit);
4228
5166
  useResizeObserver(videoContainer, dimensions);
5167
+ const handleClick = () => {
5168
+ var _a;
5169
+ if ((_a = remoteVideoElement.value) == null ? void 0 : _a.srcObject) {
5170
+ remoteVideoElement.value.muted = false;
5171
+ }
5172
+ };
4229
5173
  onMounted(() => {
4230
5174
  checkDeviceMode();
4231
5175
  window.addEventListener("resize", checkDeviceMode);
4232
5176
  window.addEventListener("pointerdown", checkTouchSupport);
4233
5177
  window.addEventListener("pointerup", handleUp);
5178
+ document.addEventListener("click", handleClick);
4234
5179
  initVideoContainer();
4235
5180
  });
4236
5181
  onUnmounted(() => {
4237
5182
  window.removeEventListener("resize", checkDeviceMode);
4238
5183
  window.removeEventListener("pointerdown", checkTouchSupport);
4239
5184
  window.removeEventListener("pointerup", handleUp);
5185
+ document.removeEventListener("click", handleClick);
4240
5186
  });
4241
5187
  __expose({ startPlay, stopPlay });
4242
5188
  return (_ctx, _cache) => {
@@ -4244,16 +5190,16 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
4244
5190
  ref_key: "videoContainer",
4245
5191
  ref: videoContainer,
4246
5192
  class: "flex flex-1 items-center justify-center",
4247
- style: { "width": "100%", "height": "100%", "background": "black", "position": "relative", "overflow": "hidden" }
5193
+ style: { "width": "100%", "height": "100%", "position": "relative", "overflow": "hidden" }
4248
5194
  }, [
4249
5195
  createElementVNode("div", {
4250
5196
  ref: "keyboardArea",
4251
- onPointerenter: _cache[9] || (_cache[9] = ($event) => unref(disabled) ? null : unref(startListening)),
4252
- onPointerleave: _cache[10] || (_cache[10] = ($event) => unref(disabled) ? null : unref(stopListening)),
4253
- tabindex: "0",
4254
- class: "vContainer",
4255
- onKeydown: _cache[11] || (_cache[11] = ($event) => unref(disabled) ? null : unref(handleKeyDown)),
4256
- style: normalizeStyle([{ height: unref(videoSize).height + "px", width: unref(videoSize).width + "px", transform: `rotate(${unref(videoAngle)}deg)` }, { "position": "relative" }])
5197
+ onPointerenter: _cache[9] || (_cache[9] = //@ts-ignore
5198
+ (...args) => unref(startListening) && unref(startListening)(...args)),
5199
+ onPointerleave: _cache[10] || (_cache[10] = //@ts-ignore
5200
+ (...args) => unref(stopListening) && unref(stopListening)(...args)),
5201
+ class: "vContainer flex justify-center items-center",
5202
+ style: normalizeStyle([{ height: unref(videoSize).height + "px", width: unref(videoSize).width + "px", transform: `rotate(${unref(videoAngle)}deg)` }, { "position": "relative", "border": "none", "overflow": "hidden" }])
4257
5203
  }, [
4258
5204
  createElementVNode("video", {
4259
5205
  ref_key: "remoteVideoElement",
@@ -4280,7 +5226,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
4280
5226
  autoplay: "",
4281
5227
  playsinline: "",
4282
5228
  muted: "",
4283
- disablePictureInPicture: ""
5229
+ disablePictureInPicture: true
4284
5230
  }, null, 34)
4285
5231
  ], 36)
4286
5232
  ], 512);
@@ -4294,12 +5240,15 @@ const _export_sfc = (sfc, props) => {
4294
5240
  }
4295
5241
  return target;
4296
5242
  };
4297
- const index = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-27488d0e"]]);
5243
+ const index = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-f0ecea8b"]]);
4298
5244
  export {
5245
+ ActionCommandType,
4299
5246
  ActionType,
4300
5247
  ChannelDataType,
4301
5248
  ContainerDirection,
4302
5249
  EmitType,
5250
+ GestureData,
5251
+ GroupControllerManager,
4303
5252
  InputData,
4304
5253
  KeyEventData,
4305
5254
  index as RemotePlayer,