@danything/arib 1.3.1 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/eit.d.ts CHANGED
@@ -99,7 +99,7 @@ export interface EitEvent {
99
99
  */
100
100
  series?: EitSeries | null;
101
101
  /**
102
- * CA契約情報記述子 (0xCB) の contract_verification_info。
102
+ * CA 契約情報記述子 (0xCB) の contract_verification_info。
103
103
  * 有料放送の契約確認・復号判定に使う (B-CAS の 0x90 0x3C コマンド)。
104
104
  * 載っていなければ null。詳細の表では言っていないので undefined。
105
105
  */
@@ -124,10 +124,10 @@ export declare const PID_TIME = 20;
124
124
  /**
125
125
  * TDT / TOT のセクションから**放送の実時刻**を読む。別のテーブルなら null。
126
126
  *
127
- * 頭 3 バイトのあとに MJD + BCD が 5 バイト。**TOT も同じ並び**で、後ろに
127
+ * 先頭 3 バイトのあとに MJD + BCD が 5 バイト。**TOT も同じ並び**で、後ろに
128
128
  * 時差の記述子が付くだけなので同じに読める。
129
129
  *
130
- * データ放送 (`bml.ts` の `onTime`) が読み、BML の時計にします
130
+ * データ放送 (`bml.ts` の `onTime`) が読んで、BML の時計にする
131
131
  */
132
132
  export declare function parseTimeTable(section: Uint8Array): number | null;
133
133
  /**
@@ -194,24 +194,24 @@ export declare class ScheduleProgress {
194
194
  * **番号が飛ぶ。** 1 つの `table_id` が受け持つのは 4 日ぶんで、基本は
195
195
  * `0x50` から、詳細は `0x58` から始まる。日本の放送は 8 日ぶんなので、
196
196
  * 実際に流れてくるのは `0x50` `0x51` と `0x58` `0x59` あたりだけで、
197
- * **`0x52`〜`0x57` は永久に来ません**。
197
+ * **`0x52`〜`0x57` は永久に来ない**。
198
198
  *
199
199
  * `0x50` から `last_table_id` まで全部を待っていた頃は、詳細を積んでいる局が
200
200
  * **一度も「揃った」にならず**、どのチャンネルも上限の 10 分 (denpa の `epgChannelTimeout`) まで開きっぱなしに
201
- * なっていました (実機で、詳細の無い BS11 だけが早く閉じていた)。
201
+ * なっていた (実機で、詳細の無い BS11 だけが早く閉じていた)。
202
202
  *
203
- * 見かけた表と、`last_table_id` が指す表だけを見ます。
203
+ * 見かけた表と、`last_table_id` が指す表だけを見る。
204
204
  */
205
205
  get complete(): boolean;
206
- /** その表でまだ来ていない節。セグメントの先頭すら来ていなければ、先頭の番号を数える */
206
+ /** その表でまだ来ていないセクション。セグメントの先頭すら来ていなければ、先頭の番号を数える */
207
207
  private holes;
208
208
  /**
209
209
  * そのセグメントの時間帯がもう過ぎているか。**過ぎたものは待たない。**
210
210
  *
211
- * セグメントは 0:00 から 3 時間ずつの枠で、`table_id` と節番号から
211
+ * セグメントは 0:00 から 3 時間ずつの枠で、`table_id` とセクション番号から
212
212
  * それがいつの枠なのかが決まる。基本は `0x50` が当日 0:00 から 4 日ぶん、
213
213
  * `0x51` がその次の 4 日ぶん。詳細 (`0x58`〜) も同じ並びをもう一度たどる。
214
- * 終わった枠は放送に乗らない (クラスの説明)。そのぶんの番組は、そこが未来だった数日前に取り込んである。
214
+ * 終わった枠は放送されない (クラスの説明)。そのぶんの番組は、そこが未来だった数日前に取り込んである。
215
215
  */
216
216
  private stale;
217
217
  /**
@@ -281,11 +281,11 @@ export declare class EpgReader {
281
281
  * p/f で「いま流れている」と言えるか。
282
282
  *
283
283
  * **`running_status` を当てにしきれない。** 4 (放送中) を入れてくる局も
284
- * あれば、**0 (未定義) しか入れてこない局もある。** 実機の NHK は 74 節
284
+ * あれば、**0 (未定義) しか入れてこない局もある。** 実機の NHK は 74 セクション
285
285
  * ぜんぶ 0 だった。4 だけを見ていると、そういう局では延長追従が丸ごと
286
286
  * 効かなくなる (denpa の docs/data.md)。
287
287
  *
288
- * そこで 0 のときは**節の番号で決める**。p/f は仕様で
288
+ * そこで 0 のときは**セクションの番号で決める**。p/f は仕様で
289
289
  * **section 0 が現在・section 1 が次**と決まっていて、こちらは局の都合で
290
290
  * 変わらない。1 (まもなく) や 2 (停止中) は今までどおり入れない。
291
291
  */
package/dist/eit.js CHANGED
@@ -60,10 +60,10 @@ const TABLE_TOT = 0x73;
60
60
  /**
61
61
  * TDT / TOT のセクションから**放送の実時刻**を読む。別のテーブルなら null。
62
62
  *
63
- * 頭 3 バイトのあとに MJD + BCD が 5 バイト。**TOT も同じ並び**で、後ろに
63
+ * 先頭 3 バイトのあとに MJD + BCD が 5 バイト。**TOT も同じ並び**で、後ろに
64
64
  * 時差の記述子が付くだけなので同じに読める。
65
65
  *
66
- * データ放送 (`bml.ts` の `onTime`) が読み、BML の時計にします
66
+ * データ放送 (`bml.ts` の `onTime`) が読んで、BML の時計にする
67
67
  */
68
68
  export function parseTimeTable(section) {
69
69
  if (section[0] !== TABLE_TDT && section[0] !== TABLE_TOT)
@@ -134,14 +134,14 @@ const lang = (data, at) => ascii(data, at, 3).toLowerCase();
134
134
  * 「直前の項目の続き」という意味なので、そこにも繋ぐ。
135
135
  *
136
136
  * **繋ぐのはデコードする前、バイトのうちに。** 部分ごとにデコードして文字列を繋いで
137
- * いた頃は、続きが**別の文字で出て**いました (実機の「音楽制作ずはのづ ねふびどっ」。
137
+ * いた頃は、続きが**別の文字で出て**いた (実機の「音楽制作ずはのづ ねふびどっ」。
138
138
  * 正しくは「音楽制作:ONE MUSIC」)。分割点は
139
139
  *
140
140
  * - **二バイト文字の途中**に来ることがある (片割れだけでは字にならない)
141
141
  * - **文字集合の状態を持ち越す。** G0〜G3 の指示も GL/GR の呼び出しも、
142
142
  * 続きの側には書き直されない。前の状態のまま読む前提で送られてくる
143
143
  *
144
- * ので、部分だけを単独でデコードすると、そこから先が崩れます。
144
+ * ので、部分だけを単独でデコードすると、そこから先が崩れる。
145
145
  *
146
146
  * **ただし見出しのある項目は、同じ見出しでも別の項目として最初の状態から読む。** 見出しが同じ
147
147
  * 項目が 2 つ続けて来る局があり (BS日テレの「番組内容」)、2 つ目は最初の状態 (漢字) から読む前提で
@@ -159,10 +159,12 @@ function readDescriptors(event, body) {
159
159
  for (const [tag, data] of descriptors(body)) {
160
160
  switch (tag) {
161
161
  case DESC_SHORT_EVENT: {
162
+ if (data.length < 4)
163
+ break;
162
164
  const nameLength = data[3];
163
165
  const textAt = 4 + nameLength;
164
166
  event.name = decodeAribText(data.subarray(4, textAt));
165
- const textLength = data[textAt];
167
+ const textLength = data[textAt] ?? 0;
166
168
  event.description = decodeAribText(data.subarray(textAt + 1, textAt + 1 + textLength));
167
169
  break;
168
170
  }
@@ -199,6 +201,9 @@ function readDescriptors(event, body) {
199
201
  break;
200
202
  }
201
203
  case DESC_COMPONENT: {
204
+ // 短いものを読むと、種別 0 の「480i」と出る
205
+ if (data.length < 2)
206
+ break;
202
207
  const streamContent = data[0] & 0x0f;
203
208
  const componentType = data[1];
204
209
  event.video = {
@@ -221,6 +226,9 @@ function readDescriptors(event, body) {
221
226
  * [残り] text_char … **放送が付けた名前**
222
227
  */
223
228
  case DESC_AUDIO_COMPONENT: {
229
+ // 言語の符号まで無いものを読むと、言語が空の音声が 1 本増える
230
+ if (data.length < 9)
231
+ break;
224
232
  const flags = data[5];
225
233
  const multiLingual = (flags & 0x80) !== 0;
226
234
  const langs = [lang(data, 6)];
@@ -245,7 +253,7 @@ function readDescriptors(event, body) {
245
253
  case DESC_CA_CONTRACT_INFO: {
246
254
  if (data.length < 4)
247
255
  break;
248
- const caSystemId = (data[0] << 8) | data[1];
256
+ const caSystemId = u16(data, 0);
249
257
  const numOfComponent = data[2] & 0x0f;
250
258
  let at = 3 + numOfComponent;
251
259
  if (at >= data.length)
@@ -254,7 +262,7 @@ function readDescriptors(event, body) {
254
262
  at++;
255
263
  if (at + cviLength <= data.length && cviLength > 0) {
256
264
  const cvi = data.subarray(at, at + cviLength);
257
- // B-CAS (0x0005) を優先。まだ無ければ拾う
265
+ // B-CAS (0x0005) を優先。まだ無ければこれを使う
258
266
  if (caSystemId === 0x0005 ||
259
267
  event.contractVerification === undefined ||
260
268
  event.contractVerification === null) {
@@ -434,13 +442,13 @@ export class ScheduleProgress {
434
442
  * **番号が飛ぶ。** 1 つの `table_id` が受け持つのは 4 日ぶんで、基本は
435
443
  * `0x50` から、詳細は `0x58` から始まる。日本の放送は 8 日ぶんなので、
436
444
  * 実際に流れてくるのは `0x50` `0x51` と `0x58` `0x59` あたりだけで、
437
- * **`0x52`〜`0x57` は永久に来ません**。
445
+ * **`0x52`〜`0x57` は永久に来ない**。
438
446
  *
439
447
  * `0x50` から `last_table_id` まで全部を待っていた頃は、詳細を積んでいる局が
440
448
  * **一度も「揃った」にならず**、どのチャンネルも上限の 10 分 (denpa の `epgChannelTimeout`) まで開きっぱなしに
441
- * なっていました (実機で、詳細の無い BS11 だけが早く閉じていた)。
449
+ * なっていた (実機で、詳細の無い BS11 だけが早く閉じていた)。
442
450
  *
443
- * 見かけた表と、`last_table_id` が指す表だけを見ます。
451
+ * 見かけた表と、`last_table_id` が指す表だけを見る。
444
452
  */
445
453
  get complete() {
446
454
  if (this.seen.size === 0)
@@ -454,7 +462,7 @@ export class ScheduleProgress {
454
462
  }
455
463
  return true;
456
464
  }
457
- /** その表でまだ来ていない節。セグメントの先頭すら来ていなければ、先頭の番号を数える */
465
+ /** その表でまだ来ていないセクション。セグメントの先頭すら来ていなければ、先頭の番号を数える */
458
466
  holes(tableId) {
459
467
  const numbers = this.seen.get(tableId) ?? new Set();
460
468
  const last = this.lastSection.get(tableId) ?? 0;
@@ -477,10 +485,10 @@ export class ScheduleProgress {
477
485
  /**
478
486
  * そのセグメントの時間帯がもう過ぎているか。**過ぎたものは待たない。**
479
487
  *
480
- * セグメントは 0:00 から 3 時間ずつの枠で、`table_id` と節番号から
488
+ * セグメントは 0:00 から 3 時間ずつの枠で、`table_id` とセクション番号から
481
489
  * それがいつの枠なのかが決まる。基本は `0x50` が当日 0:00 から 4 日ぶん、
482
490
  * `0x51` がその次の 4 日ぶん。詳細 (`0x58`〜) も同じ並びをもう一度たどる。
483
- * 終わった枠は放送に乗らない (クラスの説明)。そのぶんの番組は、そこが未来だった数日前に取り込んである。
491
+ * 終わった枠は放送されない (クラスの説明)。そのぶんの番組は、そこが未来だった数日前に取り込んである。
484
492
  */
485
493
  stale(tableId, start) {
486
494
  const base = tableId < SCHEDULE_ACTUAL_EXTENDED
@@ -501,7 +509,7 @@ export class ScheduleProgress {
501
509
  */
502
510
  report() {
503
511
  if (this.seen.size === 0)
504
- return "EIT[schedule] が1つも来ていない";
512
+ return "EIT[schedule] が 1 つも来ていない";
505
513
  if (!this.seen.has(this.lastTableId)) {
506
514
  const seen = [...this.seen.keys()].map(hex).join(",");
507
515
  return `最後の表 ${hex(this.lastTableId)} が一度も来ない (来たのは ${seen})`;
@@ -511,12 +519,12 @@ export class ScheduleProgress {
511
519
  const holes = this.holes(tableId);
512
520
  if (holes.length > 0) {
513
521
  const head = holes.slice(0, 8).join(",");
514
- missing.push(`${hex(tableId)} の ${head}${holes.length > 8 ? ` ほか${holes.length - 8}` : ""}`);
522
+ missing.push(`${hex(tableId)} の ${head}${holes.length > 8 ? ` ほか ${holes.length - 8}` : ""}`);
515
523
  }
516
524
  }
517
525
  return missing.length === 0
518
526
  ? "揃っている"
519
- : `来ていない節: ${missing.join(" / ")}`;
527
+ : `来ていないセクション: ${missing.join(" / ")}`;
520
528
  }
521
529
  }
522
530
  const hex = (value) => `0x${value.toString(16)}`;
@@ -632,11 +640,11 @@ export class EpgReader {
632
640
  * p/f で「いま流れている」と言えるか。
633
641
  *
634
642
  * **`running_status` を当てにしきれない。** 4 (放送中) を入れてくる局も
635
- * あれば、**0 (未定義) しか入れてこない局もある。** 実機の NHK は 74 節
643
+ * あれば、**0 (未定義) しか入れてこない局もある。** 実機の NHK は 74 セクション
636
644
  * ぜんぶ 0 だった。4 だけを見ていると、そういう局では延長追従が丸ごと
637
645
  * 効かなくなる (denpa の docs/data.md)。
638
646
  *
639
- * そこで 0 のときは**節の番号で決める**。p/f は仕様で
647
+ * そこで 0 のときは**セクションの番号で決める**。p/f は仕様で
640
648
  * **section 0 が現在・section 1 が次**と決まっていて、こちらは局の都合で
641
649
  * 変わらない。1 (まもなく) や 2 (停止中) は今までどおり入れない。
642
650
  */
@@ -775,7 +783,7 @@ export class PresentFollowing {
775
783
  return changed;
776
784
  }
777
785
  }
778
- /** 変わったかどうかを見る中身。**番号・時刻・尺・タイトルだけ** (番組表に写して画面に出るもの) */
786
+ /** 変わったかどうかを見る中身。**番号・時刻・尺・タイトルだけ** (番組表に入れて画面に出るもの) */
779
787
  function markOf(event) {
780
788
  return `${event.eventId}:${event.startAt}:${event.duration}:${event.name}`;
781
789
  }
package/dist/multipart.js CHANGED
@@ -121,7 +121,7 @@ export function readEntity(data, part = false) {
121
121
  const headers = [];
122
122
  let at = 0;
123
123
  for (;;) {
124
- // 中身が空の部品は、ヘッダの空行の CRLF が次の区切りの頭に食われて、ヘッダの行で
124
+ // 中身が空の部品は、ヘッダの空行の CRLF が次の区切りの先頭として読まれ、ヘッダの行で
125
125
  // ちょうど終わる (`--X\r\nContent-Type: a\r\n\r\n--X--`)。空の本体として受ける
126
126
  // (web-bml の entity-parser はここで null を返し、モジュールごと捨てていた)
127
127
  if (part && at === data.length && headers.length > 0)
package/dist/pes.d.ts CHANGED
@@ -29,7 +29,7 @@ export interface Streams {
29
29
  }
30
30
  /** 5 バイトの PTS / DTS を読む (ISO/IEC 13818-1 2.4.3.7) */
31
31
  export declare function readStamp(data: Uint8Array, at: number): number;
32
- /** PES の頭を読んで中身を切り出す。**壊れていれば null** (頭の 00 00 01 が無いなど) */
32
+ /** PES のヘッダを読んで中身を切り出す。**壊れていれば null** (先頭の 00 00 01 が無いなど) */
33
33
  export declare function parsePes(data: Uint8Array): {
34
34
  pts: number | null;
35
35
  dts: number | null;
@@ -38,7 +38,7 @@ export declare function parsePes(data: Uint8Array): {
38
38
  /**
39
39
  * TS を渡すと PES を返す。**選局し直したら作り直す** (前の局の切れ端を持ち越さない)。
40
40
  *
41
- * 映像は長さ 0 (次の頭で終わりが分かる) なので 1 枚ぶん遅れて出るが、貯めの中に収まる。
41
+ * 映像は長さ 0 (次の PES の先頭で終わりが分かる) なので 1 フレームぶん遅れて出るが、受け側が貯めるぶんに収まる。
42
42
  * 音声は長さが書いてあるので揃った時点で出す
43
43
  */
44
44
  export declare class PesDemuxer {
@@ -65,7 +65,7 @@ export declare class PesDemuxer {
65
65
  /** ADTS の標本化周波数の表 (ISO/IEC 14496-3 表 1.18) */
66
66
  export declare const ADTS_RATES: number[];
67
67
  export interface AdtsFrame {
68
- /** 頭 (7 か 9 バイト) ごと。WASM の AAC デコーダは ADTS のまま受け取る */
68
+ /** ヘッダ (7 か 9 バイト) ごと。WASM の AAC デコーダは ADTS のまま受け取る */
69
69
  data: Uint8Array;
70
70
  /** 90kHz */
71
71
  pts: number;
@@ -77,7 +77,7 @@ export interface AdtsFrame {
77
77
  /**
78
78
  * PES の中身を ADTS のコマに割る。**コマは PES をまたぐことがある**ので、余りは持ち越す。
79
79
  *
80
- * 時刻は PES の PTS を頭のコマに付け、続くコマには 1 コマぶんずつ足す。持ち越した
80
+ * 時刻は PES の PTS を先頭のコマに付け、続くコマには 1 コマぶんずつ足す。持ち越した
81
81
  * 余りから始まるコマは、前の続きの時刻になる
82
82
  */
83
83
  export declare class AdtsSplitter {
package/dist/pes.js CHANGED
@@ -25,7 +25,7 @@ export function readStamp(data, at) {
25
25
  (data[at + 3] << 7) +
26
26
  (data[at + 4] >> 1));
27
27
  }
28
- /** PES の頭を読んで中身を切り出す。**壊れていれば null** (頭の 00 00 01 が無いなど) */
28
+ /** PES のヘッダを読んで中身を切り出す。**壊れていれば null** (先頭の 00 00 01 が無いなど) */
29
29
  export function parsePes(data) {
30
30
  if (data.length < 9 || data[0] !== 0 || data[1] !== 0 || data[2] !== 1)
31
31
  return null;
@@ -35,18 +35,18 @@ export function parsePes(data) {
35
35
  if (start > data.length)
36
36
  return null;
37
37
  const length = u16(data, 4);
38
- // 長さが書いてあればそこまで (後ろに詰め物が付くことがある)。0 は「次の頭まで」
38
+ // 長さが書いてあればそこまで (後ろに詰め物が付くことがある)。0 は「次の PES の先頭まで」
39
39
  const end = length === 0 ? data.length : Math.min(data.length, 6 + length);
40
40
  const pts = flags & 0x02 && data.length >= 14 ? readStamp(data, 9) : null;
41
41
  const dts = flags === 0x03 && data.length >= 19 ? readStamp(data, 14) : pts;
42
42
  return { pts, dts, data: data.subarray(start, end) };
43
43
  }
44
- /** 長さの分からない PES (映像) の入れ物の最初の大きさ。1 コマの多くはこれに収まる */
44
+ /** 長さの分からない PES (映像) のバッファの最初の大きさ。1 コマの多くはこれに収まる */
45
45
  const PES_START = 64 * 1024;
46
46
  /**
47
47
  * TS を渡すと PES を返す。**選局し直したら作り直す** (前の局の切れ端を持ち越さない)。
48
48
  *
49
- * 映像は長さ 0 (次の頭で終わりが分かる) なので 1 枚ぶん遅れて出るが、貯めの中に収まる。
49
+ * 映像は長さ 0 (次の PES の先頭で終わりが分かる) なので 1 フレームぶん遅れて出るが、受け側が貯めるぶんに収まる。
50
50
  * 音声は長さが書いてあるので揃った時点で出す
51
51
  */
52
52
  export class PesDemuxer {
@@ -118,19 +118,19 @@ export class PesDemuxer {
118
118
  return;
119
119
  const payload = packet.subarray(offset);
120
120
  if (packet[1] & 0x40) {
121
- // 次の頭が来た。**長さ 0 の PES (映像) はここで終わりが分かる**
121
+ // 次の PES の先頭が来た。**長さ 0 の PES (映像) はここで終わりが分かる**
122
122
  this.finish(pid, kind, out);
123
123
  const expected = payload.length >= 6 ? 6 + u16(payload, 4) : 0;
124
- // 溜めるものは写す。パケットは届いた塊の上の窓で、塊は使い回される (psi.ts の PacketStream)
125
124
  const known = expected === 6 ? 0 : expected;
126
125
  // 長さが書いてあればちょうどの大きさ (音声はほぼこれ)、無ければ映像向けに大きめ
127
126
  const buffer = new Uint8Array(Math.max(known > 0 ? known : PES_START, payload.length));
127
+ // 溜めるものはコピーする。パケットは届いたチャンクの一部を指し、チャンクのバッファは使い回される (psi.ts の PacketStream)
128
128
  buffer.set(payload);
129
129
  this.partial.set(pid, { buffer, size: payload.length, expected: known });
130
130
  }
131
131
  else {
132
132
  const partial = this.partial.get(pid);
133
- // 頭を見ていない続きは捨てる (途中から受け取った)
133
+ // 先頭を見ていない続きは捨てる (途中から受け取った)
134
134
  if (partial === undefined)
135
135
  return;
136
136
  const end = partial.size + payload.length;
@@ -155,7 +155,7 @@ export class PesDemuxer {
155
155
  return;
156
156
  this.partial.delete(pid);
157
157
  // 余りが大きければ詰めて返す。返したものはキューに積まれたり worker へ送られたりするので、
158
- // 広げた入れ物の余り (最大で倍近く) まで抱えさせない
158
+ // 広げたバッファの余り (最大で倍近く) まで抱えさせない
159
159
  const { buffer, size } = partial;
160
160
  const parsed = parsePes(size * 1.25 < buffer.length
161
161
  ? buffer.slice(0, size)
@@ -173,14 +173,14 @@ export const ADTS_RATES = [
173
173
  /**
174
174
  * PES の中身を ADTS のコマに割る。**コマは PES をまたぐことがある**ので、余りは持ち越す。
175
175
  *
176
- * 時刻は PES の PTS を頭のコマに付け、続くコマには 1 コマぶんずつ足す。持ち越した
176
+ * 時刻は PES の PTS を先頭のコマに付け、続くコマには 1 コマぶんずつ足す。持ち越した
177
177
  * 余りから始まるコマは、前の続きの時刻になる
178
178
  */
179
179
  export class AdtsSplitter {
180
180
  rest = new Uint8Array(0);
181
181
  next = null;
182
182
  feed(data, pts) {
183
- // 余りが無いときだけ PES の時刻に合わせ直す (余りがあれば頭のコマはその続き)
183
+ // 余りが無いときだけ PES の時刻に合わせ直す (余りがあれば先頭のコマはその続き)
184
184
  if (pts !== null && this.rest.length === 0)
185
185
  this.next = pts;
186
186
  const buffer = this.rest.length === 0 ? data : concatBytes([this.rest, data]);
package/dist/psi.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * TS の土台 (パケットの切り出し・セクションの組み立て・PAT/PMT) と、局の一覧。
3
3
  * 局の一覧はチャンネルスキャンで「この物理チャンネルに何が入っているか」を知るために使い、
4
- * 読むのは NIT と SDT の 2 つ。
4
+ * 読むのは NIT と SDT の 2 つ。ケーブルでは、局の無い TS を見分けるのに PAT も読む (`ServiceReader`)。
5
5
  *
6
6
  * - NIT (PID 0x0010) … ネットワーク ID と、地上波ならリモコン番号。衛星はネットワークの全部の TS
7
7
  * (TSID・周波数・サービスの一覧) が載っている (`NitReader`)
@@ -17,14 +17,10 @@ export declare const SYNC = 71;
17
17
  export declare function packetPid(packet: Uint8Array): number;
18
18
  /** PAT。どの PID に PMT があるかを持つ。**入口はいつもここ** */
19
19
  export declare const PID_PAT = 0;
20
- export declare const PID_NIT = 16;
21
20
  export declare const PID_SDT = 17;
22
21
  export declare const TABLE_PAT = 0;
23
22
  export declare const TABLE_PMT = 2;
24
- export declare const TABLE_NIT_ACTUAL = 64;
25
- export declare const TABLE_NIT_OTHER = 65;
26
23
  export declare const TABLE_SDT_ACTUAL = 66;
27
- export declare const TABLE_SDT_OTHER = 70;
28
24
  /**
29
25
  * スキャンで残すサービス種別。Mirakurun のスキャンが通しているものと同じで、
30
26
  * ラジオ (0x02) とデータ (0xc0) も入る。映像の無いものを番組表に並べないのは
@@ -52,15 +48,16 @@ export interface TransportInfo {
52
48
  }
53
49
  export interface NetworkInfo {
54
50
  networkId: number;
51
+ /** 最初の TS のリモコン番号。地上波の NIT は自分の TS 1 つだけを載せる */
55
52
  remoteControlKeyId: number | null;
56
- transportStreams: TransportInfo[];
53
+ transportStreams: NetworkTransport[];
57
54
  }
58
55
  /**
59
56
  * PSI セクションを組み立てる。
60
57
  *
61
58
  * セクションは TS パケットをまたいで運ばれ、パケットの切れ目とは無関係な
62
59
  * 位置で終わる。payload_unit_start_indicator と pointer_field を見て
63
- * 頭を合わせ、section_length ぶん溜まったら 1 本として返す。
60
+ * 先頭を合わせ、section_length ぶん溜まったら 1 本として返す。
64
61
  */
65
62
  export declare class SectionAssembler {
66
63
  private readonly pid;
@@ -90,14 +87,14 @@ export declare function findSync(data: Uint8Array, from?: number, until?: number
90
87
  /**
91
88
  * 任意の長さで届くバイト列を 188 バイトのパケットに切り分ける。
92
89
  *
93
- * 頭が必ずパケットの先頭とは限らず、電波が弱いと途中で数バイト落ちる。
94
- * ずれたままだと**以降ずっと 1 パケットも読めなくなる**ので、頭が 0x47 でなければ
90
+ * 渡されたバイト列の先頭がパケットの先頭とは限らず、電波が弱いと途中で数バイト落ちる。
91
+ * ずれたままだと**以降ずっと 1 パケットも読めなくなる**ので、先頭が 0x47 でなければ
95
92
  * 取り直す。普段は先頭が 0x47 なので、探しに行くのはずれたときだけ。
96
93
  *
97
- * **出すパケットは渡された塊の上の窓** (写しではない。写すと録画の処理の 1/3 を食う)。
98
- * 塊の入れ物を使い回す呼び出し側がある
99
- * (denpa の `server/recorded-bml.ts`) ので、**次の `feed` より後まで持つなら写すこと**。
100
- * いまのパーサ (`SectionAssembler`・`PesDemuxer`) は溜めるときに写している
94
+ * **出すパケットは渡されたチャンクの一部を指す** (コピーではない。コピーすると録画の処理時間の 1/3 を使う)。
95
+ * チャンクのバッファを使い回す呼び出し側がある
96
+ * (denpa の `server/recorded-bml.ts`) ので、**次の `feed` より後まで持つならコピーすること**。
97
+ * いまのパーサ (`SectionAssembler`・`PesDemuxer`) は溜めるときにコピーしている
101
98
  */
102
99
  export declare class PacketStream {
103
100
  private rest;
@@ -136,10 +133,10 @@ export declare function pmtProgramInfo(section: Uint8Array): Uint8Array;
136
133
  /**
137
134
  * PMT の ES の並びを `[stream_type, PID, 記述子]` で返す。
138
135
  *
139
- * **`stream_type` では物を見分けられません。** データ放送も AIT もロゴも同じ
136
+ * **`stream_type` では中身を見分けられない。** データ放送も AIT もロゴも同じ
140
137
  * DSM-CC セクション (0x0D) を名乗るので、見分けるのは記述子のほう
141
- * (component_tag や application_signalling) です。だからここは**素通しで並べる
142
- * だけ**にして、選り分けは呼ぶ側に置いてあります。
138
+ * (component_tag や application_signalling)。だからここは**素通しで並べる
139
+ * だけ**にして、選り分けは呼ぶ側に置いてある。
143
140
  */
144
141
  export declare function pmtStreams(section: Uint8Array): Generator<[number, number, Uint8Array]>;
145
142
  /** PAT から `サービスID → PMT の PID`。サービス 0 は NIT なので飛ばす */
@@ -147,19 +144,10 @@ export declare function parsePat(section: Uint8Array): Map<number, number>;
147
144
  /**
148
145
  * SDT のサービスの並びを (service_id, 記述子の並び) に切り分ける。
149
146
  *
150
- * **読む側が 2 つある。** 局名 (`parseSdt`) とロゴの対応 (denpa の `ts/logo.ts`) で、
147
+ * **読む側が 2 つある。** 局名 (`sdtTransport`) とロゴの対応 (denpa の `ts/logo.ts`) で、
151
148
  * 欲しい記述子が違うだけで歩き方は同じ。並びの読み方をここ 1 箇所に置く。
152
149
  */
153
150
  export declare function sdtServices(section: Uint8Array): Generator<[number, Uint8Array]>;
154
- /** SDT からサービスの一覧を読む。自分の TS のものだけ */
155
- export declare function parseSdt(section: Uint8Array): TransportInfo | null;
156
- /**
157
- * SDT[other] からサービスの一覧を読む。**ほかの TS のもの。**
158
- *
159
- * 衛星は、どの TS にもネットワークのほかの TS の局名を流している (番組表の EIT[other] と同じ考え)。
160
- * 開いていない TS の局名をこれで知る。TS ごとに別のセクションで来るので、集めるのは `SdtReader`
161
- */
162
- export declare function parseSdtOther(section: Uint8Array): TransportInfo | null;
163
151
  /** 衛星の分配の記述子 (0x43)。どの周波数で流れているか */
164
152
  export interface SatelliteDelivery {
165
153
  kind: "satellite";
@@ -195,27 +183,9 @@ export type Delivery = SatelliteDelivery | TerrestrialDelivery;
195
183
  /** NIT の TS の 1 件。サービスの一覧に、どこで流れているかが付く */
196
184
  export interface NetworkTransport extends TransportInfo {
197
185
  delivery: Delivery | null;
198
- }
199
- /** NIT のセクション 1 つ。表は何本かのセクションに分かれて来るので、そろえるのは `NitReader` */
200
- export interface NitSection {
201
- /** NIT[other] (ほかのネットワークのもの) なら true */
202
- other: boolean;
203
- networkId: number;
204
- version: number;
205
- /** current_next_indicator。0 (これから使う表) のものは `NitReader` が読まない */
206
- current: boolean;
207
- sectionNumber: number;
208
- lastSectionNumber: number;
186
+ /** その TS のリモコン番号 (TS 情報記述子)。載せていなければ null */
209
187
  remoteControlKeyId: number | null;
210
- transportStreams: NetworkTransport[];
211
188
  }
212
- /** NIT のセクションを 1 つ読む。actual (0x40) と other (0x41) のどちらも */
213
- export declare function parseNitSection(section: Uint8Array): NitSection | null;
214
- /**
215
- * NIT からネットワーク ID とリモコン番号、他の TS の顔ぶれを読む。**セクション 1 つぶん。**
216
- * スキャンで「どのネットワークか」を知るにはこれで足りる。ネットワークの全部の TS が要るなら `NitReader`
217
- */
218
- export declare function parseNit(section: Uint8Array): NetworkInfo | null;
219
189
  /** そろった NIT。セクションをつないだもの */
220
190
  export interface Network {
221
191
  /** NIT[other] なら true */
@@ -292,13 +262,26 @@ export interface FoundService extends Service {
292
262
  * Mirakurun のスキャンと同じで、**両方**揃って初めてそのチャンネルを
293
263
  * 「受信できた」とみなす。SDT だけ取れても、どのネットワークのものか
294
264
  * 分からないと設定に書けない。
265
+ *
266
+ * **ケーブル (`requireNit: false`) は SDT[actual] だけで揃ったとみなす。** 1 つのネットワークが
267
+ * 地上波・BS の再送信と自主放送の TS をまとめて流していて、NIT は CATV のネットワークのもの
268
+ * (局の元の放送とは別)。どの放送の局かは SDT の original_network_id で分かる。
269
+ * NIT が先に来ていれば、その TS のリモコン番号だけを使う。
270
+ * PAT に局が 1 つも無い TS (データだけの TS) も揃ったとみなし、局は返さない (`empty`)
295
271
  */
296
272
  export declare class ServiceReader {
297
273
  private readonly nit;
298
274
  private readonly sdt;
275
+ private readonly pat;
299
276
  private readonly packets;
277
+ private readonly requireNit;
300
278
  network: NetworkInfo | null;
301
279
  transport: TransportInfo | null;
280
+ /** PAT に局が 1 つも無かった (`requireNit: false` のときだけ読む) */
281
+ empty: boolean;
282
+ constructor({ requireNit }?: {
283
+ requireNit?: boolean;
284
+ });
302
285
  get complete(): boolean;
303
286
  /** 任意の長さのバイト列を渡す。揃ったら true */
304
287
  feed(chunk: Uint8Array): boolean;