werift 0.18.3 → 0.18.4

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.
Files changed (97) hide show
  1. package/lib/dtls/src/flight/server/flight2.js +1 -1
  2. package/lib/dtls/src/flight/server/flight2.js.map +1 -1
  3. package/lib/rtp/src/container/ebml/ebml.d.ts +5 -6
  4. package/lib/rtp/src/container/ebml/ebml.js +14 -13
  5. package/lib/rtp/src/container/ebml/ebml.js.map +1 -1
  6. package/lib/rtp/src/container/ebml/typedArrayUtils.d.ts +3 -4
  7. package/lib/rtp/src/container/ebml/typedArrayUtils.js +9 -10
  8. package/lib/rtp/src/container/ebml/typedArrayUtils.js.map +1 -1
  9. package/lib/rtp/src/container/index.d.ts +2 -0
  10. package/lib/rtp/src/{processor/source → container}/index.js +2 -3
  11. package/lib/rtp/src/container/index.js.map +1 -0
  12. package/lib/rtp/src/helper.d.ts +4 -0
  13. package/lib/rtp/src/helper.js +14 -1
  14. package/lib/rtp/src/helper.js.map +1 -1
  15. package/lib/rtp/src/index.d.ts +2 -0
  16. package/lib/rtp/src/index.js +2 -0
  17. package/lib/rtp/src/index.js.map +1 -1
  18. package/lib/rtp/src/processor/depacketizer.d.ts +1 -1
  19. package/lib/rtp/src/processor/depacketizer.js +16 -9
  20. package/lib/rtp/src/processor/depacketizer.js.map +1 -1
  21. package/lib/rtp/src/processor/depacketizerCallback.d.ts +14 -6
  22. package/lib/rtp/src/processor/depacketizerCallback.js +2 -35
  23. package/lib/rtp/src/processor/depacketizerCallback.js.map +1 -1
  24. package/lib/rtp/src/processor/dtx.d.ts +1 -0
  25. package/lib/rtp/src/processor/dtx.js +10 -1
  26. package/lib/rtp/src/processor/dtx.js.map +1 -1
  27. package/lib/rtp/src/processor/dtxCallback.d.ts +14 -5
  28. package/lib/rtp/src/processor/dtxCallback.js +2 -35
  29. package/lib/rtp/src/processor/dtxCallback.js.map +1 -1
  30. package/lib/rtp/src/processor/index.d.ts +3 -1
  31. package/lib/rtp/src/processor/index.js +3 -1
  32. package/lib/rtp/src/processor/index.js.map +1 -1
  33. package/lib/rtp/src/processor/interface.d.ts +17 -0
  34. package/lib/rtp/src/processor/interface.js +57 -0
  35. package/lib/rtp/src/processor/interface.js.map +1 -1
  36. package/lib/rtp/src/processor/jitterBuffer.d.ts +1 -2
  37. package/lib/rtp/src/processor/jitterBuffer.js +3 -1
  38. package/lib/rtp/src/processor/jitterBuffer.js.map +1 -1
  39. package/lib/rtp/src/processor/jitterBufferCallback.d.ts +14 -5
  40. package/lib/rtp/src/processor/jitterBufferCallback.js +2 -35
  41. package/lib/rtp/src/processor/jitterBufferCallback.js.map +1 -1
  42. package/lib/rtp/src/processor/jitterBufferTransformer.d.ts +1 -1
  43. package/lib/rtp/src/processor/lipsync.d.ts +19 -8
  44. package/lib/rtp/src/processor/lipsync.js +131 -83
  45. package/lib/rtp/src/processor/lipsync.js.map +1 -1
  46. package/lib/rtp/src/processor/lipsyncCallback.d.ts +8 -5
  47. package/lib/rtp/src/processor/lipsyncCallback.js +39 -4
  48. package/lib/rtp/src/processor/lipsyncCallback.js.map +1 -1
  49. package/lib/rtp/src/processor/mute.d.ts +17 -4
  50. package/lib/rtp/src/processor/mute.js +121 -40
  51. package/lib/rtp/src/processor/mute.js.map +1 -1
  52. package/lib/rtp/src/processor/muteCallback.d.ts +5 -2
  53. package/lib/rtp/src/processor/muteCallback.js +23 -7
  54. package/lib/rtp/src/processor/muteCallback.js.map +1 -1
  55. package/lib/rtp/src/processor/nack.d.ts +6 -6
  56. package/lib/rtp/src/processor/nack.js +23 -17
  57. package/lib/rtp/src/processor/nack.js.map +1 -1
  58. package/lib/rtp/src/processor/nackHandlerCallback.d.ts +14 -7
  59. package/lib/rtp/src/processor/nackHandlerCallback.js +2 -29
  60. package/lib/rtp/src/processor/nackHandlerCallback.js.map +1 -1
  61. package/lib/rtp/src/processor/ntpTime.d.ts +7 -7
  62. package/lib/rtp/src/processor/ntpTime.js +27 -29
  63. package/lib/rtp/src/processor/ntpTime.js.map +1 -1
  64. package/lib/rtp/src/processor/ntpTimeCallback.d.ts +13 -4
  65. package/lib/rtp/src/processor/ntpTimeCallback.js +2 -29
  66. package/lib/rtp/src/processor/ntpTimeCallback.js.map +1 -1
  67. package/lib/rtp/src/processor/rtcpCallback.d.ts +18 -0
  68. package/lib/rtp/src/processor/{source/rtcpCallback.js → rtcpCallback.js} +25 -3
  69. package/lib/rtp/src/processor/rtcpCallback.js.map +1 -0
  70. package/lib/rtp/src/processor/rtpCallback.d.ts +28 -0
  71. package/lib/rtp/src/processor/rtpCallback.js +125 -0
  72. package/lib/rtp/src/processor/rtpCallback.js.map +1 -0
  73. package/lib/rtp/src/processor/{source/rtpStream.d.ts → rtpStream.d.ts} +1 -1
  74. package/lib/rtp/src/processor/{source/rtpStream.js → rtpStream.js} +1 -1
  75. package/lib/rtp/src/processor/rtpStream.js.map +1 -0
  76. package/lib/rtp/src/processor/rtpTimeCallback.d.ts +13 -5
  77. package/lib/rtp/src/processor/rtpTimeCallback.js +2 -29
  78. package/lib/rtp/src/processor/rtpTimeCallback.js.map +1 -1
  79. package/lib/rtp/src/processor/webm.d.ts +8 -4
  80. package/lib/rtp/src/processor/webm.js +41 -8
  81. package/lib/rtp/src/processor/webm.js.map +1 -1
  82. package/lib/rtp/src/processor/webmCallback.d.ts +6 -5
  83. package/lib/rtp/src/processor/webmCallback.js +21 -7
  84. package/lib/rtp/src/processor/webmCallback.js.map +1 -1
  85. package/lib/webrtc/src/nonstandard/userMedia.d.ts +32 -23
  86. package/lib/webrtc/src/nonstandard/userMedia.js +49 -131
  87. package/lib/webrtc/src/nonstandard/userMedia.js.map +1 -1
  88. package/package.json +1 -1
  89. package/src/nonstandard/userMedia.ts +69 -75
  90. package/lib/rtp/src/processor/source/index.d.ts +0 -3
  91. package/lib/rtp/src/processor/source/index.js.map +0 -1
  92. package/lib/rtp/src/processor/source/rtcpCallback.d.ts +0 -13
  93. package/lib/rtp/src/processor/source/rtcpCallback.js.map +0 -1
  94. package/lib/rtp/src/processor/source/rtpCallback.d.ts +0 -19
  95. package/lib/rtp/src/processor/source/rtpCallback.js +0 -62
  96. package/lib/rtp/src/processor/source/rtpCallback.js.map +0 -1
  97. package/lib/rtp/src/processor/source/rtpStream.js.map +0 -1
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.LipsyncBase = void 0;
4
- const src_1 = require("../../../common/src");
4
+ const crypto_1 = require("crypto");
5
+ const __1 = require("..");
5
6
  class LipsyncBase {
6
7
  constructor(audioOutput, videoOutput, options = {}) {
7
8
  Object.defineProperty(this, "audioOutput", {
@@ -22,6 +23,12 @@ class LipsyncBase {
22
23
  writable: true,
23
24
  value: options
24
25
  });
26
+ Object.defineProperty(this, "id", {
27
+ enumerable: true,
28
+ configurable: true,
29
+ writable: true,
30
+ value: (0, crypto_1.randomUUID)()
31
+ });
25
32
  Object.defineProperty(this, "bufferLength", {
26
33
  enumerable: true,
27
34
  configurable: true,
@@ -60,11 +67,30 @@ class LipsyncBase {
60
67
  writable: true,
61
68
  value: void 0
62
69
  });
63
- Object.defineProperty(this, "started", {
70
+ /**ms */
71
+ Object.defineProperty(this, "bufferDuration", {
64
72
  enumerable: true,
65
73
  configurable: true,
66
74
  writable: true,
67
- value: false
75
+ value: void 0
76
+ });
77
+ Object.defineProperty(this, "ptime", {
78
+ enumerable: true,
79
+ configurable: true,
80
+ writable: true,
81
+ value: void 0
82
+ });
83
+ Object.defineProperty(this, "index", {
84
+ enumerable: true,
85
+ configurable: true,
86
+ writable: true,
87
+ value: 0
88
+ });
89
+ Object.defineProperty(this, "currentTimestamp", {
90
+ enumerable: true,
91
+ configurable: true,
92
+ writable: true,
93
+ value: void 0
68
94
  });
69
95
  /**ms */
70
96
  Object.defineProperty(this, "lastCommittedTime", {
@@ -73,11 +99,11 @@ class LipsyncBase {
73
99
  writable: true,
74
100
  value: 0
75
101
  });
76
- Object.defineProperty(this, "intervalId", {
102
+ Object.defineProperty(this, "lastExecutionTime", {
77
103
  enumerable: true,
78
104
  configurable: true,
79
105
  writable: true,
80
- value: void 0
106
+ value: 0
81
107
  });
82
108
  Object.defineProperty(this, "internalStats", {
83
109
  enumerable: true,
@@ -85,6 +111,13 @@ class LipsyncBase {
85
111
  writable: true,
86
112
  value: {}
87
113
  });
114
+ /**ms */
115
+ Object.defineProperty(this, "lastFrameReceivedAt", {
116
+ enumerable: true,
117
+ configurable: true,
118
+ writable: true,
119
+ value: 0
120
+ });
88
121
  Object.defineProperty(this, "processAudioInput", {
89
122
  enumerable: true,
90
123
  configurable: true,
@@ -96,23 +129,7 @@ class LipsyncBase {
96
129
  this.audioOutput = undefined;
97
130
  return;
98
131
  }
99
- if (this.stopped) {
100
- return;
101
- }
102
- if (this.baseTime == undefined) {
103
- this.baseTime = frame.time;
104
- }
105
- /**ms */
106
- const elapsed = frame.time - this.baseTime;
107
- if (elapsed < 0 || frame.time < this.lastCommittedTime) {
108
- return;
109
- }
110
- const index = (0, src_1.int)(elapsed / this.interval) % this.bufferLength;
111
- this.audioBuffer[index].push({
112
- frame,
113
- kind: "audio",
114
- });
115
- this.startIfNeed();
132
+ this.processInput(frame, this.audioBuffer, "audio");
116
133
  }
117
134
  });
118
135
  Object.defineProperty(this, "processVideoInput", {
@@ -126,99 +143,130 @@ class LipsyncBase {
126
143
  this.videoOutput = undefined;
127
144
  return;
128
145
  }
146
+ this.processInput(frame, this.videoBuffer, "video");
147
+ }
148
+ });
149
+ Object.defineProperty(this, "processInput", {
150
+ enumerable: true,
151
+ configurable: true,
152
+ writable: true,
153
+ value: (frame, buffer, kind) => {
129
154
  if (this.stopped) {
130
155
  return;
131
156
  }
132
157
  if (this.baseTime == undefined) {
133
158
  this.baseTime = frame.time;
159
+ this.currentTimestamp = this.baseTime;
160
+ this.lastExecutionTime = this.baseTime;
161
+ this.lastCommittedTime = this.baseTime;
162
+ this.lastFrameReceivedAt = Date.now();
134
163
  }
135
- /**ms */
136
- const elapsed = frame.time - this.baseTime;
137
- if (elapsed < 0 || frame.time < this.lastCommittedTime) {
164
+ // 過去のフレームを捨てる
165
+ if (frame.time < this.lastCommittedTime) {
138
166
  return;
139
167
  }
140
- const index = (0, src_1.int)(elapsed / this.interval) % this.bufferLength;
141
- this.videoBuffer[index].push({
168
+ // NTPの同期ずれが疑われるので捨てる
169
+ const now = Date.now();
170
+ const gap = 5000; // RTCP SR interval;
171
+ const lastCommittedElapsed = frame.time - this.lastCommittedTime;
172
+ const lastFrameReceivedElapsed = now - this.lastFrameReceivedAt;
173
+ if (gap < lastFrameReceivedElapsed && lastCommittedElapsed < gap) {
174
+ this.internalStats["invalidFrameTime"] = {
175
+ count: (this.internalStats["invalidFrameTime"]?.count ?? 0) + 1,
176
+ at: new Date().toISOString(),
177
+ lastCommittedElapsed,
178
+ lastFrameReceivedElapsed,
179
+ };
180
+ return;
181
+ }
182
+ this.lastFrameReceivedAt = now;
183
+ const elapsed = frame.time - this.baseTime;
184
+ const index = (0, __1.int)(elapsed / this.bufferDuration) % this.bufferLength;
185
+ buffer[index].push({
142
186
  frame,
143
- kind: "video",
187
+ kind,
144
188
  });
145
- this.startIfNeed();
189
+ const diff = frame.time - this.lastExecutionTime;
190
+ if (diff >= this.interval) {
191
+ const times = (0, __1.int)(diff / this.bufferDuration) - 1;
192
+ this.lastExecutionTime = this.currentTimestamp;
193
+ for (let i = 0; i < times; i++) {
194
+ this.executeTask();
195
+ this.lastExecutionTime += this.bufferDuration;
196
+ }
197
+ }
198
+ return;
146
199
  }
147
200
  });
148
201
  this.interval = this.options.syncInterval ?? 500;
149
- this.bufferLength = this.options.bufferingTimes ?? 10;
202
+ this.bufferDuration = this.interval / 2;
203
+ this.bufferLength = (this.options.bufferLength ?? 10) * 2;
150
204
  this.audioBuffer = [...new Array(this.bufferLength)].map(() => []);
151
205
  this.videoBuffer = [...new Array(this.bufferLength)].map(() => []);
206
+ this.ptime = this.options.ptime ?? 20;
152
207
  }
153
208
  toJSON() {
154
209
  return {
210
+ ...this.internalStats,
211
+ id: this.id,
155
212
  audioBufferLength: this.audioBuffer.flatMap((v) => v).length,
156
213
  videoBufferLength: this.videoBuffer.flatMap((v) => v).length,
157
214
  baseTime: this.baseTime,
158
215
  lastCommittedTimeSec: this.lastCommittedTime / 1000,
159
- ...this.internalStats,
160
216
  };
161
217
  }
162
- startIfNeed() {
163
- // 2列目にカーソルが移ってから処理を始めることで1列目の処理を完了できる
164
- if ([...this.audioBuffer[1], ...this.videoBuffer[1]].length === 0) {
165
- return;
166
- }
167
- if (this.started) {
168
- return;
169
- }
170
- this.started = true;
171
- let index = 0;
172
- let currentTimestamp = this.baseTime;
173
- const task = () => {
174
- const audioBuffer = this.audioBuffer[index].sort((a, b) => a.frame.time - b.frame.time);
175
- if (this.options.fillDummyAudioPacket) {
176
- const last = audioBuffer.at(-1);
177
- const expect = last ? last.frame.time + 20 : currentTimestamp;
178
- // パケット間の損失/muteはdtxプラグインでダミーパケットを挿入する
179
- // interval中のパケットが途中から無いもしくはinterval中にパケットが無い場合はここでダミーパケットを挿入する
180
- if (expect < currentTimestamp + this.interval) {
181
- for (let time = expect; time < currentTimestamp + this.interval; time += 20) {
182
- audioBuffer.push({
183
- frame: {
184
- time,
185
- data: this.options.fillDummyAudioPacket,
186
- isKeyframe: true,
187
- },
188
- kind: "audio",
189
- });
190
- this.internalStats["pushDummyPacket"] = {
191
- count: (this.internalStats["pushDummyPacket"]?.count ?? 0) + 1,
192
- at: new Date().toISOString(),
218
+ executeTask() {
219
+ const audioBuffer = this.audioBuffer[this.index].sort((a, b) => a.frame.time - b.frame.time);
220
+ if (this.options.fillDummyAudioPacket) {
221
+ const last = audioBuffer.at(-1);
222
+ const expect = last
223
+ ? last.frame.time +
224
+ // offset
225
+ this.ptime
226
+ : this.currentTimestamp;
227
+ // パケット間の損失/muteはdtxプラグインでダミーパケットを挿入する
228
+ // interval中のパケットが途中から無いもしくはinterval中にパケットが無い場合はここでダミーパケットを挿入する
229
+ const audioDiff = this.currentTimestamp + this.bufferDuration - expect;
230
+ if (audioDiff > 0) {
231
+ for (let time = expect; time < this.currentTimestamp + this.bufferDuration; time += this.ptime) {
232
+ audioBuffer.push({
233
+ frame: {
193
234
  time,
194
- };
195
- }
235
+ data: this.options.fillDummyAudioPacket,
236
+ isKeyframe: true,
237
+ },
238
+ kind: "audio",
239
+ });
240
+ this.internalStats["pushDummyPacket"] = {
241
+ count: (this.internalStats["pushDummyPacket"]?.count ?? 0) + 1,
242
+ at: new Date().toISOString(),
243
+ time,
244
+ };
196
245
  }
197
- currentTimestamp += this.interval;
198
246
  }
199
- const joined = [...audioBuffer, ...this.videoBuffer[index]].filter((b) => b.frame.time >= this.lastCommittedTime);
200
- const sorted = joined.sort((a, b) => a.frame.time - b.frame.time);
201
- this.audioBuffer[index] = [];
202
- this.videoBuffer[index] = [];
203
- for (const output of sorted) {
204
- if (output.kind === "audio") {
205
- this.audioOutput(output);
206
- }
207
- else {
208
- this.videoOutput(output);
209
- }
210
- this.lastCommittedTime = output.frame.time;
247
+ }
248
+ this.currentTimestamp += this.bufferDuration;
249
+ const joined = [...audioBuffer, ...this.videoBuffer[this.index]].filter((b) => b.frame.time >= this.lastCommittedTime);
250
+ const sorted = joined.sort((a, b) => a.frame.time - b.frame.time);
251
+ this.audioBuffer[this.index] = [];
252
+ this.videoBuffer[this.index] = [];
253
+ for (const output of sorted) {
254
+ if (output.kind === "audio") {
255
+ this.audioOutput(output);
211
256
  }
212
- index++;
213
- if (index === this.bufferLength) {
214
- index = 0;
257
+ else {
258
+ this.videoOutput(output);
215
259
  }
216
- };
217
- this.intervalId = setInterval(task, this.interval);
260
+ this.internalStats["lipsync"] = new Date().toISOString();
261
+ this.lastCommittedTime = output.frame.time;
262
+ }
263
+ this.index++;
264
+ if (this.index === this.bufferLength) {
265
+ this.index = 0;
266
+ }
218
267
  }
219
268
  stop() {
220
269
  this.stopped = true;
221
- clearInterval(this.intervalId);
222
270
  this.audioBuffer = [];
223
271
  this.videoBuffer = [];
224
272
  }
@@ -1 +1 @@
1
- {"version":3,"file":"lipsync.js","sourceRoot":"","sources":["../../../../../rtp/src/processor/lipsync.ts"],"names":[],"mappings":";;;AAAA,6CAA0C;AAc1C,MAAa,WAAW;IAetB,YACU,WAA4C,EAC5C,WAA4C,EAC5C,UAAmC,EAAE;;;;;mBAFrC;;;;;;mBACA;;;;;;mBACA;;QAjBV;;;;;WAAqB;QACrB,QAAQ;QACR;;;;;WAAkB;QAClB;;;;;WAAqD;QACrD;;;;;WAAqD;QACrD;;;;mBAAU,KAAK;WAAC;QAChB,QAAQ;QACR;;;;;WAAyB;QACzB;;;;mBAAkB,KAAK;WAAC;QACxB,QAAQ;QACR;;;;mBAAoB,CAAC;WAAC;QACtB;;;;;WAAyB;QACzB;;;;mBAAwB,EAAE;WAAC;QAqG3B;;;;mBAAoB,CAAC,EAAE,KAAK,EAAE,GAAG,EAAgB,EAAE,EAAE;gBACnD,IAAI,CAAC,KAAK,EAAE;oBACV,IAAI,CAAC,WAAW,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;oBAC1B,IAAI,CAAC,IAAI,EAAE,CAAC;oBACZ,IAAI,CAAC,WAAW,GAAG,SAAgB,CAAC;oBACpC,OAAO;iBACR;gBACD,IAAI,IAAI,CAAC,OAAO,EAAE;oBAChB,OAAO;iBACR;gBAED,IAAI,IAAI,CAAC,QAAQ,IAAI,SAAS,EAAE;oBAC9B,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC;iBAC5B;gBAED,QAAQ;gBACR,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,QAAS,CAAC;gBAC5C,IAAI,OAAO,GAAG,CAAC,IAAI,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,iBAAiB,EAAE;oBACtD,OAAO;iBACR;gBACD,MAAM,KAAK,GAAG,IAAA,SAAG,EAAC,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC;gBAC/D,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC;oBAC3B,KAAK;oBACL,IAAI,EAAE,OAAO;iBACd,CAAC,CAAC;gBAEH,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,CAAC;WAAC;QAEF;;;;mBAAoB,CAAC,EAAE,KAAK,EAAE,GAAG,EAAgB,EAAE,EAAE;gBACnD,IAAI,CAAC,KAAK,EAAE;oBACV,IAAI,CAAC,WAAW,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;oBAC1B,IAAI,CAAC,IAAI,EAAE,CAAC;oBACZ,IAAI,CAAC,WAAW,GAAG,SAAgB,CAAC;oBACpC,OAAO;iBACR;gBACD,IAAI,IAAI,CAAC,OAAO,EAAE;oBAChB,OAAO;iBACR;gBAED,IAAI,IAAI,CAAC,QAAQ,IAAI,SAAS,EAAE;oBAC9B,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC;iBAC5B;gBAED,QAAQ;gBACR,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,QAAS,CAAC;gBAC5C,IAAI,OAAO,GAAG,CAAC,IAAI,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,iBAAiB,EAAE;oBACtD,OAAO;iBACR;gBACD,MAAM,KAAK,GAAG,IAAA,SAAG,EAAC,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC;gBAC/D,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC;oBAC3B,KAAK;oBACL,IAAI,EAAE,OAAO;iBACd,CAAC,CAAC;gBAEH,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,CAAC;WAAC;QAtJA,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,IAAI,GAAG,CAAC;QACjD,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,IAAI,EAAE,CAAC;QACtD,IAAI,CAAC,WAAW,GAAG,CAAC,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QACnE,IAAI,CAAC,WAAW,GAAG,CAAC,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;IACrE,CAAC;IAED,MAAM;QACJ,OAAO;YACL,iBAAiB,EAAE,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM;YAC5D,iBAAiB,EAAE,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM;YAC5D,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,oBAAoB,EAAE,IAAI,CAAC,iBAAiB,GAAG,IAAI;YACnD,GAAG,IAAI,CAAC,aAAa;SACtB,CAAC;IACJ,CAAC;IAEO,WAAW;QACjB,sCAAsC;QACtC,IAAI,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE;YACjE,OAAO;SACR;QAED,IAAI,IAAI,CAAC,OAAO,EAAE;YAChB,OAAO;SACR;QACD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QAEpB,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,IAAI,gBAAgB,GAAG,IAAI,CAAC,QAAS,CAAC;QACtC,MAAM,IAAI,GAAG,GAAG,EAAE;YAChB,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,IAAI,CAC9C,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CACtC,CAAC;YAEF,IAAI,IAAI,CAAC,OAAO,CAAC,oBAAoB,EAAE;gBACrC,MAAM,IAAI,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;gBAChC,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC;gBAE9D,sCAAsC;gBACtC,+DAA+D;gBAC/D,IAAI,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAAC,QAAQ,EAAE;oBAC7C,KACE,IAAI,IAAI,GAAG,MAAM,EACjB,IAAI,GAAG,gBAAgB,GAAG,IAAI,CAAC,QAAQ,EACvC,IAAI,IAAI,EAAE,EACV;wBACA,WAAW,CAAC,IAAI,CAAC;4BACf,KAAK,EAAE;gCACL,IAAI;gCACJ,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,oBAAoB;gCACvC,UAAU,EAAE,IAAI;6BACjB;4BACD,IAAI,EAAE,OAAO;yBACd,CAAC,CAAC;wBACH,IAAI,CAAC,aAAa,CAAC,iBAAiB,CAAC,GAAG;4BACtC,KAAK,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,iBAAiB,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC;4BAC9D,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;4BAC5B,IAAI;yBACL,CAAC;qBACH;iBACF;gBACD,gBAAgB,IAAI,IAAI,CAAC,QAAQ,CAAC;aACnC;YACD,MAAM,MAAM,GAAG,CAAC,GAAG,WAAW,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAChE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,IAAI,IAAI,CAAC,iBAAiB,CAC9C,CAAC;YACF,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAClE,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;YAC7B,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;YAE7B,KAAK,MAAM,MAAM,IAAI,MAAM,EAAE;gBAC3B,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO,EAAE;oBAC3B,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;iBAC1B;qBAAM;oBACL,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;iBAC1B;gBACD,IAAI,CAAC,iBAAiB,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC;aAC5C;YAED,KAAK,EAAE,CAAC;YACR,IAAI,KAAK,KAAK,IAAI,CAAC,YAAY,EAAE;gBAC/B,KAAK,GAAG,CAAC,CAAC;aACX;QACH,CAAC,CAAC;QACF,IAAI,CAAC,UAAU,GAAG,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IACrD,CAAC;IAEO,IAAI;QACV,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC/B,IAAI,CAAC,WAAW,GAAG,EAAE,CAAC;QACtB,IAAI,CAAC,WAAW,GAAG,EAAE,CAAC;IACxB,CAAC;CA2DF;AA3KD,kCA2KC","sourcesContent":["import { int } from \"../../../common/src\";\nimport { CodecFrame } from \"./depacketizer\";\nimport { AVProcessor } from \"./interface\";\n\nexport type LipsyncInput = {\n frame?: CodecFrame;\n eol?: boolean;\n};\n\nexport type LipsyncOutput = {\n frame?: CodecFrame;\n eol?: boolean;\n};\n\nexport class LipsyncBase implements AVProcessor<LipsyncInput> {\n bufferLength: number;\n /**ms */\n baseTime?: number;\n audioBuffer: { frame: CodecFrame; kind: string }[][];\n videoBuffer: { frame: CodecFrame; kind: string }[][];\n stopped = false;\n /**ms */\n private interval: number;\n private started = false;\n /**ms */\n lastCommittedTime = 0;\n private intervalId?: any;\n private internalStats = {};\n\n constructor(\n private audioOutput: (output: LipsyncOutput) => void,\n private videoOutput: (output: LipsyncOutput) => void,\n private options: Partial<LipSyncOptions> = {}\n ) {\n this.interval = this.options.syncInterval ?? 500;\n this.bufferLength = this.options.bufferingTimes ?? 10;\n this.audioBuffer = [...new Array(this.bufferLength)].map(() => []);\n this.videoBuffer = [...new Array(this.bufferLength)].map(() => []);\n }\n\n toJSON(): Record<string, any> {\n return {\n audioBufferLength: this.audioBuffer.flatMap((v) => v).length,\n videoBufferLength: this.videoBuffer.flatMap((v) => v).length,\n baseTime: this.baseTime,\n lastCommittedTimeSec: this.lastCommittedTime / 1000,\n ...this.internalStats,\n };\n }\n\n private startIfNeed() {\n // 2列目にカーソルが移ってから処理を始めることで1列目の処理を完了できる\n if ([...this.audioBuffer[1], ...this.videoBuffer[1]].length === 0) {\n return;\n }\n\n if (this.started) {\n return;\n }\n this.started = true;\n\n let index = 0;\n let currentTimestamp = this.baseTime!;\n const task = () => {\n const audioBuffer = this.audioBuffer[index].sort(\n (a, b) => a.frame.time - b.frame.time\n );\n\n if (this.options.fillDummyAudioPacket) {\n const last = audioBuffer.at(-1);\n const expect = last ? last.frame.time + 20 : currentTimestamp;\n\n // パケット間の損失/muteはdtxプラグインでダミーパケットを挿入する\n // interval中のパケットが途中から無いもしくはinterval中にパケットが無い場合はここでダミーパケットを挿入する\n if (expect < currentTimestamp + this.interval) {\n for (\n let time = expect;\n time < currentTimestamp + this.interval;\n time += 20\n ) {\n audioBuffer.push({\n frame: {\n time,\n data: this.options.fillDummyAudioPacket,\n isKeyframe: true,\n },\n kind: \"audio\",\n });\n this.internalStats[\"pushDummyPacket\"] = {\n count: (this.internalStats[\"pushDummyPacket\"]?.count ?? 0) + 1,\n at: new Date().toISOString(),\n time,\n };\n }\n }\n currentTimestamp += this.interval;\n }\n const joined = [...audioBuffer, ...this.videoBuffer[index]].filter(\n (b) => b.frame.time >= this.lastCommittedTime\n );\n const sorted = joined.sort((a, b) => a.frame.time - b.frame.time);\n this.audioBuffer[index] = [];\n this.videoBuffer[index] = [];\n\n for (const output of sorted) {\n if (output.kind === \"audio\") {\n this.audioOutput(output);\n } else {\n this.videoOutput(output);\n }\n this.lastCommittedTime = output.frame.time;\n }\n\n index++;\n if (index === this.bufferLength) {\n index = 0;\n }\n };\n this.intervalId = setInterval(task, this.interval);\n }\n\n private stop() {\n this.stopped = true;\n clearInterval(this.intervalId);\n this.audioBuffer = [];\n this.videoBuffer = [];\n }\n\n processAudioInput = ({ frame, eol }: LipsyncInput) => {\n if (!frame) {\n this.audioOutput({ eol });\n this.stop();\n this.audioOutput = undefined as any;\n return;\n }\n if (this.stopped) {\n return;\n }\n\n if (this.baseTime == undefined) {\n this.baseTime = frame.time;\n }\n\n /**ms */\n const elapsed = frame.time - this.baseTime!;\n if (elapsed < 0 || frame.time < this.lastCommittedTime) {\n return;\n }\n const index = int(elapsed / this.interval) % this.bufferLength;\n this.audioBuffer[index].push({\n frame,\n kind: \"audio\",\n });\n\n this.startIfNeed();\n };\n\n processVideoInput = ({ frame, eol }: LipsyncInput) => {\n if (!frame) {\n this.videoOutput({ eol });\n this.stop();\n this.videoOutput = undefined as any;\n return;\n }\n if (this.stopped) {\n return;\n }\n\n if (this.baseTime == undefined) {\n this.baseTime = frame.time;\n }\n\n /**ms */\n const elapsed = frame.time - this.baseTime!;\n if (elapsed < 0 || frame.time < this.lastCommittedTime) {\n return;\n }\n const index = int(elapsed / this.interval) % this.bufferLength;\n this.videoBuffer[index].push({\n frame,\n kind: \"video\",\n });\n\n this.startIfNeed();\n };\n}\n\nexport interface LipSyncOptions {\n /**ms */\n syncInterval: number;\n /**\n * int\n * @description syncInterval * bufferingTimes=bufferTimeLength\n * */\n bufferingTimes: number;\n fillDummyAudioPacket: Buffer;\n}\n"]}
1
+ {"version":3,"file":"lipsync.js","sourceRoot":"","sources":["../../../../../rtp/src/processor/lipsync.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"crypto\";\n\nimport { int } from \"..\";\nimport { CodecFrame } from \"./depacketizer\";\nimport { AVProcessor } from \"./interface\";\nimport { MediaKind } from \"./webm\";\n\nexport type LipsyncInput = {\n frame?: CodecFrame;\n eol?: boolean;\n};\n\nexport type LipsyncOutput = {\n frame?: CodecFrame;\n eol?: boolean;\n};\n\nexport class LipsyncBase implements AVProcessor<LipsyncInput> {\n private id = randomUUID();\n bufferLength: number;\n /**ms */\n baseTime?: number;\n audioBuffer: {\n frame: CodecFrame;\n kind: MediaKind;\n [key: string]: any;\n }[][];\n videoBuffer: { frame: CodecFrame; kind: MediaKind }[][];\n stopped = false;\n /**ms */\n private interval: number;\n /**ms */\n private bufferDuration: number;\n private ptime: number;\n private index = 0;\n private currentTimestamp!: number;\n /**ms */\n private lastCommittedTime = 0;\n private lastExecutionTime = 0;\n private internalStats = {};\n /**ms */\n private lastFrameReceivedAt = 0;\n\n constructor(\n private audioOutput: (output: LipsyncOutput) => void,\n private videoOutput: (output: LipsyncOutput) => void,\n private options: Partial<LipSyncOptions> = {}\n ) {\n this.interval = this.options.syncInterval ?? 500;\n this.bufferDuration = this.interval / 2;\n this.bufferLength = (this.options.bufferLength ?? 10) * 2;\n this.audioBuffer = [...new Array(this.bufferLength)].map(() => []);\n this.videoBuffer = [...new Array(this.bufferLength)].map(() => []);\n this.ptime = this.options.ptime ?? 20;\n }\n\n toJSON(): Record<string, any> {\n return {\n ...this.internalStats,\n id: this.id,\n audioBufferLength: this.audioBuffer.flatMap((v) => v).length,\n videoBufferLength: this.videoBuffer.flatMap((v) => v).length,\n baseTime: this.baseTime,\n lastCommittedTimeSec: this.lastCommittedTime / 1000,\n };\n }\n\n private executeTask() {\n const audioBuffer = this.audioBuffer[this.index].sort(\n (a, b) => a.frame.time - b.frame.time\n );\n\n if (this.options.fillDummyAudioPacket) {\n const last = audioBuffer.at(-1);\n const expect = last\n ? last.frame.time +\n // offset\n this.ptime\n : this.currentTimestamp;\n\n // パケット間の損失/muteはdtxプラグインでダミーパケットを挿入する\n // interval中のパケットが途中から無いもしくはinterval中にパケットが無い場合はここでダミーパケットを挿入する\n const audioDiff = this.currentTimestamp + this.bufferDuration - expect;\n if (audioDiff > 0) {\n for (\n let time = expect;\n time < this.currentTimestamp + this.bufferDuration;\n time += this.ptime\n ) {\n audioBuffer.push({\n frame: {\n time,\n data: this.options.fillDummyAudioPacket,\n isKeyframe: true,\n },\n kind: \"audio\",\n });\n this.internalStats[\"pushDummyPacket\"] = {\n count: (this.internalStats[\"pushDummyPacket\"]?.count ?? 0) + 1,\n at: new Date().toISOString(),\n time,\n };\n }\n }\n }\n this.currentTimestamp += this.bufferDuration;\n const joined = [...audioBuffer, ...this.videoBuffer[this.index]].filter(\n (b) => b.frame.time >= this.lastCommittedTime\n );\n const sorted = joined.sort((a, b) => a.frame.time - b.frame.time);\n this.audioBuffer[this.index] = [];\n this.videoBuffer[this.index] = [];\n\n for (const output of sorted) {\n if (output.kind === \"audio\") {\n this.audioOutput(output);\n } else {\n this.videoOutput(output);\n }\n this.internalStats[\"lipsync\"] = new Date().toISOString();\n this.lastCommittedTime = output.frame.time;\n }\n\n this.index++;\n if (this.index === this.bufferLength) {\n this.index = 0;\n }\n }\n\n private stop() {\n this.stopped = true;\n this.audioBuffer = [];\n this.videoBuffer = [];\n }\n\n processAudioInput = ({ frame, eol }: LipsyncInput) => {\n if (!frame) {\n this.audioOutput({ eol });\n this.stop();\n this.audioOutput = undefined as any;\n return;\n }\n\n this.processInput(frame, this.audioBuffer, \"audio\");\n };\n\n processVideoInput = ({ frame, eol }: LipsyncInput) => {\n if (!frame) {\n this.videoOutput({ eol });\n this.stop();\n this.videoOutput = undefined as any;\n return;\n }\n\n this.processInput(frame, this.videoBuffer, \"video\");\n };\n\n private processInput = (\n frame: CodecFrame,\n buffer: {\n frame: CodecFrame;\n kind: MediaKind;\n }[][],\n kind: MediaKind\n ) => {\n if (this.stopped) {\n return;\n }\n\n if (this.baseTime == undefined) {\n this.baseTime = frame.time;\n this.currentTimestamp = this.baseTime;\n this.lastExecutionTime = this.baseTime;\n this.lastCommittedTime = this.baseTime;\n this.lastFrameReceivedAt = Date.now();\n }\n\n // 過去のフレームを捨てる\n if (frame.time < this.lastCommittedTime) {\n return;\n }\n\n // NTPの同期ずれが疑われるので捨てる\n const now = Date.now();\n const gap = 5000; // RTCP SR interval;\n const lastCommittedElapsed = frame.time - this.lastCommittedTime;\n const lastFrameReceivedElapsed = now - this.lastFrameReceivedAt;\n if (gap < lastFrameReceivedElapsed && lastCommittedElapsed < gap) {\n this.internalStats[\"invalidFrameTime\"] = {\n count: (this.internalStats[\"invalidFrameTime\"]?.count ?? 0) + 1,\n at: new Date().toISOString(),\n lastCommittedElapsed,\n lastFrameReceivedElapsed,\n };\n return;\n }\n this.lastFrameReceivedAt = now;\n\n const elapsed = frame.time - this.baseTime;\n const index = int(elapsed / this.bufferDuration) % this.bufferLength;\n buffer[index].push({\n frame,\n kind,\n });\n\n const diff = frame.time - this.lastExecutionTime;\n if (diff >= this.interval) {\n const times = int(diff / this.bufferDuration) - 1;\n this.lastExecutionTime = this.currentTimestamp;\n for (let i = 0; i < times; i++) {\n this.executeTask();\n this.lastExecutionTime += this.bufferDuration;\n }\n }\n return;\n };\n}\n\nexport interface LipSyncOptions {\n /**ms */\n syncInterval: number;\n /**\n * int\n * @description syncInterval * bufferLength = max packet lifetime\n * */\n bufferLength: number;\n fillDummyAudioPacket: Buffer;\n ptime: number;\n}\n"]}
@@ -1,10 +1,13 @@
1
- import { LipsyncBase, LipSyncOptions, LipsyncOutput } from "./lipsync";
1
+ import { LipsyncBase, LipsyncInput, LipSyncOptions, LipsyncOutput } from "./lipsync";
2
2
  export declare class LipsyncCallback extends LipsyncBase {
3
3
  private audioCb?;
4
+ private audioDestructor?;
4
5
  private videoCb?;
6
+ private videoDestructor?;
5
7
  constructor(options?: Partial<LipSyncOptions>);
6
- pipeAudio: (cb: (input: LipsyncOutput) => void) => void;
7
- pipeVideo: (cb: (input: LipsyncOutput) => void) => void;
8
- inputAudio: ({ frame, eol }: import("./lipsync").LipsyncInput) => void;
9
- inputVideo: ({ frame, eol }: import("./lipsync").LipsyncInput) => void;
8
+ pipeAudio: (cb: (input: LipsyncOutput) => void, destructor?: () => void) => void;
9
+ pipeVideo: (cb: (input: LipsyncOutput) => void, destructor?: () => void) => void;
10
+ inputAudio: (input: LipsyncInput) => void;
11
+ inputVideo: (input: LipsyncInput) => void;
12
+ destroy: () => void;
10
13
  }
@@ -19,39 +19,74 @@ class LipsyncCallback extends lipsync_1.LipsyncBase {
19
19
  writable: true,
20
20
  value: void 0
21
21
  });
22
+ Object.defineProperty(this, "audioDestructor", {
23
+ enumerable: true,
24
+ configurable: true,
25
+ writable: true,
26
+ value: void 0
27
+ });
22
28
  Object.defineProperty(this, "videoCb", {
23
29
  enumerable: true,
24
30
  configurable: true,
25
31
  writable: true,
26
32
  value: void 0
27
33
  });
34
+ Object.defineProperty(this, "videoDestructor", {
35
+ enumerable: true,
36
+ configurable: true,
37
+ writable: true,
38
+ value: void 0
39
+ });
28
40
  Object.defineProperty(this, "pipeAudio", {
29
41
  enumerable: true,
30
42
  configurable: true,
31
43
  writable: true,
32
- value: (cb) => {
44
+ value: (cb, destructor) => {
33
45
  this.audioCb = cb;
46
+ this.audioDestructor = destructor;
34
47
  }
35
48
  });
36
49
  Object.defineProperty(this, "pipeVideo", {
37
50
  enumerable: true,
38
51
  configurable: true,
39
52
  writable: true,
40
- value: (cb) => {
53
+ value: (cb, destructor) => {
41
54
  this.videoCb = cb;
55
+ this.videoDestructor = destructor;
42
56
  }
43
57
  });
44
58
  Object.defineProperty(this, "inputAudio", {
45
59
  enumerable: true,
46
60
  configurable: true,
47
61
  writable: true,
48
- value: this.processAudioInput
62
+ value: (input) => {
63
+ this.processAudioInput(input);
64
+ }
49
65
  });
50
66
  Object.defineProperty(this, "inputVideo", {
51
67
  enumerable: true,
52
68
  configurable: true,
53
69
  writable: true,
54
- value: this.processVideoInput
70
+ value: (input) => {
71
+ this.processVideoInput(input);
72
+ }
73
+ });
74
+ Object.defineProperty(this, "destroy", {
75
+ enumerable: true,
76
+ configurable: true,
77
+ writable: true,
78
+ value: () => {
79
+ if (this.audioDestructor) {
80
+ this.audioDestructor();
81
+ this.audioDestructor = undefined;
82
+ }
83
+ if (this.videoDestructor) {
84
+ this.videoDestructor();
85
+ this.videoDestructor = undefined;
86
+ }
87
+ this.audioCb = undefined;
88
+ this.videoCb = undefined;
89
+ }
55
90
  });
56
91
  }
57
92
  }
@@ -1 +1 @@
1
- {"version":3,"file":"lipsyncCallback.js","sourceRoot":"","sources":["../../../../../rtp/src/processor/lipsyncCallback.ts"],"names":[],"mappings":";;;AAAA,uCAAuE;AAEvE,MAAa,eAAgB,SAAQ,qBAAW;IAG9C,YAAY,UAAmC,EAAE;QAC/C,KAAK,CACH,CAAC,MAAM,EAAE,EAAE;YACT,IAAI,IAAI,CAAC,OAAO,EAAE;gBAChB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;aACtB;QACH,CAAC,EACD,CAAC,MAAM,EAAE,EAAE;YACT,IAAI,IAAI,CAAC,OAAO,EAAE;gBAChB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;aACtB;QACH,CAAC,EACD,OAAO,CACR,CAAC;QAfJ;;;;;WAAiD;QACjD;;;;;WAAiD;QAiBjD;;;;mBAAY,CAAC,EAAkC,EAAE,EAAE;gBACjD,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC;YACpB,CAAC;WAAC;QACF;;;;mBAAY,CAAC,EAAkC,EAAE,EAAE;gBACjD,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC;YACpB,CAAC;WAAC;QAEF;;;;mBAAa,IAAI,CAAC,iBAAiB;WAAC;QACpC;;;;mBAAa,IAAI,CAAC,iBAAiB;WAAC;IAVpC,CAAC;CAWF;AA5BD,0CA4BC","sourcesContent":["import { LipsyncBase, LipSyncOptions, LipsyncOutput } from \"./lipsync\";\n\nexport class LipsyncCallback extends LipsyncBase {\n private audioCb?: (input: LipsyncOutput) => void;\n private videoCb?: (input: LipsyncOutput) => void;\n constructor(options: Partial<LipSyncOptions> = {}) {\n super(\n (output) => {\n if (this.audioCb) {\n this.audioCb(output);\n }\n },\n (output) => {\n if (this.videoCb) {\n this.videoCb(output);\n }\n },\n options\n );\n }\n\n pipeAudio = (cb: (input: LipsyncOutput) => void) => {\n this.audioCb = cb;\n };\n pipeVideo = (cb: (input: LipsyncOutput) => void) => {\n this.videoCb = cb;\n };\n\n inputAudio = this.processAudioInput;\n inputVideo = this.processVideoInput;\n}\n"]}
1
+ {"version":3,"file":"lipsyncCallback.js","sourceRoot":"","sources":["../../../../../rtp/src/processor/lipsyncCallback.ts"],"names":[],"mappings":";;;AAAA,uCAKmB;AAEnB,MAAa,eAAgB,SAAQ,qBAAW;IAK9C,YAAY,UAAmC,EAAE;QAC/C,KAAK,CACH,CAAC,MAAM,EAAE,EAAE;YACT,IAAI,IAAI,CAAC,OAAO,EAAE;gBAChB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;aACtB;QACH,CAAC,EACD,CAAC,MAAM,EAAE,EAAE;YACT,IAAI,IAAI,CAAC,OAAO,EAAE;gBAChB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;aACtB;QACH,CAAC,EACD,OAAO,CACR,CAAC;QAjBJ;;;;;WAAiD;QACjD;;;;;WAAqC;QACrC;;;;;WAAiD;QACjD;;;;;WAAqC;QAiBrC;;;;mBAAY,CAAC,EAAkC,EAAE,UAAuB,EAAE,EAAE;gBAC1E,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC;gBAClB,IAAI,CAAC,eAAe,GAAG,UAAU,CAAC;YACpC,CAAC;WAAC;QACF;;;;mBAAY,CAAC,EAAkC,EAAE,UAAuB,EAAE,EAAE;gBAC1E,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC;gBAClB,IAAI,CAAC,eAAe,GAAG,UAAU,CAAC;YACpC,CAAC;WAAC;QAEF;;;;mBAAa,CAAC,KAAmB,EAAE,EAAE;gBACnC,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC;YAChC,CAAC;WAAC;QACF;;;;mBAAa,CAAC,KAAmB,EAAE,EAAE;gBACnC,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC;YAChC,CAAC;WAAC;QAEF;;;;mBAAU,GAAG,EAAE;gBACb,IAAI,IAAI,CAAC,eAAe,EAAE;oBACxB,IAAI,CAAC,eAAe,EAAE,CAAC;oBACvB,IAAI,CAAC,eAAe,GAAG,SAAS,CAAC;iBAClC;gBACD,IAAI,IAAI,CAAC,eAAe,EAAE;oBACxB,IAAI,CAAC,eAAe,EAAE,CAAC;oBACvB,IAAI,CAAC,eAAe,GAAG,SAAS,CAAC;iBAClC;gBACD,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC;gBACzB,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC;YAC3B,CAAC;WAAC;IA7BF,CAAC;CA8BF;AAjDD,0CAiDC","sourcesContent":["import {\n LipsyncBase,\n LipsyncInput,\n LipSyncOptions,\n LipsyncOutput,\n} from \"./lipsync\";\n\nexport class LipsyncCallback extends LipsyncBase {\n private audioCb?: (input: LipsyncOutput) => void;\n private audioDestructor?: () => void;\n private videoCb?: (input: LipsyncOutput) => void;\n private videoDestructor?: () => void;\n constructor(options: Partial<LipSyncOptions> = {}) {\n super(\n (output) => {\n if (this.audioCb) {\n this.audioCb(output);\n }\n },\n (output) => {\n if (this.videoCb) {\n this.videoCb(output);\n }\n },\n options\n );\n }\n\n pipeAudio = (cb: (input: LipsyncOutput) => void, destructor?: () => void) => {\n this.audioCb = cb;\n this.audioDestructor = destructor;\n };\n pipeVideo = (cb: (input: LipsyncOutput) => void, destructor?: () => void) => {\n this.videoCb = cb;\n this.videoDestructor = destructor;\n };\n\n inputAudio = (input: LipsyncInput) => {\n this.processAudioInput(input);\n };\n inputVideo = (input: LipsyncInput) => {\n this.processVideoInput(input);\n };\n\n destroy = () => {\n if (this.audioDestructor) {\n this.audioDestructor();\n this.audioDestructor = undefined;\n }\n if (this.videoDestructor) {\n this.videoDestructor();\n this.videoDestructor = undefined;\n }\n this.audioCb = undefined;\n this.videoCb = undefined;\n };\n}\n"]}
@@ -8,18 +8,31 @@ export declare class MuteHandlerBase implements Processor<MuteInput, MuteOutput>
8
8
  private props;
9
9
  readonly id: string;
10
10
  private buffer;
11
- private started;
11
+ private index;
12
12
  private ended;
13
- private intervalId;
13
+ private baseTime?;
14
14
  private currentTimestamp;
15
+ private internalStats;
16
+ /**ms */
17
+ private lastCommittedTime;
18
+ private lastExecutionTime;
19
+ /**ms */
20
+ private interval;
21
+ private bufferDuration;
22
+ private bufferLength;
23
+ /**ms */
24
+ private lastFrameReceivedAt;
15
25
  constructor(output: (o: MuteOutput) => void, props: {
16
26
  ptime: number;
17
27
  dummyPacket: Buffer;
28
+ /**ms
29
+ * @description intervalごとに無音区間に空パケットを挿入する
30
+ */
18
31
  interval: number;
19
- sort?: boolean;
32
+ bufferLength: number;
20
33
  });
21
34
  toJSON(): Record<string, any>;
22
- private startIfNeed;
35
+ private executeTask;
23
36
  private stop;
24
37
  processInput: ({ frame, eol }: MuteInput) => MuteOutput[];
25
38
  }