/* * $Id: getservices.cpp,v 1.84 2003/12/09 21:12:28 thegoodguy Exp $ * * (C) 2002, 2003 by Andreas Oberritter * * (C) 2007-2009, 2013 Stefan Seyfried * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include #include #include #include #include #include #include #include #include //#define SAVE_DEBUG extern transponder_list_t transponders; CServiceManager * CServiceManager::manager = NULL; CServiceManager::CServiceManager() { scanInputParser = NULL; service_count = 0; services_changed = false; keep_numbers = false; } CServiceManager::~CServiceManager() { delete scanInputParser; transponders.clear(); } CServiceManager * CServiceManager::getInstance() { if(manager == NULL) manager = new CServiceManager(); return manager; } bool CServiceManager::ParseScanXml(fe_type_t delsys) { if(scanInputParser) { delete scanInputParser; scanInputParser = NULL; } //frontendType = CFEManager::getInstance()->getLiveFE()->getInfo()->type; switch (delsys) { case FE_QPSK: scanInputParser = parseXmlFile(SATELLITES_XML); break; case FE_QAM: scanInputParser = parseXmlFile(CABLES_XML); break; case FE_OFDM: scanInputParser = parseXmlFile(TERRESTRIAL_XML); break; default: WARN("Unknown type %d", frontendType); return false; } return (scanInputParser != NULL); } #if 0 //never used xmlDocPtr CServiceManager::ScanXml() { if(!scanInputParser) ParseScanXml(); return scanInputParser; } #endif bool CServiceManager::AddChannel(CZapitChannel * &channel) { channel_insert_res_t ret = allchans.insert ( channel_pair_t (channel->getChannelID(), *channel)); delete channel; channel = &ret.first->second; if(ret.second) services_changed = true; return ret.second; } bool CServiceManager::AddCurrentChannel(CZapitChannel * &channel) { channel_insert_res_t ret = curchans.insert ( channel_pair_t (channel->getChannelID(), *channel)); delete channel; channel = &ret.first->second; return ret.second; } bool CServiceManager::AddNVODChannel(CZapitChannel * &channel) { t_service_id service_id = channel->getServiceId(); t_original_network_id original_network_id = channel->getOriginalNetworkId(); t_transport_stream_id transport_stream_id = channel->getTransportStreamId(); t_satellite_position satellitePosition = channel->getSatellitePosition(); //FIXME define CREATE_NVOD_CHANNEL_ID t_channel_id sub_channel_id = ((uint64_t) ( satellitePosition >= 0 ? satellitePosition : (uint64_t)(0xF000+ abs(satellitePosition))) << 48) | (uint64_t) CREATE_CHANNEL_ID(service_id, original_network_id, transport_stream_id); channel_insert_res_t ret = nvodchannels.insert ( channel_pair_t (sub_channel_id, *channel)); delete channel; channel = &ret.first->second; return ret.second; } void CServiceManager::ResetChannelNumbers(bool bouquets, bool numbers) { for (channel_map_iterator_t it = allchans.begin(); it != allchans.end(); ++it) { #if 0 /* force to get free numbers if there are any */ if(have_numbers) { if(!it->second.number) { it->second.number = GetFreeNumber(it->second.getServiceType() == ST_DIGITAL_RADIO_SOUND_SERVICE); } } else { it->second.number = 0; } #endif if(!keep_numbers || numbers) it->second.number = 0; if(bouquets) it->second.has_bouquet = 0; } if(numbers) { tv_numbers.clear(); radio_numbers.clear(); } } void CServiceManager::RemoveChannel(const t_channel_id channel_id) { allchans.erase(channel_id); services_changed = true; } void CServiceManager::RemoveAllChannels() { allchans.clear(); } void CServiceManager::RemovePosition(t_satellite_position satellitePosition) { INFO("delete %d, size before: %d", satellitePosition, allchans.size()); t_channel_id live_id = CZapit::getInstance()->GetCurrentChannelID(); for (channel_map_iterator_t it = allchans.begin(); it != allchans.end();) { if (it->second.getSatellitePosition() == satellitePosition && live_id != it->first) allchans.erase(it++); else ++it; } services_changed = true; INFO("delete %d, size after: %d", satellitePosition, allchans.size()); } #if 0 //never used void CServiceManager::RemoveNVODChannels() { nvodchannels.clear(); } #endif void CServiceManager::RemoveCurrentChannels() { curchans.clear(); } CZapitChannel * CServiceManager::FindChannel(const t_channel_id channel_id, bool * current_is_nvod) { if(current_is_nvod) *current_is_nvod = false; channel_map_iterator_t cit = nvodchannels.find(channel_id); if (cit == nvodchannels.end()) { cit = allchans.find(channel_id); if (cit == allchans.end()) { //printf("%s: channel %llx not found\n", __FUNCTION__, channel_id); return NULL; } } else if(current_is_nvod) *current_is_nvod = true; return &cit->second; } CZapitChannel * CServiceManager::FindChannelByName(std::string name) { for (channel_map_iterator_t it = allchans.begin(); it != allchans.end(); ++it) { if(it->second.getName().length() == name.length() && !strcasecmp(it->second.getName().c_str(), name.c_str())) { return &it->second; } } return NULL; } CZapitChannel * CServiceManager::FindCurrentChannel(const t_channel_id channel_id) { channel_map_iterator_t cit = curchans.find(channel_id); if(cit != curchans.end()) return &cit->second; return NULL; } CZapitChannel * CServiceManager::FindChannel48(const t_channel_id channel_id) { for (channel_map_iterator_t it = allchans.begin(); it != allchans.end(); ++it) { if((it->second.getChannelID() & 0xFFFFFFFFFFFFULL) == (channel_id & 0xFFFFFFFFFFFFULL)) return &it->second; } return NULL; } /* TODO: those FindChannel* functions are naive at best. By using a different construction * scheme for the channel_id,they could easily be made much more efficient. Side effects would * need to be checked first, though */ CZapitChannel* CServiceManager::FindChannelFuzzy(const t_channel_id channel_id, const t_satellite_position pos, const freq_id_t freq) { for (channel_map_iterator_t it = allchans.begin(); it != allchans.end(); ++it) { CZapitChannel *ret = &it->second; if ((ret->getChannelID() & 0xFFFFFFFFFFFFULL) != (channel_id & 0xFFFFFFFFFFFFULL)) continue; /* use position only on SAT boxes. * Cable/terr does not need thix: There usually is no second cable provider * to choose from and people are wondering why their ubouquets are no longer * working => because they had the wrong 's="x"' attribute. * TODO: think about mixed-mode (sat/cable/terrestrial) operation */ if (ret->deltype == FE_QPSK && pos != ret->getSatellitePosition()) continue; /* match +-2MHz to make old ubouquets work with updated satellites.xml */ if (abs((int)ret->getFreqId() - (int)freq) < 3) return ret; } return NULL; } bool CServiceManager::GetAllRadioChannels(ZapitChannelList &list, int flags) { list.clear(); for (channel_map_iterator_t it = allchans.begin(); it != allchans.end(); ++it) { if (it->second.getServiceType() == ST_DIGITAL_RADIO_SOUND_SERVICE && (it->second.flags & flags)) list.push_back(&(it->second)); } return (!list.empty()); } bool CServiceManager::GetAllTvChannels(ZapitChannelList &list, int flags) { list.clear(); for (channel_map_iterator_t it = allchans.begin(); it != allchans.end(); ++it) { if (it->second.getServiceType() != ST_DIGITAL_RADIO_SOUND_SERVICE && (it->second.flags & flags)) list.push_back(&(it->second)); } return (!list.empty()); } bool CServiceManager::GetAllHDChannels(ZapitChannelList &list, int flags) { list.clear(); for (channel_map_iterator_t it = allchans.begin(); it != allchans.end(); ++it) { if ((it->second.flags & flags) && it->second.isHD()) list.push_back(&(it->second)); } return (!list.empty()); } bool CServiceManager::GetAllUnusedChannels(ZapitChannelList &list, int flags) { list.clear(); for (channel_map_iterator_t it = allchans.begin(); it != allchans.end(); ++it) { if ((it->second.flags & flags) && it->second.has_bouquet == false) list.push_back(&(it->second)); } return (!list.empty()); } bool CServiceManager::GetAllSatelliteChannels(ZapitChannelList &list, t_satellite_position position, int flags) { list.clear(); for (channel_map_iterator_t it = allchans.begin(); it != allchans.end(); ++it) { if((it->second.flags & flags) && it->second.getSatellitePosition() == position) list.push_back(&(it->second)); } return (!list.empty()); } bool CServiceManager::GetAllTransponderChannels(ZapitChannelList &list, transponder_id_t tpid, int flags) { list.clear(); for (channel_map_iterator_t it = allchans.begin(); it != allchans.end(); ++it) { if((it->second.flags & flags) && it->second.getTransponderId() == tpid) list.push_back(&(it->second)); } return (!list.empty()); } std::string CServiceManager::GetServiceName(t_channel_id channel_id) { channel_map_iterator_t it = allchans.find(channel_id); if (it != allchans.end()) return it->second.getName(); else return ""; } void CServiceManager::ParseTransponders(xmlNodePtr node, t_satellite_position satellitePosition, fe_type_t delsys) { uint8_t polarization = 0; /* read all transponders */ while ((node = xmlGetNextOccurence(node, "TS")) != NULL) { FrontendParameters feparams; t_transport_stream_id transport_stream_id = xmlGetNumericAttribute(node, "id", 16); t_original_network_id original_network_id = xmlGetNumericAttribute(node, "on", 16); feparams.dvb_feparams.frequency = xmlGetNumericAttribute(node, "frq", 0); feparams.dvb_feparams.inversion = (fe_spectral_inversion) xmlGetNumericAttribute(node, "inv", 0); switch (delsys) { case FE_OFDM: case FE_QAM: feparams.dvb_feparams.u.qam.symbol_rate = xmlGetNumericAttribute(node, "sr", 0); feparams.dvb_feparams.u.qam.fec_inner = (fe_code_rate_t) xmlGetNumericAttribute(node, "fec", 0); feparams.dvb_feparams.u.qam.modulation = (fe_modulation_t) xmlGetNumericAttribute(node, "mod", 0); if (feparams.dvb_feparams.frequency > 1000*1000) feparams.dvb_feparams.frequency = feparams.dvb_feparams.frequency/1000; //transponderlist was read from tuxbox break; default: feparams.dvb_feparams.u.qpsk.fec_inner = (fe_code_rate_t) xmlGetNumericAttribute(node, "fec", 0); feparams.dvb_feparams.u.qpsk.symbol_rate = xmlGetNumericAttribute(node, "sr", 0); polarization = xmlGetNumericAttribute(node, "pol", 0); if(feparams.dvb_feparams.u.qpsk.symbol_rate < 50000) feparams.dvb_feparams.u.qpsk.symbol_rate = feparams.dvb_feparams.u.qpsk.symbol_rate * 1000; if(feparams.dvb_feparams.frequency < 20000) feparams.dvb_feparams.frequency = feparams.dvb_feparams.frequency*1000; else feparams.dvb_feparams.frequency = (int) 1000 * (int) round ((double) feparams.dvb_feparams.frequency / (double) 1000); } freq_id_t freq = CREATE_FREQ_ID(feparams.dvb_feparams.frequency, delsys != FE_QPSK); transponder_id_t tid = CREATE_TRANSPONDER_ID64(freq, satellitePosition,original_network_id,transport_stream_id); transponder t(delsys, tid, feparams, polarization); pair::iterator,bool> ret; ret = transponders.insert(transponder_pair_t(tid, t)); if (ret.second == false) t.dump("[zapit] duplicate in all transponders:"); /* read channels that belong to the current transponder */ ParseChannels(node->xmlChildrenNode, transport_stream_id, original_network_id, satellitePosition, freq, polarization, delsys); /* hop to next transponder */ node = node->xmlNextNode; } UpdateSatTransponders(satellitePosition); return; } void CServiceManager::ParseChannels(xmlNodePtr node, const t_transport_stream_id transport_stream_id, const t_original_network_id original_network_id, t_satellite_position satellitePosition, freq_id_t freq, uint8_t polarization, fe_type_t delsys) { int dummy = 0; int * have_ptr = &dummy; sat_iterator_t sit = satellitePositions.find(satellitePosition); if(sit != satellitePositions.end()) have_ptr = &sit->second.have_channels; while ((node = xmlGetNextOccurence(node, "S")) != NULL) { *have_ptr = 1; t_service_id service_id = xmlGetNumericAttribute(node, "i", 16); std::string name = xmlGetAttribute(node, "n"); uint8_t service_type = xmlGetNumericAttribute(node, "t", 16); uint16_t vpid = xmlGetNumericAttribute(node, "v", 16); uint16_t apid = xmlGetNumericAttribute(node, "a", 16); uint16_t pcrpid = xmlGetNumericAttribute(node, "p", 16); uint16_t pmtpid = xmlGetNumericAttribute(node, "pmt", 16); uint16_t txpid = xmlGetNumericAttribute(node, "tx", 16); uint16_t vtype = xmlGetNumericAttribute(node, "vt", 16); uint16_t scrambled = xmlGetNumericAttribute(node, "s", 16); int number = xmlGetNumericAttribute(node, "num", 10); int flags = xmlGetNumericAttribute(node, "f", 10); /* default if no flags present */ if (flags == 0) flags = CZapitChannel::UPDATED; t_channel_id chid = CREATE_CHANNEL_ID64; char *ptr = xmlGetAttribute(node, "action"); bool remove = ptr ? (!strcmp(ptr, "remove") || !strcmp(ptr, "replace")) : false; bool add = ptr ? (!strcmp(ptr, "add") || !strcmp(ptr, "replace")) : true; if (remove) { int result = allchans.erase(chid); printf("[getservices]: %s '%s' (sid=0x%x): %s", add ? "replacing" : "removing", name.c_str(), service_id, result ? "succeded.\n" : "FAILED!\n"); if(!result && remove && add) add = false;//dont replace not existing channel } if(!add) { node = node->xmlNextNode; continue; } audio_map_set_t * pidmap = CZapit::getInstance()->GetSavedPids(chid); if(pidmap) apid = pidmap->apid; CZapitChannel * channel = new CZapitChannel(name, chid, service_type, satellitePosition, freq); channel->deltype = delsys; service_number_map_t * channel_numbers = (service_type == ST_DIGITAL_RADIO_SOUND_SERVICE) ? &radio_numbers : &tv_numbers; if(!keep_numbers) number = 0; if(number) { have_numbers = true; service_number_map_t::iterator it = channel_numbers->find(number); if(it != channel_numbers->end()) { printf("[zapit] duplicate channel number %d: %s id %" PRIx64 " freq %d\n", number, name.c_str(), chid, freq); number = 0; dup_numbers = true; // force save after loading } else channel_numbers->insert(number); } bool ret = AddChannel(channel); //printf("INS CHANNEL %s %x\n", name.c_str(), (int) &ret.first->second); if(ret == false) { printf("[zapit] duplicate channel %s id %" PRIx64 " freq %d (old %s at %d)\n", name.c_str(), chid, freq, channel->getName().c_str(), channel->getFreqId()); } else { service_count++; channel->number = number; channel->flags = flags; channel->scrambled = scrambled; channel->polarization = polarization; service_type = channel->getServiceType(); if(pmtpid != 0 && (((channel->getServiceType() == ST_DIGITAL_RADIO_SOUND_SERVICE) && (apid > 0)) || ( (channel->getServiceType() == ST_DIGITAL_TELEVISION_SERVICE) && (vpid > 0) && (apid > 0))) ) { DBG("[getserv] preset chan %s vpid %X sid %X tpid %X onid %X\n", name.c_str(), vpid, service_id, transport_stream_id, transport_stream_id); channel->setVideoPid(vpid); channel->setAudioPid(apid); channel->setPcrPid(pcrpid); channel->setPmtPid(pmtpid); channel->setTeletextPid(txpid); channel->setPidsFlag(); channel->type = vtype; } } node = node->xmlNextNode; } return; } void CServiceManager::FindTransponder(xmlNodePtr search) { while (search) { fe_type_t delsys = FE_QPSK; t_satellite_position satellitePosition = xmlGetSignedNumericAttribute(search, "position", 10); if (!(strcmp(xmlGetName(search), "cable"))) { delsys = FE_QAM; char * name = xmlGetAttribute(search, "name"); satellitePosition = GetSatellitePosition(name); } else if (!strcmp(xmlGetName(search), "terrestrial")) { delsys = FE_OFDM; char * name = xmlGetAttribute(search, "name"); satellitePosition = GetSatellitePosition(name); } else if ((strcmp(xmlGetName(search), "sat"))) { search = search->xmlNextNode; continue; } #if 0 //t_satellite_position satellitePosition = xmlGetSignedNumericAttribute(search, "position", 10); char * name = xmlGetAttribute(search, "name"); t_satellite_position satellitePosition = GetSatellitePosition(name); #endif DBG("going to parse dvb-%c provider %s\n", xmlGetName(search)[0], xmlGetAttribute(search, "name")); ParseTransponders(search->xmlChildrenNode, satellitePosition, delsys); newfound++; search = search->xmlNextNode; } } void CServiceManager::ParseSatTransponders(fe_type_t fType, xmlNodePtr search, t_satellite_position satellitePosition) { uint8_t polarization = 0; FrontendParameters feparams; fake_tid = fake_nid = 0; satelliteTransponders[satellitePosition].clear(); xmlNodePtr tps = search->xmlChildrenNode; while ((tps = xmlGetNextOccurence(tps, "transponder")) != NULL) { memset(&feparams, 0x00, sizeof(FrontendParameters)); feparams.dvb_feparams.frequency = xmlGetNumericAttribute(tps, "frequency", 0); feparams.dvb_feparams.inversion = INVERSION_AUTO; if (fType == FE_QAM) { feparams.dvb_feparams.u.qam.symbol_rate = xmlGetNumericAttribute(tps, "symbol_rate", 0); feparams.dvb_feparams.u.qam.fec_inner = (fe_code_rate_t) xmlGetNumericAttribute(tps, "fec_inner", 0); feparams.dvb_feparams.u.qam.modulation = (fe_modulation_t) xmlGetNumericAttribute(tps, "modulation", 0); if (feparams.dvb_feparams.frequency > 1000*1000) feparams.dvb_feparams.frequency=feparams.dvb_feparams.frequency/1000; //transponderlist was read from tuxbox } else if (fType == FE_QPSK) { feparams.dvb_feparams.u.qpsk.symbol_rate = xmlGetNumericAttribute(tps, "symbol_rate", 0); polarization = xmlGetNumericAttribute(tps, "polarization", 0); uint8_t system = xmlGetNumericAttribute(tps, "system", 0); uint8_t modulation = xmlGetNumericAttribute(tps, "modulation", 0); int xml_fec = xmlGetNumericAttribute(tps, "fec_inner", 0); xml_fec = CFrontend::getCodeRate(xml_fec, system); if(modulation == 2 && ((fe_code_rate_t) xml_fec != FEC_AUTO)) xml_fec += 9; feparams.dvb_feparams.u.qpsk.fec_inner = (fe_code_rate_t) xml_fec; feparams.dvb_feparams.frequency = (int) 1000 * (int) round ((double) feparams.dvb_feparams.frequency / (double) 1000); } else if (fType == FE_OFDM) { feparams.dvb_feparams.u.ofdm.bandwidth = (fe_bandwidth_t) xmlGetNumericAttribute(tps, "bandwidth", 0); feparams.dvb_feparams.u.ofdm.constellation = (fe_modulation_t) xmlGetNumericAttribute(tps, "constellation", 0); feparams.dvb_feparams.u.ofdm.transmission_mode = (fe_transmit_mode_t) xmlGetNumericAttribute(tps, "transmission_mode", 0); feparams.dvb_feparams.u.ofdm.code_rate_HP = (fe_code_rate_t) xmlGetNumericAttribute(tps, "code_rate_HP", 0); feparams.dvb_feparams.u.ofdm.code_rate_LP = (fe_code_rate_t) xmlGetNumericAttribute(tps, "code_rate_LP", 0); feparams.dvb_feparams.u.ofdm.guard_interval = (fe_guard_interval_t) xmlGetNumericAttribute(tps, "guard_interval", 0); feparams.dvb_feparams.u.ofdm.hierarchy_information = (fe_hierarchy_t) xmlGetNumericAttribute(tps, "hierarchy", 0); if (feparams.dvb_feparams.frequency > 1000*1000) feparams.dvb_feparams.frequency /= 1000; // old transponder list } else /* we'll probably crash sooner or later, so write to STDERR... */ fprintf(stderr, "[getservices] %s: unknown frontend type %d!\n", __func__, fType); freq_id_t freq = CREATE_FREQ_ID(feparams.dvb_feparams.frequency, fType != FE_QPSK); polarization &= 7; transponder_id_t tid = CREATE_TRANSPONDER_ID64(freq, satellitePosition, fake_nid, fake_tid); transponder t(fType, tid, feparams, polarization); satelliteTransponders[satellitePosition].insert(transponder_pair_t(tid, t)); fake_nid ++; fake_tid ++; tps = tps->xmlNextNode; } } int CServiceManager::LoadMotorPositions(void) { FILE *fd = NULL; char buffer[256] = ""; t_satellite_position satellitePosition; int spos = 0, mpos = 0, diseqc = 0, uncom = 0, com = 0, usals = 0, inuse, input = 0; int offH = 10600, offL = 9750, sw = 11700; printf("[getservices] loading motor positions...\n"); if ((fd = fopen(SATCONFIG, "r"))) { fgets(buffer, 255, fd); while(!feof(fd)) { sscanf(buffer, "%d %d %d %d %d %d %d %d %d %d %d", &spos, &mpos, &diseqc, &com, &uncom, &offL, &offH, &sw, &inuse, &usals, &input); satellitePosition = spos; sat_iterator_t sit = satellitePositions.find(satellitePosition); if(sit != satellitePositions.end()) { sit->second.diseqc = diseqc; sit->second.commited = com; sit->second.uncommited = uncom; sit->second.motor_position = mpos; sit->second.lnbOffsetLow = offL; sit->second.lnbOffsetHigh = offH; sit->second.lnbSwitch = sw; sit->second.use_in_scan = inuse; sit->second.use_usals = usals; sit->second.input = input; sit->second.position = satellitePosition; } fgets(buffer, 255, fd); } fclose(fd); } else printf("[getservices] %s not found.\n", SATCONFIG); return 0; } #if 0 //never used void CServiceManager::SaveMotorPositions() { FILE * fd; sat_iterator_t sit; printf("[getservices] saving motor positions...\n"); fd = fopen(SATCONFIG, "w"); if(fd == NULL) { printf("[zapit] cannot open %s\n", SATCONFIG); return; } fprintf(fd, "# sat position, stored rotor, diseqc, commited, uncommited, low, high, switch, use in full scan, use usals, input\n"); for(sit = satellitePositions.begin(); sit != satellitePositions.end(); ++sit) { fprintf(fd, "%d %d %d %d %d %d %d %d %d %d %d\n", sit->first, sit->second.motor_position, sit->second.diseqc, sit->second.commited, sit->second.uncommited, sit->second.lnbOffsetLow, sit->second.lnbOffsetHigh, sit->second.lnbSwitch, sit->second.use_in_scan, sit->second.use_usals, sit->second.input); } fdatasync(fileno(fd)); fclose(fd); } #endif bool CServiceManager::InitSatPosition(t_satellite_position position, char * name, bool force, int deltype) { if(force || (satellitePositions.find(position) == satellitePositions.end())) { satellitePositions[position].position = position; satellitePositions[position].diseqc = -1; satellitePositions[position].commited = -1; satellitePositions[position].uncommited = -1; satellitePositions[position].motor_position = 0; satellitePositions[position].diseqc_order = 0; satellitePositions[position].lnbOffsetLow = 9750; satellitePositions[position].lnbOffsetHigh = 10600; satellitePositions[position].lnbSwitch = 11700; satellitePositions[position].use_in_scan = 0; satellitePositions[position].use_usals = 0; satellitePositions[position].input = 0; satellitePositions[position].configured = 0; satellitePositions[position].cable_nid = 0; satellitePositions[position].deltype = deltype; if(name) satellitePositions[position].name = name; return true; } return false; } bool CServiceManager::LoadScanXml(fe_type_t delsys) { if (ParseScanXml(delsys)) { /* fake position for non-satellite */ t_satellite_position position = 0; xmlNodePtr search = xmlDocGetRootElement(scanInputParser)->xmlChildrenNode; while (search) { if (!(strcmp(xmlGetName(search), "sat"))) { position = xmlGetSignedNumericAttribute(search, "position", 10); char * name = xmlGetAttribute(search, "name"); InitSatPosition(position, name, false, delsys); } else if (!(strcmp(xmlGetName(search), "terrestrial"))) { char * name = xmlGetAttribute(search, "name"); position = fake_pos++; position &= 0x0EFF; InitSatPosition(position, name, false, delsys); } else if(!(strcmp(xmlGetName(search), "cable"))) { char * name = xmlGetAttribute(search, "name"); position = fake_pos++; InitSatPosition(position, name, false, delsys); satellitePositions[position].cable_nid = xmlGetNumericAttribute(search, "nid", 0); } ParseSatTransponders(delsys, search, position); search = search->xmlNextNode; } delete scanInputParser; scanInputParser = NULL; return true; } return false; } bool CServiceManager::LoadServices(bool only_current) { if(CFEManager::getInstance()->getLiveFE() == NULL) return false; xmlDocPtr parser; service_count = 0; printf("[zapit] Loading services, channel size %d ..\n", (int)sizeof(CZapitChannel)); //frontendType = CFEManager::getInstance()->getLiveFE()->getInfo()->type; if(only_current) goto do_current; #if 0 // FIXME: obsolete ? static bool satcleared = 0;//clear only once, because menu is static if(!satcleared) { satellitePositions.clear(); satcleared = 1; } #endif TIMER_START(); allchans.clear(); transponders.clear(); tv_numbers.clear(); radio_numbers.clear(); have_numbers = false; dup_numbers = false; fake_tid = fake_nid = 0; fake_pos = 0xF00; if (CFEManager::getInstance()->haveSat()) { INFO("Loading satellites..."); LoadScanXml(FE_QPSK); } if (CFEManager::getInstance()->haveCable()) { INFO("Loading cables..."); LoadScanXml(FE_QAM); } if (CFEManager::getInstance()->haveTerr()) { INFO("Loading terrestrial..."); LoadScanXml(FE_OFDM); } parser = parseXmlFile(SERVICES_XML); if (parser != NULL) { xmlNodePtr search = xmlDocGetRootElement(parser)->xmlChildrenNode; while (search) { char * name = xmlGetAttribute(search, "name"); t_satellite_position position; if (!(strcmp(xmlGetName(search), "sat"))) { position = xmlGetSignedNumericAttribute(search, "position", 10); InitSatPosition(position, name, false, FE_QPSK); } else if (!(strcmp(xmlGetName(search), "terrestrial"))) { position = GetSatellitePosition(name); if (!position) position = (0x0EFF & fake_pos++); InitSatPosition(position, name, false, FE_OFDM); } else { position = GetSatellitePosition(name); if (!position) position = fake_pos++; InitSatPosition(position, name, false, FE_QAM); } search = search->xmlNextNode; } FindTransponder(xmlDocGetRootElement(parser)->xmlChildrenNode); xmlFreeDoc(parser); } #if 0 if (CFEManager::getInstance()->haveSat()) { LoadMotorPositions(); } #endif LoadProviderMap(); printf("[zapit] %d services loaded (%d)...\n", service_count, (int)allchans.size()); TIMER_STOP("[zapit] service loading took"); if(zapit_debug) {//FIXME sat_iterator_t sit; for(sit = satellitePositions.begin(); sit != satellitePositions.end(); ++sit) printf("satelliteName = %s (%d), satellitePosition = %d motor position = %d usals %d\n", sit->second.name.c_str(), (int)sit->second.name.size(), sit->first, sit->second.motor_position, sit->second.use_usals); } /* reset flag after loading services.xml */ services_changed = false; do_current: #if 0 DBG("Loading current..\n"); if (CZapit::getInstance()->scanSDT() && (parser = parseXmlFile(CURRENTSERVICES_XML))) { newfound = 0; printf("[getservices] " CURRENTSERVICES_XML " found.\n"); FindTransponder(xmlDocGetRootElement(parser)->xmlChildrenNode); xmlFreeDoc(parser); unlink(CURRENTSERVICES_XML); if(newfound) { //SaveServices(true); services_changed = true; } } #endif if(!only_current) { parser = parseXmlFile(MYSERVICES_XML); if (parser != NULL) { FindTransponder(xmlDocGetRootElement(parser)->xmlChildrenNode); xmlFreeDoc(parser); } } /* if no numbers, zapit will save after loading bouquets, with numbers */ if(service_count && keep_numbers && (!have_numbers || dup_numbers)) services_changed = true; return true; } void CServiceManager::CopyFile(char * from, char * to) { char cmd[256] = "cp -f "; strcat(cmd, from); strcat(cmd, " "); strcat(cmd, to); system(cmd); sync(); } void CServiceManager::WriteSatHeader(FILE * fd, sat_config_t &config) { /* FIXME hack */ if (SAT_POSITION_CABLE(config.position)) config.deltype = FE_QAM; else if (SAT_POSITION_TERR(config.position)) config.deltype = FE_OFDM; switch (config.deltype) { case FE_QPSK: /* satellite */ fprintf(fd, "\t\n", config.name.c_str(), config.position, config.diseqc, config.uncommited); break; case FE_QAM: /* cable */ fprintf(fd, "\t\n", config.name.c_str(), config.position); break; case FE_OFDM: /* terrestrial */ fprintf(fd, "\t\n", config.name.c_str(), config.position); break; default: break; } } void CServiceManager::SaveServices(bool tocopy, bool if_changed, bool no_deleted) { int processed = 0; if(if_changed && !services_changed) return; #ifdef SAVE_DEBUG set chans_processed; #endif printf("CServiceManager::SaveServices: total channels: %d\n", (int)allchans.size()); FILE * fd = fopen(SERVICES_TMP, "w"); if(!fd) { perror(SERVICES_TMP); return; } fprintf(fd, "\n\n"); for (sat_iterator_t spos_it = satellitePositions.begin(); spos_it != satellitePositions.end(); ++spos_it) { bool satdone = 0; #ifdef SAVE_DEBUG printf("Process sat: %s\n", spos_it->second.name.c_str()); printf("processed channels: %d\n", chans_processed.size()); printf("tp count: %d\n", transponders.size()); #endif for(transponder_list_t::iterator tI = transponders.begin(); tI != transponders.end(); ++tI) { bool tpdone = 0; if(tI->second.satellitePosition != spos_it->first) { #ifdef SAVE_DEBUG printf("Sat position %d not found !!\n", satpos); #endif continue; } for (channel_map_iterator_t ccI = allchans.begin(); ccI != allchans.end(); ++ccI) { if(ccI->second.flags & CZapitChannel::NOT_FOUND) continue; if(ccI->second.getTransponderId() == tI->first) { if(!satdone) { WriteSatHeader(fd, spos_it->second); satdone = 1; } if(!tpdone) { tI->second.dumpServiceXml(fd); tpdone = 1; } /* don't dump removed channels if no_deleted == true */ if (!no_deleted || !(ccI->second.flags & CZapitChannel::REMOVED)) ccI->second.dumpServiceXml(fd); processed++; #ifdef SAVE_DEBUG chans_processed.insert(ccI->second.getChannelID()); #endif } } if(tpdone) fprintf(fd, "\t\t\n"); } if(satdone) { switch (spos_it->second.deltype) { case FE_QPSK: fprintf(fd, "\t\n"); break; case FE_QAM: fprintf(fd, "\t\n"); break; case FE_OFDM: fprintf(fd, "\t\n"); break; default: break; } } } fprintf(fd, "\n"); fclose(fd); if(tocopy) { CopyFile((char *) SERVICES_TMP, (char *) SERVICES_XML); unlink(SERVICES_TMP); } #ifdef SAVE_DEBUG printf("processed channels: %d\n", chans_processed.size()); int i = 0; for (channel_map_iterator_t it = allchans.begin(); it != allchans.end(); ++it) if (chans_processed.find(it->first) == chans_processed.end()) printf("unused channel %d sat %d freq %d sid %04X: %s\n", ++i, it->second.getSatellitePosition(), it->second.getFreqId(), it->second.getServiceId(), it->second.getName().c_str()); chans_processed.clear(); #endif printf("CServiceManager::SaveServices: processed channels: %d\n", processed); services_changed = false; } bool CServiceManager::CopyCurrentServices(transponder_id_t tpid) { channel_map_iterator_t aI; bool updated = false; for (channel_map_iterator_t cI = curchans.begin(); cI != curchans.end(); ++cI) { aI = allchans.find(cI->second.getChannelID()); if(aI == allchans.end()) { channel_insert_res_t ret = allchans.insert(channel_pair_t (cI->second.getChannelID(), cI->second)); ret.first->second.flags = CZapitChannel::NEW; updated = true; printf("CServiceManager::CopyCurrentServices: [%s] add\n", cI->second.getName().c_str()); } else { if(cI->second.scrambled != aI->second.scrambled || cI->second.getName() != aI->second.getName()) { aI->second.setName(cI->second.getName()); aI->second.scrambled = cI->second.scrambled; aI->second.flags = CZapitChannel::UPDATED; updated = true; printf("CServiceManager::CopyCurrentServices: [%s] replace\n", cI->second.getName().c_str()); } } } for (aI = allchans.begin(); aI != allchans.end(); ++aI) { if(aI->second.getTransponderId() == tpid) { channel_map_iterator_t dI = curchans.find(aI->second.getChannelID()); if(dI == curchans.end()) { aI->second.flags = CZapitChannel::REMOVED; updated = true; printf("CServiceManager::CopyCurrentServices: [%s] remove\n", aI->second.getName().c_str()); } else if(aI->second.flags & CZapitChannel::REMOVED) { printf("CServiceManager::CopyCurrentServices: [%s] restore\n", aI->second.getName().c_str()); aI->second.flags = CZapitChannel::UPDATED; updated = true; } } } if(updated) services_changed = true; return updated; } /* helper for reused code */ void CServiceManager::WriteCurrentService(FILE * fd, bool &satfound, bool &tpdone, bool &updated, char * satstr, transponder &tp, CZapitChannel &channel, const char * action) { if(!tpdone) { if(!satfound) fprintf(fd, "%s", satstr); tp.dumpServiceXml(fd); tpdone = 1; } updated = 1; channel.dumpServiceXml(fd, action); } bool CServiceManager::SaveCurrentServices(transponder_id_t tpid) { channel_map_iterator_t ccI; channel_map_iterator_t dI; transponder_list_t::iterator tI; char satstr[256]; char buffer[256]; FILE * fd = 0; FILE * fd1 = 0; bool updated = 0; bool tpdone = 0; bool satfound = 0; tI = transponders.find(tpid); if(tI == transponders.end()) { printf("[sdt monitor] tp not found ?!\n"); return false; } t_satellite_position satellitePosition = tI->second.satellitePosition; fd = fopen(CURRENTSERVICES_TMP, "w"); if(!fd) { printf("[sdt monitor] " CURRENTSERVICES_TMP ": cant open!\n"); return false; } sat_iterator_t spos_it = satellitePositions.find(satellitePosition); if(spos_it == satellitePositions.end()){ fclose(fd); return false; } const char * footer = ""; switch (tI->second.deltype) { case FE_QPSK: /* satellite */ sprintf(satstr, "\t<%s name=\"%s\" position=\"%hd\">\n", "sat", spos_it->second.name.c_str(), satellitePosition); footer = ""; break; case FE_QAM: /* cable */ sprintf(satstr, "\t<%s name=\"%s\"\n", "cable", spos_it->second.name.c_str()); footer = ""; break; case FE_OFDM: sprintf(satstr, "\t<%s name=\"%s\"\n", "terrestrial", spos_it->second.name.c_str()); footer = ""; break; default: break; } fd1 = fopen(CURRENTSERVICES_XML, "r"); if(!fd1) { fprintf(fd, "\n\n"); } else { fgets(buffer, 255, fd1); while(!feof(fd1) && !strstr(buffer, satfound ? footer : "")) { if(!satfound && !strcmp(buffer, satstr)) satfound = 1; fputs(buffer, fd); fgets(buffer, 255, fd1); } } for (channel_map_iterator_t cI = curchans.begin(); cI != curchans.end(); ++cI) { ccI = allchans.find(cI->second.getChannelID()); if(ccI == allchans.end()) { WriteCurrentService(fd, satfound, tpdone, updated, satstr, tI->second, cI->second, "add"); } else { if(strcmp(cI->second.getName().c_str(), ccI->second.getName().c_str()) || cI->second.scrambled != ccI->second.scrambled) { cI->second.number = ccI->second.number; WriteCurrentService(fd, satfound, tpdone, updated, satstr, tI->second, cI->second, "replace"); } } } for (ccI = allchans.begin(); ccI != allchans.end(); ++ccI) { if(ccI->second.getTransponderId() == tpid) { dI = curchans.find(ccI->second.getChannelID()); if(dI == curchans.end()) WriteCurrentService(fd, satfound, tpdone, updated, satstr, tI->second, ccI->second, "remove"); } } if(tpdone) { fprintf(fd, "\t\t\n"); fprintf(fd, "\t%s\n", footer); } else if(satfound) fprintf(fd, "\t%s\n", footer); if(fd1) { fgets(buffer, 255, fd1); while(!feof(fd1)) { fputs(buffer, fd); fgets(buffer, 255, fd1); } if(!satfound) fprintf(fd, "\n"); fclose(fd1); } else fprintf(fd, "\n"); fclose(fd); rename(CURRENTSERVICES_TMP, CURRENTSERVICES_XML); return updated; } #define PROVIDER_MAP_XML CONFIGDIR "/providermap.xml" bool CServiceManager::LoadProviderMap() { xmlDocPtr parser; replace_map.clear(); parser = parseXmlFile(PROVIDER_MAP_XML); if (parser != NULL) { xmlNodePtr node = xmlDocGetRootElement(parser)->xmlChildrenNode; while ((node = xmlGetNextOccurence(node, "TS")) != NULL) { provider_replace replace; replace.transport_stream_id = xmlGetNumericAttribute(node, "id", 16); replace.original_network_id = xmlGetNumericAttribute(node, "on", 16); replace.frequency = xmlGetNumericAttribute(node, "frq", 0); char * name = xmlGetAttribute(node, "name"); char * newname = xmlGetAttribute(node, "newname"); if(name) replace.name = name; if(newname) replace.newname = newname; DBG("prov map: tsid %04x onid %04x freq %d name [%s] to [%s]\n", replace.transport_stream_id, replace.original_network_id, replace.frequency, replace.name.c_str(), replace.newname.c_str()); replace_map.push_back(replace); node = node->xmlNextNode; } xmlFreeDoc(parser); return true; } return false; } bool CServiceManager::ReplaceProviderName(std::string &name, t_transport_stream_id tsid, t_original_network_id onid) { std::string newname; prov_replace_map_iterator_t it; for (it = replace_map.begin(); it != replace_map.end(); ++it) { provider_replace replace = *it; /* if replace map has tsid and onid */ if(replace.transport_stream_id && replace.original_network_id) { /* compare tsid/onid */ if(replace.transport_stream_id == tsid && replace.original_network_id == onid) { /* if new name present, old name should be present */ if(!replace.newname.empty()) { if (name == replace.name) newname = replace.newname; } else { newname = replace.name; } } } else { /* no tsid/onid, only names. if new name present, old name should be present */ if(!replace.newname.empty()) { if(name == replace.name) newname = replace.newname; } /* no tsid/onid, no newname, only name. compare name without case */ else if(!strcasecmp(replace.name.c_str(), name.c_str())) newname = replace.name; } if(!newname.empty()) { DBG("ReplaceProviderName: old [%s] new [%s]\n", name.c_str(), newname.c_str()); name = newname; return true; } } return false; } #if 0 //never used int CServiceManager::GetFreeNumber(bool radio) { service_number_map_t * channel_numbers = radio ? &radio_numbers : &tv_numbers; int i = 0; while(true) { ++i; service_number_map_t::iterator it = channel_numbers->find(i); if(it == channel_numbers->end()) { channel_numbers->insert(i); return i; } } } #endif int CServiceManager::GetMaxNumber(bool radio) { service_number_map_t * channel_numbers = radio ? &radio_numbers : &tv_numbers; int i = 0; service_number_map_t::iterator it = channel_numbers->end(); if(it != channel_numbers->begin()) { --it; i = *it; } return i+1; } #if 0 //never used void CServiceManager::FreeNumber(int number, bool radio) { service_number_map_t * channel_numbers = radio ? &radio_numbers : &tv_numbers; channel_numbers->erase(number); } void CServiceManager::UseNumber(int number, bool radio) { service_number_map_t * channel_numbers = radio ? &radio_numbers : &tv_numbers; channel_numbers->insert(number); } #endif bool CServiceManager::GetTransponder(transponder_id_t tid, transponder &t) { stiterator tI = transponders.find(tid); if(tI != transponders.end()) { t = tI->second; return true; } return false; } void CServiceManager::UpdateSatTransponders(t_satellite_position satellitePosition) { pair::iterator,bool> ret; transponder_list_t & stransponders = satelliteTransponders[satellitePosition]; for (transponder_list_t::iterator tI = transponders.begin(); tI != transponders.end(); ++tI) { for (stiterator stI = stransponders.begin(); stI != stransponders.end(); ++stI) { if (stI->second.compare(tI->second)) { stransponders.erase(stI); break; } } if (tI->second.satellitePosition == satellitePosition) { ret = stransponders.insert(transponder_pair_t(tI->first, tI->second)); if (ret.second == false) tI->second.dump("[zapit] duplicate in sat transponders:"); } } } bool CServiceManager::IsChannelTVChannel(const t_channel_id channel_id) { bool ret = true; CZapitChannel * channel = FindChannel(channel_id); if(channel) ret = (channel->getServiceType() != ST_DIGITAL_RADIO_SOUND_SERVICE); return ret; }