mirakurun
Version:
DVR Tuner Server for Japanese TV.
820 lines • 33.7 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const EventEmitter = require("eventemitter3");
const aribts_1 = require("@chinachu/aribts");
const common_1 = require("./common");
const log = __importStar(require("./log"));
const EPG_1 = __importDefault(require("./EPG"));
const status_1 = __importDefault(require("./status"));
const _1 = __importDefault(require("./_"));
const Program_1 = require("./Program");
const Service_1 = __importDefault(require("./Service"));
const PACKET_SIZE = 188;
const PROVIDE_PIDS = [
0x0000,
0x0001,
0x0010,
0x0011,
0x0012,
0x0013,
0x0014,
0x0023,
0x0024,
0x0028,
0x0029
];
const DSMCC_BLOCK_SIZE = 4066;
const LOGO_DATA_NAME_BS = Buffer.from("LOGO-05");
const LOGO_DATA_NAME_CS = Buffer.from("CS_LOGO-05");
class TSFilter extends EventEmitter {
streamInfo = {};
_output;
_provideServiceId;
_provideEventId;
_parseNIT = false;
_parseSDT = false;
_parseEIT = false;
_targetNetworkId;
_enableParseCDT = false;
_enableParseDSMCC = false;
_tsmfEnableTsmfSplit = false;
_tsmfSlotCounter = -1;
_tsmfRelativeStreamNumber = [];
_tsmfTsNumber = 0;
_parser = new aribts_1.TsStreamLite();
_epg;
_epgReady = false;
_epgState = {};
_packet = Buffer.allocUnsafeSlow(PACKET_SIZE).fill(0);
_offset = -1;
_buffer = [];
_patsec = Buffer.allocUnsafeSlow(PACKET_SIZE - 4 - 1).fill(0);
_patCRC = Buffer.allocUnsafeSlow(4).fill(0);
_closed = false;
_ready = true;
_providePids = null;
_parsePids = new Set();
_tsid = -1;
_serviceIds = new Set();
_parseServiceIds = new Set();
_pmtPid = -1;
_pmtTimer;
_streamTime = null;
_essMap = new Map();
_essEsPids = new Set();
_dlDataMap = new Map();
_logoDataTimer;
_provideEventLastDetectedAt = -1;
_provideEventTimeout = null;
_maxBufferBytesBeforeReady = (() => {
let bytes = _1.default.config.server.maxBufferBytesBeforeReady || 1024 * 1024 * 8;
bytes = bytes - bytes % PACKET_SIZE;
return Math.max(bytes, PACKET_SIZE);
})();
_eventEndTimeout = _1.default.config.server.eventEndTimeout || 1000;
constructor(options) {
super();
const enabletsmf = options.tsmfRelTs || 0;
if (enabletsmf !== 0) {
this._tsmfEnableTsmfSplit = true;
this._tsmfTsNumber = options.tsmfRelTs;
}
this._targetNetworkId = options.networkId || null;
this._provideServiceId = options.serviceId || null;
this._provideEventId = options.eventId || null;
if (this._provideServiceId !== null) {
this._providePids = new Set(PROVIDE_PIDS);
this._ready = false;
}
if (this._provideEventId !== null) {
this._ready = false;
const program = _1.default.program.get((0, Program_1.getProgramItemId)(this._targetNetworkId, this._provideServiceId, this._provideEventId));
if (program) {
let timeout = program.startAt + program.duration - Date.now();
if (program.duration === 1) {
timeout += 1000 * 60 * 3;
}
if (timeout < 0) {
timeout = 1000 * 60 * 3;
}
this._provideEventTimeout = setTimeout(() => this._observeProvideEvent(), timeout);
}
}
if (options.output) {
this._output = options.output;
this._output.once("finish", this._close.bind(this));
this._output.once("close", this._close.bind(this));
}
else {
this._provideServiceId = null;
this._provideEventId = null;
this._providePids = new Set();
this._ready = false;
}
if (options.parseNIT === true) {
this._parseNIT = true;
}
if (options.parseSDT === true) {
this._parseSDT = true;
}
if (options.parseEIT === true) {
this._parseEIT = true;
}
if (this._targetNetworkId) {
if (this._targetNetworkId === 4) {
this._enableParseDSMCC = true;
}
else {
this._enableParseCDT = true;
}
}
this._parser.on("pat", this._onPAT.bind(this));
this._parser.on("pmt", this._onPMT.bind(this));
this._parser.on("nit", this._onNIT.bind(this));
this._parser.on("sdt", this._onSDT.bind(this));
this._parser.on("eit", this._onEIT.bind(this));
this._parser.on("tot", this._onTOT.bind(this));
this.once("end", this._close.bind(this));
this.once("close", this._close.bind(this));
log.info("TSFilter: created (serviceId=%d, eventId=%d)", this._provideServiceId, this._provideEventId);
if (this._ready === false) {
log.info("TSFilter: waiting for serviceId=%d, eventId=%d", this._provideServiceId, this._provideEventId);
}
++status_1.default.streamCount.tsFilter;
}
get closed() {
return this._closed;
}
write(chunk) {
if (this._closed) {
throw new Error("TSFilter has closed already");
}
let offset = 0;
const length = chunk.length;
const packets = [];
if (this._offset > 0) {
if (length >= PACKET_SIZE - this._offset) {
offset = PACKET_SIZE - this._offset;
packets.push(Buffer.concat([
this._packet.slice(0, this._offset),
chunk.slice(0, offset)
]));
this._offset = 0;
}
else {
chunk.copy(this._packet, this._offset);
this._offset += length;
return;
}
}
for (; offset < length; offset += PACKET_SIZE) {
if (chunk[offset] !== 71) {
offset -= PACKET_SIZE - 1;
continue;
}
if (length - offset >= PACKET_SIZE) {
packets.push(chunk.slice(offset, offset + PACKET_SIZE));
}
else {
chunk.copy(this._packet, 0, offset);
this._offset = length - offset;
}
}
this._processPackets(packets);
if (this._buffer.length !== 0) {
if (this._ready && this._output.writableLength < this._output.writableHighWaterMark) {
this._output.write(Buffer.concat(this._buffer));
this._buffer.length = 0;
}
else {
const head = this._buffer.length - (this._maxBufferBytesBeforeReady / PACKET_SIZE);
if (head > 0) {
this._buffer.splice(0, head);
}
}
}
}
end() {
this._close();
}
close() {
this._close();
}
_processPackets(packets) {
const parsingBuffers = [];
for (let packet of packets) {
const pid = packet.readUInt16BE(1) & 0x1FFF;
if (this._tsmfEnableTsmfSplit) {
if (pid === 0x002F) {
const tsmfFlameSync = packet.readUInt16BE(4) & 0x1FFF;
if (tsmfFlameSync !== 0x1A86 && tsmfFlameSync !== 0x0579) {
continue;
}
this._tsmfRelativeStreamNumber = [];
for (let i = 0; i < 26; i++) {
this._tsmfRelativeStreamNumber.push((packet[73 + i] & 0xf0) >> 4);
this._tsmfRelativeStreamNumber.push(packet[73 + i] & 0x0f);
}
this._tsmfSlotCounter = 0;
continue;
}
if (this._tsmfSlotCounter < 0 || this._tsmfSlotCounter > 51) {
continue;
}
this._tsmfSlotCounter++;
if (this._tsmfRelativeStreamNumber[this._tsmfSlotCounter - 1] !== this._tsmfTsNumber) {
continue;
}
}
if (pid === 0x1FFF) {
continue;
}
if ((packet[1] & 0x80) >> 7 === 1) {
if (this.streamInfo[pid]) {
++this.streamInfo[pid].drop;
}
continue;
}
if (pid === 0) {
const targetStart = packet[7] + 4;
if (targetStart + 4 > 188) {
if (this.streamInfo[pid]) {
++this.streamInfo[pid].drop;
}
continue;
}
if (this._patCRC.compare(packet, targetStart, targetStart + 4) !== 0) {
packet.copy(this._patCRC, 0, targetStart, targetStart + 4);
parsingBuffers.push(packet);
}
}
else if ((pid === 0x12 && (this._parseEIT || this._provideEventId !== null)) ||
pid === 0x14 ||
this._parsePids.has(pid)) {
parsingBuffers.push(packet);
}
if (this._ready === false && (pid === 0x12 || this._provideEventId === null)) {
continue;
}
if (this._providePids !== null && this._providePids.has(pid) === false) {
continue;
}
if (pid === 0 && this._pmtPid !== -1) {
packet = Buffer.from(packet);
this._patsec.copy(packet, 5, 0);
}
if (this.streamInfo[pid] === undefined) {
this.streamInfo[pid] = {
packet: 0,
drop: 0
};
}
++this.streamInfo[pid].packet;
this._buffer.push(packet);
}
if (parsingBuffers.length !== 0) {
setImmediate(() => {
if (this._closed) {
return;
}
this._parser.write(parsingBuffers);
parsingBuffers.length = 0;
});
}
}
_onPAT(pid, data) {
this._tsid = data.transport_stream_id;
this._serviceIds = new Set();
this._parseServiceIds = new Set();
for (const program of data.programs) {
const serviceId = program.program_number;
if (serviceId === 0) {
const NIT_PID = program.network_PID;
log.debug("TSFilter#_onPAT: detected NIT PID=%d", NIT_PID);
if (this._parseNIT) {
this._parsePids.add(NIT_PID);
}
continue;
}
if ((this._targetNetworkId === 4 && serviceId === 929)) {
const essPmtPid = program.program_map_PID;
this._essMap.set(serviceId, essPmtPid);
log.debug("TSFilter#_onPAT: detected ESS PMT PID=%d as serviceId=%d", essPmtPid, serviceId);
continue;
}
this._serviceIds.add(serviceId);
const item = this._targetNetworkId === null ? null : _1.default.service.get(this._targetNetworkId, serviceId);
log.debug("TSFilter#_onPAT: detected PMT PID=%d as serviceId=%d (%s)", program.program_map_PID, serviceId, item ? item.name : "unregistered");
if (serviceId === this._provideServiceId) {
if (this._pmtPid !== program.program_map_PID) {
this._pmtPid = program.program_map_PID;
if (this._providePids.has(this._pmtPid) === false) {
this._providePids.add(this._pmtPid);
}
if (this._parsePids.has(this._pmtPid) === false) {
this._parsePids.add(this._pmtPid);
}
data._raw.copy(this._patsec, 0, 0, 8);
this._patsec[2] = 17;
this._patsec[8] = 0;
this._patsec[9] = 0;
this._patsec[10] = 224;
this._patsec[11] = 16;
this._patsec[12] = serviceId >> 8;
this._patsec[13] = serviceId & 255;
this._patsec[14] = (this._pmtPid >> 8) + 224;
this._patsec[15] = this._pmtPid & 255;
this._patsec.writeInt32BE(aribts_1.TsCrc32.calc(this._patsec.slice(0, 16)), 16);
this._patsec.fill(0xff, 20);
}
}
if (this._parseEIT && item) {
for (const service of _1.default.service.findByNetworkId(this._targetNetworkId)) {
if (this._parseServiceIds.has(service.serviceId) === false) {
this._parseServiceIds.add(service.serviceId);
log.debug("TSFilter#_onPAT: parsing serviceId=%d (%s)", service.serviceId, service.name);
}
}
}
}
if (this._parseSDT) {
if (this._parsePids.has(0x11) === false) {
this._parsePids.add(0x11);
}
}
}
_onPMT(pid, data) {
if (this._essMap.has(data.program_number)) {
for (const stream of data.streams) {
for (const descriptor of stream.ES_info) {
if (descriptor.descriptor_tag === 0x52) {
if (descriptor.component_tag === 0x79 ||
descriptor.component_tag === 0x7A) {
this._parsePids.add(stream.elementary_PID);
this._essEsPids.add(stream.elementary_PID);
log.debug("TSFilter#_onPMT: detected ESS ES PID=%d", stream.elementary_PID);
break;
}
}
}
}
this._parsePids.delete(pid);
return;
}
if (this._ready === false && this._provideServiceId !== null && this._provideEventId === null) {
this._ready = true;
log.info("TSFilter#_onPMT: now ready for serviceId=%d", this._provideServiceId);
}
if (data.program_info[0]) {
this._providePids.add(data.program_info[0].CA_PID);
}
this._providePids.add(data.PCR_PID);
for (const stream of data.streams) {
this._providePids.add(stream.elementary_PID);
}
if (this._parsePids.has(pid)) {
this._parsePids.delete(pid);
this._pmtTimer = setTimeout(() => {
this._parsePids.add(pid);
}, 1000);
}
}
_onNIT(pid, data) {
const _network = {
networkId: data.network_id,
areaCode: -1,
remoteControlKeyId: -1
};
if (data.transport_streams[0]) {
for (const desc of data.transport_streams[0].transport_descriptors) {
switch (desc.descriptor_tag) {
case 0xFA:
_network.areaCode = desc.area_code;
break;
case 0xCD:
_network.remoteControlKeyId = desc.remote_control_key_id;
break;
}
}
}
this.emit("network", _network);
if (this._parsePids.has(pid)) {
this._parsePids.delete(pid);
}
}
_onSDT(pid, data) {
if (this._tsid !== data.transport_stream_id) {
return;
}
const _services = [];
for (const service of data.services) {
if (this._serviceIds.has(service.service_id) === false) {
continue;
}
let name = "";
let type = -1;
let logoId = -1;
const m = service.descriptors.length;
for (let j = 0; j < m; j++) {
if (service.descriptors[j].descriptor_tag === 0x48) {
name = new aribts_1.TsChar(service.descriptors[j].service_name_char).decode();
type = service.descriptors[j].service_type;
}
if (service.descriptors[j].descriptor_tag === 0xCF) {
logoId = service.descriptors[j].logo_id;
}
if (name !== "" && logoId !== -1) {
break;
}
}
if (_services.some(_service => _service.id === service.service_id) === false) {
_services.push({
networkId: data.original_network_id,
serviceId: service.service_id,
name: name,
type: type,
logoId: logoId
});
}
}
this.emit("services", _services);
if (this._parsePids.has(pid)) {
this._parsePids.delete(pid);
}
}
_onEIT(pid, data) {
if (this._pmtPid !== -1 &&
data.events.length !== 0 &&
this._provideEventId !== null && data.table_id === 0x4E && data.section_number === 0 &&
this._provideServiceId === data.service_id) {
if (data.events[0].event_id === this._provideEventId) {
this._provideEventLastDetectedAt = Date.now();
if (this._ready === false) {
this._ready = true;
log.info("TSFilter#_onEIT: now ready for eventId=%d", this._provideEventId);
}
}
else {
if (this._ready) {
log.info("TSFilter#_onEIT: closing because eventId=%d has ended...", this._provideEventId);
const eventId = this._provideEventId;
this._provideEventId = null;
setTimeout(() => {
this._ready = false;
this._provideEventId = eventId;
this._close();
}, this._eventEndTimeout);
}
}
}
if (this._parseEIT &&
this._parseServiceIds.has(data.service_id)) {
if (!this._epg && status_1.default.epg[this._targetNetworkId] !== true) {
status_1.default.epg[this._targetNetworkId] = true;
this._epg = new EPG_1.default();
this._standbyLogoData();
}
if (this._epg) {
this._epg.write(data);
if (!this._epgReady && data.table_id !== 0x4E && data.table_id !== 0x4F) {
this._updateEpgState(data);
}
}
}
}
_onTOT(pid, data) {
this._streamTime = (0, common_1.getTimeFromMJD)(data.JST_time);
}
_onCDT(pid, data) {
if (data.data_type === 0x01) {
const dataModule = new aribts_1.tsDataModule.TsDataModuleCdtLogo(data.data_module_byte).decode();
if (dataModule.logo_type !== 0x05) {
return;
}
log.debug("TSFilter#_onCDT: received logo data (networkId=%d, logoId=%d)", data.original_network_id, dataModule.logo_id);
const logoData = aribts_1.TsLogo.decode(dataModule.data_byte);
Service_1.default.saveLogoData(data.original_network_id, dataModule.logo_id, logoData);
}
}
_onDSMCC(pid, data) {
if (data.table_id === 0x3C) {
const ddb = data.message;
const downloadId = ddb.downloadId;
const moduleId = ddb.moduleId;
const dl = this._dlDataMap.get(downloadId);
if (!dl || dl.moduleId !== moduleId || !dl.data) {
return;
}
const moduleVersion = ddb.moduleVersion;
if (dl.moduleVersion !== moduleVersion) {
this._dlDataMap.delete(downloadId);
return;
}
const blockNumber = ddb.blockNumber;
const blockDataByte = ddb.blockDataByte;
blockDataByte.copy(dl.data, DSMCC_BLOCK_SIZE * blockNumber);
dl.loadedBytes += blockDataByte.length;
log.debug("TSFilter#_onDSMCC: detected DDB and logo data downloading... (downloadId=%d, %d/%d bytes)", downloadId, dl.loadedBytes, dl.moduleSize);
if (dl.loadedBytes !== dl.moduleSize) {
return;
}
const dlData = dl.data;
delete dl.data;
const dataModule = new aribts_1.tsDataModule.TsDataModuleLogo(dlData).decode();
for (const logo of dataModule.logos) {
for (const logoService of logo.services) {
const service = _1.default.service.get(logoService.original_network_id, logoService.service_id);
if (!service) {
continue;
}
service.logoId = logo.logo_id;
log.debug("TSFilter#_onDSMCC: received logo data (networkId=%d, logoId=%d)", service.networkId, service.logoId);
const logoData = new aribts_1.TsLogo(logo.data_byte).decode();
Service_1.default.saveLogoData(service.networkId, service.logoId, logoData);
break;
}
}
}
else if (data.table_id === 0x3B) {
const dii = data.message;
if (this._dlDataMap.has(dii.downloadId)) {
return;
}
for (const module of dii.modules) {
for (const descriptor of module.moduleInfo) {
if (descriptor.descriptor_tag !== 0x02) {
continue;
}
if (!LOGO_DATA_NAME_BS.equals(descriptor.text_char) &&
!LOGO_DATA_NAME_CS.equals(descriptor.text_char)) {
continue;
}
this._dlDataMap.set(dii.downloadId, {
downloadId: dii.downloadId,
moduleId: module.moduleId,
moduleVersion: module.moduleVersion,
moduleSize: module.moduleSize,
loadedBytes: 0,
data: Buffer.allocUnsafeSlow(module.moduleSize).fill(0)
});
log.debug("TSFilter#_onDSMCC: detected DII and buffer allocated for logo data (downloadId=%d, %d bytes)", dii.downloadId, module.moduleSize);
break;
}
}
}
}
_observeProvideEvent() {
if (Date.now() - this._provideEventLastDetectedAt < 10000) {
this._provideEventTimeout = setTimeout(() => this._observeProvideEvent(), 3000);
return;
}
log.warn("TSFilter#_observeProvideEvent: closing because EIT p/f timed out for eventId=%d...", this._provideEventId);
this._close();
}
async _standbyLogoData() {
if (this._closed) {
return;
}
if (this._logoDataTimer) {
return;
}
if (this._enableParseDSMCC && this._essMap.size === 0) {
return;
}
const targetServices = [];
if (this._provideServiceId === null) {
targetServices.push(..._1.default.service.findByNetworkId(this._targetNetworkId));
}
else if (this._enableParseCDT) {
targetServices.push(_1.default.service.get(this._targetNetworkId, this._provideServiceId));
}
else if (this._enableParseDSMCC && this._targetNetworkId === 4) {
targetServices.push(..._1.default.service.findByNetworkId(4), ..._1.default.service.findByNetworkId(6), ..._1.default.service.findByNetworkId(7));
}
const logoIdNetworkMap = {};
for (const service of targetServices) {
if (typeof service.logoId === "number") {
if (!logoIdNetworkMap[service.networkId]) {
logoIdNetworkMap[service.networkId] = new Set();
}
logoIdNetworkMap[service.networkId].add(service.logoId);
}
}
const now = Date.now();
const logoDataInterval = _1.default.config.server.logoDataInterval || 1000 * 60 * 60 * 24 * 7;
for (const networkId in logoIdNetworkMap) {
for (const logoId of logoIdNetworkMap[networkId]) {
if (logoId === -1 && logoIdNetworkMap[networkId].size > 1) {
continue;
}
if (now - await Service_1.default.getLogoDataMTime(this._targetNetworkId, logoId) > logoDataInterval) {
if (this._closed) {
return;
}
if (this._enableParseCDT) {
if (logoId >= 0) {
this._parsePids.add(0x29);
}
this._parser.on("cdt", this._onCDT.bind(this));
this._logoDataTimer = setTimeout(() => {
this._parsePids.delete(0x29);
this._parser.removeAllListeners("cdt");
log.info("TSFilter#_standbyLogoData: stopped waiting for logo data (networkId=%d, logoId=%d)", this._targetNetworkId, logoId);
}, 1000 * 60 * 30);
log.info("TSFilter#_standbyLogoData: waiting for logo data for 30 minutes... (networkId=%d, logoId=%d)", this._targetNetworkId, logoId);
}
else if (this._enableParseDSMCC) {
for (const essPmtPid of this._essMap.values()) {
this._parsePids.add(essPmtPid);
}
this._parser.on("dsmcc", this._onDSMCC.bind(this));
this._logoDataTimer = setTimeout(() => {
delete this._logoDataTimer;
for (const essEsPid of this._essEsPids.values()) {
this._parsePids.delete(essEsPid);
}
this._parser.removeAllListeners("dsmcc");
log.info("TSFilter#_standbyLogoData: stopped waiting for logo data (networkId=[4,6,7])");
}, 1000 * 60 * 30);
log.info("TSFilter#_standbyLogoData: waiting for logo data for 30 minutes... (networkId=[4,6,7])");
}
return;
}
}
}
}
_updateEpgState(data) {
const networkId = data.original_network_id;
const serviceId = data.service_id;
const versionNumber = data.version_number;
const stateByNet = this._epgState[networkId] || (this._epgState[networkId] = {});
let stateBySrv = stateByNet[serviceId];
if (!stateByNet[serviceId]) {
stateBySrv = stateByNet[serviceId] = {
basic: {
flags: [],
lastFlagsId: -1
},
extended: {
flags: [],
lastFlagsId: -1
}
};
for (let i = 0; i < 0x08; i++) {
for (const target of [stateBySrv.basic, stateBySrv.extended]) {
target.flags.push({
flag: Buffer.allocUnsafeSlow(32).fill(0x00),
ignore: Buffer.allocUnsafeSlow(32).fill(0xFF),
version_number: -1
});
}
}
}
const flagsId = data.table_id & 0x07;
const lastFlagsId = data.last_table_id & 0x07;
const segmentNumber = data.section_number >> 3;
const lastSegmentNumber = data.last_section_number >> 3;
const sectionNumber = data.section_number & 0x07;
const segmentLastSectionNumber = data.segment_last_section_number & 0x07;
const targetFlags = (data.table_id & 0x0F) < 0x08 ? stateBySrv.basic : stateBySrv.extended;
const targetFlag = targetFlags.flags[flagsId];
if ((targetFlags.lastFlagsId !== lastFlagsId) ||
(targetFlag.version_number !== -1 && targetFlag.version_number !== versionNumber)) {
if (targetFlag.version_number !== -1) {
const verDiff = versionNumber - targetFlag.version_number;
if (verDiff === -1 || verDiff > 1) {
return;
}
}
for (let i = 0; i < 0x08; i++) {
targetFlags.flags[i].flag.fill(0x00);
targetFlags.flags[i].ignore.fill(i <= lastFlagsId ? 0x00 : 0xFF);
}
}
if (flagsId === 0 && this._streamTime !== null) {
const segment = (this._streamTime + 9 * 60 * 60 * 1000) / (3 * 60 * 60 * 1000) & 0x07;
for (let i = 0; i < segment; i++) {
targetFlag.ignore[i] = 0xFF;
}
}
for (let i = lastSegmentNumber + 1; i < 0x20; i++) {
targetFlag.ignore[i] = 0xFF;
}
for (let i = segmentLastSectionNumber + 1; i < 8; i++) {
targetFlag.ignore[segmentNumber] |= 1 << i;
}
targetFlag.flag[segmentNumber] |= 1 << sectionNumber;
targetFlags.lastFlagsId = lastFlagsId;
targetFlag.version_number = versionNumber;
let ready = true;
isReady: for (const nid in this._epgState) {
for (const sid in this._epgState[nid]) {
for (const table of this._epgState[nid][sid].basic.flags.concat(this._epgState[nid][sid].extended.flags)) {
for (let i = 0; i < table.flag.length; i++) {
if ((table.flag[i] | table.ignore[i]) !== 0xFF) {
ready = false;
break isReady;
}
}
}
}
}
if (ready === true) {
this._epgReady = true;
this._clearEpgState();
for (const service of _1.default.service.findByNetworkId(this._targetNetworkId)) {
service.epgReady = true;
}
process.nextTick(() => this.emit("epgReady"));
}
}
_clearEpgState() {
if (!this._epgState) {
return;
}
for (const nid in this._epgState) {
delete this._epgState[nid];
}
}
_close() {
if (this._closed) {
return;
}
this._closed = true;
clearTimeout(this._pmtTimer);
clearTimeout(this._provideEventTimeout);
clearTimeout(this._logoDataTimer);
setImmediate(() => {
delete this._packet;
delete this._buffer;
delete this._patsec;
delete this._patCRC;
});
this._parser.removeAllListeners();
this._parser.end();
delete this._parser;
if (this._epg) {
this._epg.end();
delete this._epg;
status_1.default.epg[this._targetNetworkId] = false;
if (this._epgReady === true) {
const now = Date.now();
for (const service of _1.default.service.findByNetworkId(this._targetNetworkId)) {
service.epgUpdatedAt = now;
}
}
this._clearEpgState();
delete this._epgState;
}
if (this._output) {
if (this._output.writableEnded === false) {
this._output.end();
}
this._output.removeAllListeners();
delete this._output;
}
delete this.streamInfo;
--status_1.default.streamCount.tsFilter;
log.info("TSFilter#_close: closed (serviceId=%s, eventId=%s)", this._provideServiceId, this._provideEventId);
this.emit("close");
this.emit("end");
}
}
exports.default = TSFilter;
//# sourceMappingURL=TSFilter.js.map